主页
搜索
最近更新
数据统计
申请密钥
批量保存
开发版网站(新前端)
系统公告
1
/
1
请查看完所有公告
C++杂交容器 vector+deque(veque)
最后更新于 2025-08-28 15:30:19
作者
_Kagamine_Rin_
分类
科技·工程
复制 Markdown
查看原文
转到新前端
删除文章
更新内容
创作原因(2025/8/26 11:34): > @[\_Kagamine\_Rin\_](https://www.luogu.com.cn/user/260985) : 会慢得跟屎一样,最关键的是我要封装 || @[AKPC](https://www.luogu.com.cn/user/540363) : 用数组手写双端队列 || @[\_Kagamine\_Rin\_](https://www.luogu.com.cn/user/260985) : vector 在首尾添加很慢,deque 随机访问很慢,那能不能把这两个 STL 结合起来?? 我认为这个容器需要达到下列要求: 1. 大部分操作需要不慢于 `vector` 和 `deque` 的对应操作。 2. 所有操作需要比 `vector` 和 `deque` 对应操作中的其中一个快。 3. `sizeof(veque) <= 40` 4. 代码长度 $\le 10240 \texttt{ Bytes}$ 5. 最低能够在 `C++11 (GCC 7)` 的编译条件下运行 ### 当前版本: 0.9.0-beta 该版本已经达成了前三个目标。 3. `sizeof(veque) == 32` 4. 代码长度有 29k,未达成 5. 目前至少需要 `C++17 (GCC 7)`,未达成 ```cpp #ifndef VEQUE_HPP #define VEQUE_HPP #include <algorithm> #include <cstddef> #include <cstring> #include <iterator> #include <limits> #include <ratio> #include <string> #include <type_traits> #include <stdexcept> #include <utility> #define if_constexpr if constexpr namespace veque { template<class T> inline const T& _clamp(const T& v, const T& lo, const T& hi) { return (v < lo) ? lo : (hi < v ? hi : v); } struct frt { using abf = std::ratio<1>; using aab = std::ratio<1>; static constexpr auto rfcs = true; }; struct vcrt { using abf = std::ratio<1>; using aab = std::ratio<1>; static constexpr auto rfcs = false; }; struct svt { using abf = std::ratio<0>; using aab = std::ratio<1>; static constexpr auto rfcs = false; }; struct nrt { using abf = std::ratio<0>; using aab = std::ratio<0>; static constexpr auto rfcs = false; }; template< typename T, typename RT = frt, typename Allocator = std::allocator<T> > class veque { public: using allocator_T = Allocator; using alloc_traits = std::allocator_traits<allocator_T>; using value_T = T; using ref = T &; using const_ref = const T &; using ptr = T *; using const_ptr = const T *; using iter = T *; using citer = const T *; using reverse_iter = std::reverse_iterator<iter>; using const_reverse_iter = std::reverse_iterator<citer>; using difference_T = std::ptrdiff_t; using size_T = std::size_t; using ssize_T = std::ptrdiff_t; // Common member functions veque() noexcept(noexcept(Allocator())) : veque(Allocator()) {} explicit veque(const Allocator& alloc) noexcept : _data { 0, alloc } {} explicit veque(size_T n, const Allocator& alloc = Allocator()) : veque(_aut{}, n, alloc) { _value_construct_range(begin(), end()); } veque(size_T n, const T &value, const Allocator& alloc = Allocator()) : veque(_aut{}, n, alloc) { _value_construct_range(begin(), end(), value); } template< typename InputIt, typename ItCat = typename std::iterator_traits<InputIt>::iter_category > veque(InputIt b, InputIt e, const Allocator& alloc = Allocator()) : veque(b, e, alloc, ItCat{}) { } veque(std::initializer_list<T> lst, const Allocator& alloc = Allocator()) : veque(_aut{}, lst.size(), alloc) { _copy_construct_range(lst.begin(), lst.end(), begin()); } veque(const veque & rhs) : veque(_aut{}, rhs.size(), alloc_traits::select_on_container_copy_construction(rhs._allocator())) { _copy_construct_range(rhs.begin(), rhs.end(), begin()); } template< typename rhsRT > veque(const veque<T,rhsRT,Allocator> & rhs) : veque(_aut{}, rhs.size(), alloc_traits::select_on_container_copy_construction(rhs._allocator())) { _copy_construct_range(rhs.begin(), rhs.end(), begin()); } template< typename rhsRT > veque(const veque<T,rhsRT,Allocator> & rhs, const Allocator & alloc) : veque(_aut{}, rhs.size(), alloc) { _copy_construct_range(rhs.begin(), rhs.end(), begin()); } veque(veque && rhs) noexcept { _swap_with_allocator(std::move(rhs)); } template< typename rhsRT > veque(veque<T,rhsRT,Allocator> && rhs) noexcept { _swap_with_allocator(std::move(rhs)); } template< typename rhsRT > veque(veque<T,rhsRT,Allocator> && rhs, const Allocator & alloc) noexcept : veque(alloc) { if_constexpr (!alloc_traits::is_always_equal::value) if (alloc != rhs._allocator()) { // Incompatible allocators. Allocate new storage. auto replacement = veque(_aut{}, rhs.size(), alloc); _nothrow_move_construct_range(rhs.begin(), rhs.end(), replacement.begin()); _swap_without_allocator(std::move(replacement)); return; } _swap_without_allocator(std::move(rhs)); } ~veque() { _destroy(begin(), end()); } veque & operator=(const veque & rhs) { return _copy_assignment(rhs); } template< typename rhsRT > veque & operator=(const veque<T,rhsRT,Allocator> & rhs) { return _copy_assignment(rhs); } veque & operator=(veque && rhs) noexcept(noexcept(alloc_traits::propagate_on_container_move_assignment::value || alloc_traits::is_always_equal::value)) { return _move_assignment(std::move(rhs)); } template< typename rhsRT > veque & operator=(veque<T,rhsRT,Allocator> && rhs) noexcept(noexcept(alloc_traits::propagate_on_container_move_assignment::value || alloc_traits::is_always_equal::value)) { return _move_assignment(std::move(rhs)); } veque & operator=(std::initializer_list<T> lst) { _assign(lst.begin(), lst.end()); return *this; } void assign(size_T count, const T &value) { if (count > capacity_full()) _swap_without_allocator(veque(count, value, _allocator())); else _reassign_existing_storage(count, value); } template< typename InputIt, typename ItCat = typename std::iterator_traits<InputIt>::iter_category > void assign(InputIt b, InputIt e) { _assign(b, e, ItCat{}); } void assign(std::initializer_list<T> lst) { _assign(lst.begin(), lst.end()); } allocator_T get_allocator() const { return _allocator(); } // Element access ref at(size_T idx) { return (*this)[idx]; } const_ref at(size_T idx) const { return (*this)[idx]; } ref operator[](size_T idx) { return *(begin() + idx); } const_ref operator[](size_T idx) const { return *(begin() + idx); } ref front() { return (*this)[0]; } const_ref front() const { return (*this)[0]; } ref back() { return (*this)[size() - 1];} const_ref back() const { return (*this)[size() - 1]; } T * data() noexcept { return begin(); } const T * data() const noexcept { return begin(); } // Iterators citer cbegin() const noexcept { return _storage_begin() + _offset; } iter begin() noexcept { return _storage_begin() + _offset; } citer begin() const noexcept { return cbegin(); } citer cend() const noexcept { return _storage_begin() + _offset + size(); } iter end() noexcept { return _storage_begin() + _offset + size(); } citer end() const noexcept { return cend(); } const_reverse_iter crbegin() const noexcept { return const_reverse_iter(cend()); } reverse_iter rbegin() noexcept { return reverse_iter(end()); } const_reverse_iter rbegin() const noexcept { return crbegin(); } const_reverse_iter crend() const noexcept { return const_reverse_iter(cbegin()); } reverse_iter rend() noexcept { return reverse_iter(begin()); } const_reverse_iter rend() const noexcept{ return crend(); } // Capacity [[nodiscard]] bool empty() const noexcept { return size() == 0; } size_T size() const noexcept { return _size; } ssize_T ssize() const noexcept { return _size; } size_T max_size() const noexcept { constexpr auto compile_time_limit = std::min( std::numeric_limits<ssize_T>::max() / sizeof(T), std::numeric_limits<size_T>::max() / _fur::num ); // The allocator's ceiling auto runtime_limit = alloc_traits::max_size(_allocator()); return std::min(compile_time_limit, runtime_limit); } // Reserve front and back capacity, in one operation. void reserve(size_T front, size_T back) { if (front > capacity_front() || back > capacity_back()) { auto allocated_before_begin = std::max(capacity_front(), front) - size(); auto allocated_after_begin = std::max(capacity_back(), back); auto new_full_capacity = allocated_before_begin + allocated_after_begin; _reallocate(new_full_capacity, allocated_before_begin); } } void reserve_front(size_T count) { reserve(count, 0); } void reserve_back(size_T count) { reserve(0, count); } void reserve(size_T count) { reserve(count, count); } size_T capacity_front() const noexcept { return _offset + size(); } size_T capacity_back() const noexcept { return capacity_full() - _offset; } size_T capacity_full() const noexcept { return _data._allocated; } size_T capacity() const noexcept { return capacity_back(); } void shrink_to_fit() { if (size() < capacity_full()) _reallocate(size(), 0); } // Modifiers void clear() noexcept { _destroy(begin(), end()); _size = 0; _offset = 0; if_constexpr (std::ratio_greater<_ur, std::ratio<0>>::value) { using unused_front_ratio = std::ratio_divide<_fr,_ur>; _offset = capacity_full() * unused_front_ratio::num / unused_front_ratio::den; } } iter insert(citer it, const T & value) { return emplace(it, value); } iter insert(citer it, T && value) { return emplace(it, std::move(value)); } iter insert(citer it, size_T count, const T & value) { auto res = _insert_storage(it, count); _value_construct_range(res, res + count, value); return res; } template< typename InputIt, typename ItCat = typename std::iterator_traits<InputIt>::iter_category > iter insert(citer it, InputIt b, InputIt e) { return _insert(it, b, e, ItCat{}); } iter insert(citer it, std::initializer_list<T> lst) { return insert(it, lst.begin(), lst.end()); } template< typename ...Args > iter emplace(citer it, Args && ... args) { auto res = _insert_storage(it, 1); alloc_traits::construct(_allocator(), res, std::forward<Args>(args)...); return res; } iter erase(citer it) { return erase(it, std::next(it)); } iter erase(citer b, citer e) { auto count = std::distance(b, e); if_constexpr (_rfcs) { auto elements_before = std::distance(cbegin(), b); auto elements_after = std::distance(e, cend()); if ( elements_before < elements_after) { _shift_back(begin(), b, count); _move_begin(count); return _mutable_iter(e); } } _shift_front(e, end(), count); _move_end(-count); return _mutable_iter(b); } void push_back(const T & value) { emplace_back(value); } void push_back(T && value) { emplace_back(std::move(value)); } void push_front(const T & value) { emplace_front(value); } void push_front(T && value) { emplace_front(std::move(value)); } template< typename ... Args> ref emplace_back(Args && ...args) { if (size() == capacity_back()) _reallocate_space_at_back(size() + 1); alloc_traits::construct(_allocator(), end(), std::forward<Args>(args)...); _move_end(1); return back(); } template< typename ... Args> ref emplace_front(Args && ...args) { if (size() == capacity_front()) _reallocate_space_at_front(size() + 1); alloc_traits::construct(_allocator(), begin()-1, std::forward<Args>(args)...); _move_begin(-1); return front(); } void pop_back() { alloc_traits::destroy(_allocator(), &back()); _move_end(-1); } void pop_front() { alloc_traits::destroy(_allocator(), &front()); _move_begin(1); } T pop_back_element() { auto res(_nothrow_construct_move(back())); pop_back(); return res; } T pop_front_element() { auto res(_nothrow_construct_move(front())); pop_front(); return res; } void resize_front(size_T count) { _resize_front(count); } void resize_front(size_T count, const T & value) { _resize_front(count, value); } void resize_back(size_T count) { _resize_back(count); } void resize_back(size_T count, const T & value) { _resize_back(count, value); } void resize(size_T count) { _resize_back(count); } void resize(size_T count, const T & value) { _resize_back(count, value); } template< typename rhsRT > void swap(veque<T,rhsRT,Allocator> & rhs) noexcept(noexcept(alloc_traits::propagate_on_container_swap::value || alloc_traits::is_always_equal::value)) { if_constexpr (alloc_traits::propagate_on_container_swap::value) _swap_with_allocator(std::move(rhs)); else { if (_allocator() == rhs._allocator()) _swap_without_allocator(std::move(rhs)); else { auto new_this = veque(_aut{}, rhs.size(), _allocator()); _nothrow_move_construct_range(rhs.begin(), rhs.end(), new_this.begin()); auto new_rhs = veque(_aut{}, size(), rhs._allocator()); _nothrow_move_construct_range(begin(), end(), new_rhs.begin()); _swap_without_allocator(std::move(new_this)); rhs._swap_without_allocator(std::move(new_rhs)); } } } private: using _fr = typename RT::abf::type; using _br = typename RT::aab::type; using _ur = std::ratio_add< _fr, _br >; using _fur = std::ratio_add< std::ratio<1>, _ur >; static constexpr auto _rfcs = RT::rfcs; static_assert(_fr::den > 0 ); static_assert(_br::den > 0 ); static_assert(std::ratio_greater_equal<_fr,std::ratio<0>>::value, "Reserving negative space is not well-defined"); static_assert(std::ratio_greater_equal<_br,std::ratio<0>>::value, "Reserving negative space is not well-defined"); static_assert(std::ratio_greater_equal<_ur,std::ratio<0>>::value, "Reserving negative space is not well-defined"); static constexpr auto _cdcd = std::is_same<allocator_T,std::allocator<T>>::value; static constexpr auto _cccd = std::is_same<allocator_T,std::allocator<T>>::value; static constexpr auto _cdd =std::is_same<allocator_T,std::allocator<T>>::value; size_T _size = 0; size_T _offset = 0; struct Data : Allocator { T *_storage = nullptr; size_T _allocated = 0; Data() = default; Data(size_T size, const Allocator & alloc) : Allocator{alloc} , _storage{size ? std::allocator_traits<Allocator>::allocate(allocator(), size) : nullptr} , _allocated{size} { } Data(const Data&) = delete; Data(Data && rhs) { *this = std::move(rhs); } ~Data() { if (_storage) std::allocator_traits<Allocator>::deallocate(allocator(), _storage, _allocated); } Data& operator=(const Data &) = delete; Data& operator=(Data && rhs) { using std::swap; if_constexpr(! std::is_empty<Allocator>::value) swap(allocator(), rhs.allocator()); swap(_allocated, rhs._allocated); swap(_storage, rhs._storage); return *this; } Allocator& allocator() { return *this; } const Allocator& allocator() const { return *this; } } _data; template< typename InputIt > veque(InputIt b, InputIt e, const Allocator & alloc, std::input_iterator_tag) : veque{alloc} { for (; b != e; ++b) push_back(*b); } template< typename InputIt > veque(InputIt b, InputIt e, const Allocator & alloc, std::forward_iterator_tag) : veque(_aut{}, std::distance(b, e), alloc) { _copy_construct_range(b, e, begin()); } struct _aut {}; struct _rut {}; veque(_aut, size_T size, size_T allocated, size_T offset, const Allocator & alloc) : _size{ size } , _offset{ offset } , _data { allocated, alloc } { } veque(_aut, size_T size, const Allocator & alloc) : veque(_aut{}, size, size, 0, alloc) { } veque(_rut, size_T size, const Allocator & alloc) : veque(_aut{}, size, _calc_reallocation(size), _calc_offset(size), alloc) { } static constexpr size_T _calc_reallocation(size_T size) { return size * _fur::num / _fur::den; } static constexpr size_T _calc_offset(size_T size) { return size * _fr::num / _fr::den; } // Acquire Allocator Allocator& _allocator() noexcept { return _data.allocator(); } const Allocator& _allocator() const noexcept { return _data.allocator(); } void _destroy(citer b, citer e) { if_constexpr (std::is_trivially_destructible<T>::value && _cdd) { (void)b; (void)e; // Unused } else { auto start = _mutable_iter(b); for (auto i = start; i != e; ++i) alloc_traits::destroy(_allocator(), i); } } template< typename rhsRT > veque & _copy_assignment(const veque<T,rhsRT,Allocator> & rhs) { if_constexpr (alloc_traits::propagate_on_container_copy_assignment::value) if_constexpr (!alloc_traits::is_always_equal::value) if (rhs._allocator() != _allocator() || rhs.size() > capacity_full()) { _swap_with_allocator(veque(rhs, rhs._allocator())); return *this; } if (rhs.size() > capacity_full()) _swap_without_allocator(veque(rhs, _allocator())); else _reassign_existing_storage(rhs.begin(), rhs.end()); return *this; } template< typename rhsRT > veque & _move_assignment(veque<T,rhsRT,Allocator> && rhs) noexcept(noexcept(alloc_traits::propagate_on_container_move_assignment::value || alloc_traits::is_always_equal::value)) { if_constexpr (!alloc_traits::is_always_equal::value) if (_allocator() != rhs._allocator()) { if_constexpr (alloc_traits::propagate_on_container_move_assignment::value) _swap_with_allocator(std::move(rhs)); else { if (rhs.size() > capacity_full()) _swap_without_allocator(veque(std::move(rhs), _allocator())); else _reassign_existing_storage(std::make_move_iterator(rhs.begin()), std::make_move_iterator(rhs.end())); } return *this; } _swap_without_allocator(std::move(rhs)); return *this; } template< typename ...Args > void _value_construct_range(citer b, citer e, const Args & ...args) { static_assert(sizeof...(args) <= 1, "This is for default- or copy-constructing"); if_constexpr (std::is_trivially_copy_constructible<T>::value && _cdcd) { if_constexpr (sizeof...(args) == 0) std::memset(_mutable_iter(b), 0, std::distance(b, e) * sizeof(T)); else std::fill(_mutable_iter(b), _mutable_iter(e), args...); } else for (auto dest = _mutable_iter(b); dest != e; ++dest) alloc_traits::construct(_allocator(), dest, args...); } template< typename It > void _copy_construct_range(It b, It e, citer dest) { static_assert(std::is_convertible<typename std::iterator_traits<It>::iter_category,std::forward_iterator_tag>::value); if_constexpr (std::is_trivially_copy_constructible<T>::value && _cccd) std::memcpy(_mutable_iter(dest), b, std::distance(b, e) * sizeof(T)); else for (; b != e; ++dest, ++b) alloc_traits::construct(_allocator(), dest, *b); } template< typename It > void _assign(It b, It e) { static_assert(std::is_convertible<typename std::iterator_traits<It>::iter_category,std::forward_iterator_tag>::value); if (std::distance(b, e) > static_cast<difference_T>(capacity_full())) _swap_without_allocator(veque(b, e, _allocator())); else _reassign_existing_storage(b, e); } template< typename It > void _assign(It b, It e, std::forward_iterator_tag) { _assign(b, e); } template< typename It > void _assign(It b, It e, std::input_iterator_tag) { clear(); for (; b != e; ++b) push_back(*b); } template< typename It > iter _insert(citer it, It b, It e) { static_assert(std::is_convertible<typename std::iterator_traits<It>::iter_category,std::forward_iterator_tag>::value); auto res = _insert_storage(it, std::distance(b, e)); _copy_construct_range(b, e, res); return res; } template< typename It > iter _insert(citer it, It b, It e, std::forward_iterator_tag) { return _insert(it, b, e); } template< typename It > iter _insert(citer it, It b, It e, std::input_iterator_tag) { auto allocated = veque(b, e); _insert(it, allocated.begin(), allocated.end()); } template< typename rhsRT > void _swap_with_allocator(veque<T,rhsRT,Allocator> && rhs) noexcept { std::swap(_size, rhs._size); std::swap(_offset, rhs._offset); std::swap(_data, rhs._data); } template< typename rhsRT > void _swap_without_allocator(veque<T,rhsRT,Allocator> && rhs) noexcept { std::swap(_size, rhs._size); std::swap(_offset, rhs._offset); std::swap(_data._allocated, rhs._data._allocated); std::swap(_data._storage, rhs._data._storage); } template< typename ...Args > void _resize_front(size_T count, const Args & ...args) { difference_T delta = count - size(); if (delta > 0) { if (count > capacity_front()) _reallocate_space_at_front(count); _value_construct_range(begin() - delta, begin(), args...); } else _destroy(begin(), begin() - delta); _move_begin(-delta); } template< typename ...Args > void _resize_back(size_T count, const Args & ...args) { difference_T delta = count - size(); if (delta > 0) { if (count > capacity_back()) _reallocate_space_at_back(count); _value_construct_range(end(), end() + delta, args...); } else _destroy(end() + delta, end()); _move_end(delta); } void _reallocate_space_at_back(size_T count) { auto storage_needed = _calc_reallocation(count); auto current_capacity = capacity_full(); auto new_offset = _calc_offset(count); if (storage_needed <= current_capacity) { auto distance = _offset - new_offset; _shift_front(begin(), end(), distance ); _move_begin(-distance); _move_end(-distance); } else _reallocate(storage_needed, new_offset); } void _reallocate_space_at_front(size_T count) { auto storage_needed = _calc_reallocation(count); auto current_capacity = capacity_full(); auto new_offset = count - size() + _calc_offset(count); if (storage_needed <= current_capacity) { auto distance = new_offset - _offset; _shift_back(begin(), end(), distance); _move_begin(distance); _move_end(distance); } else _reallocate(storage_needed, new_offset); } void _reallocate(size_T allocated, size_T offset) { auto replacement = veque(_aut{}, size(), allocated, offset, _allocator()); _nothrow_move_construct_range(begin(), end(), replacement.begin()); _swap_without_allocator(std::move(replacement)); } iter _insert_storage(citer it, size_T count) { auto required_size = size() + count; auto can_shift_back = capacity_back() >= required_size; if_constexpr (std::ratio_greater<_fr,std::ratio<0>>::value) if (can_shift_back && it == begin()) can_shift_back = false; if_constexpr (_rfcs) { auto can_shift_front = capacity_front() >= required_size; if_constexpr (std::ratio_greater<_br,std::ratio<0>>::value) if (can_shift_front && it == end()) can_shift_front = false; if (can_shift_back && can_shift_front) { auto index = std::distance(cbegin(), it); if (index <= ssize() / 2) can_shift_back = false; else can_shift_front = false; } if (can_shift_front) { _shift_front(begin(), it, count); _move_begin(-count); return _mutable_iter(it) - count; } } if (can_shift_back) { _shift_back(it, end(), count); _move_end(count); return _mutable_iter(it); } auto replacement = veque(_rut{}, required_size, _allocator()); auto index = std::distance(cbegin(), it); auto insertion_point = begin() + index; _nothrow_move_construct_range(begin(), insertion_point, replacement.begin()); _nothrow_move_construct_range(insertion_point, end(), replacement.begin() + index + count); _swap_with_allocator(std::move(replacement)); return begin() + index; } void _shift_front(citer b, citer e, size_T count) { if (e == begin()) return; auto element_count = std::distance(b, e); auto start = _mutable_iter(b); if (element_count > 0) { auto dest = start - count; if_constexpr (std::is_trivially_copyable<T>::value && std::is_trivially_copy_constructible<T>::value && _cccd) std::memmove(dest, start, element_count * sizeof(T)); else { auto src = start; auto dest_construct_end = std::min(begin(), _mutable_iter(e) - count); for (; dest < dest_construct_end; ++src, ++dest) _nothrow_move_construct(dest, src); for (; src != e; ++src, ++dest) _nothrow_move_assign(dest, src); } } _destroy(std::max(cbegin(), e - count), e); } void _shift_back(citer b, citer e, size_T count) { auto start = _mutable_iter(b); if (b == end()) return; auto element_count = std::distance(b, e); if (element_count > 0) { if_constexpr (std::is_trivially_copyable<T>::value && std::is_trivially_copy_constructible<T>::value && _cccd) std::memmove(start + count, start, element_count * sizeof(T)); else { auto src = _mutable_iter(e-1); auto dest = src + count; auto dest_construct_end = std::max(end()-1, dest - element_count); for (; dest > dest_construct_end; --src, --dest) _nothrow_move_construct(dest, src); for (; src != b-1; --src, --dest) _nothrow_move_assign(dest, src); } } _destroy(b, std::min(cend(), b + count)); } template< typename It > void _reassign_existing_storage(It b, It e) { static_assert(std::is_convertible<typename std::iterator_traits<It>::iter_category,std::forward_iterator_tag>::value); auto count = std::distance(b, e); auto size_delta = static_cast<difference_T>(count - size()); auto ideal_begin = _storage_begin() + (capacity_full() - count) / 2; if (size() == 0) _copy_construct_range(b, e, ideal_begin); else if (size_delta == 0) { std::copy(b, e, begin()); return; } else if (size_delta < 0) { ideal_begin = _clamp(ideal_begin, begin(), end() - count); _destroy(begin(), ideal_begin); auto ideal_end = std::copy(b, e, ideal_begin); _destroy(ideal_end, end()); } else { ideal_begin = _clamp(ideal_begin, end() - count, begin()); auto src = b; auto copy_src = src + std::distance(ideal_begin, begin()); _copy_construct_range(src, copy_src, ideal_begin); std::copy(copy_src, copy_src + ssize(), begin()); _copy_construct_range(copy_src + ssize(), e, end()); } _move_begin(std::distance(begin(), ideal_begin)); _move_end(std::distance(end(), ideal_begin + count)); } void _reassign_existing_storage(size_T count, const T & value) { auto size_delta = static_cast<difference_T>(count - size()); auto ideal_begin = _storage_begin(); if_constexpr (std::ratio_greater<_ur, std::ratio<0>>::value) { using ideal_begin_ratio = std::ratio_divide<_fr, _ur >; ideal_begin += (capacity_full() - count) * ideal_begin_ratio::num / ideal_begin_ratio::den; } if (size() == 0) _value_construct_range(ideal_begin, ideal_begin + count, value); else if (size_delta == 0) { std::fill(begin(), end(), value); return; } else if (size_delta < 0) { ideal_begin = _clamp(ideal_begin, begin(), end() - count); _destroy(begin(), ideal_begin); std::fill(ideal_begin, ideal_begin + count, value); _destroy(ideal_begin + count, end()); } else { ideal_begin += _calc_offset(capacity_full() - count) / 2; _value_construct_range(ideal_begin, begin(), value); std::fill(begin(), end(), value); _value_construct_range(end(), ideal_begin + count, value); } _move_begin(std::distance(begin(), ideal_begin)); _move_end(std::distance(end(), ideal_begin + count)); } static decltype(auto) _nothrow_construct_move_impl(T & t, std::true_type) { return std::move(t); } static decltype(auto) _nothrow_construct_move_impl(T & t, std::false_type) { return t; } static decltype(auto) _nothrow_construct_move(T & t) { return _nothrow_construct_move_impl(t, std::is_nothrow_move_constructible<T>{}); } void _nothrow_move_construct(iter dest, iter src) { if_constexpr (std::is_trivially_copy_constructible<T>::value && _cccd) *dest = *src; else alloc_traits::construct(_allocator(), dest, _nothrow_construct_move(*src)); } void _nothrow_move_construct_range(iter b, iter e, iter dest) { auto size = std::distance(b, e); if (size) { if_constexpr (std::is_trivially_copy_constructible<T>::value && _cccd) std::memcpy(dest, b, size * sizeof(T)); else for (; b != e; ++dest, ++b) _nothrow_move_construct(dest, b); } } static void _nothrow_move_assign(iter dest, iter src) { if_constexpr (std::is_nothrow_move_assignable<T>::value) *dest = std::move(*src); else *dest = *src; } static void _nothrow_move_assign_range(iter b, iter e, iter src) { for (auto dest = b; dest != e; ++dest, ++src) _nothrow_move_assign(dest, src); } void _move_begin(difference_T count) noexcept { _size -= count; _offset += count; } void _move_end(difference_T count) noexcept { _size += count; } iter _mutable_iter(citer i) { return begin() + std::distance(cbegin(), i); } citer _storage_begin() const noexcept { return _data._storage; } iter _storage_begin() noexcept { return _data._storage; } }; #define TPIB template< typename T, typename LRT, typename LAlloc, typename RRT, typename RA > TPIB operator==(const veque<T,LRT,LAlloc> &lhs, const veque<T,RRT,RA> &rhs) { return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } TPIB operator!=(const veque<T,LRT,LAlloc> &lhs, const veque<T,RRT,RA> &rhs) { return !(lhs == rhs); } TPIB operator<(const veque<T,LRT,LAlloc> &lhs, const veque<T,RRT,RA> &rhs) { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } TPIB operator<=(const veque<T,LRT,LAlloc> &lhs, const veque<T,RRT,RA> &rhs) { return !(rhs < lhs); } TPIB operator>(const veque<T,LRT,LAlloc> &lhs, const veque<T,RRT,RA> &rhs) { return (rhs < lhs); } TPIB operator>=(const veque<T,LRT,LAlloc> &lhs, const veque<T,RRT,RA> &rhs) { return !(lhs < rhs); } template< typename T, typename RT, typename Alloc > inline void swap(veque<T,RT,Alloc> & lhs, veque<T,RT,Alloc> & rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); } #undef TPIB } namespace std { template< typename T, typename RT, typename Alloc > struct hash<veque::veque<T,RT,Alloc>> { size_t operator()(const veque::veque<T,RT,Alloc> & v) const { size_t hash = 0; auto hasher = std::hash<T>(); for (auto && val : v) hash ^= hasher(val) + 0x9e3779b9 + (hash<<6) + (hash>>2); return hash; } }; } #endif #include <vector> #include <deque> #include <iostream> using namespace std; veque::veque<int> a; vector<int> b; deque<int> c; #define test(...) {clock_t _t = clock(); __VA_ARGS__ cout << (clock() - _t) << "\n"; } int main() { test( for (int i = 1; i <= 100000000; ++ i) a.emplace_back(i); ) test( for (int i = 1; i <= 100000000; ++ i) b.emplace_back(i); ) test( for (int i = 1; i <= 100000000; ++ i) c.emplace_back(i); ) } ``` Note: 这个版本已经让一些变量名简化,但仍然有 29k。 欢迎查错,可在评论区或私信提出。
正在渲染内容...
点赞
1
收藏
0