📄 stl_deque.h
字号:
_Alloc_traits<_Tp, _Alloc>::_S_instanceless> _Base; typedef typename _Base::allocator_type allocator_type; typedef _Deque_iterator<_Tp,_Tp&,_Tp*> iterator; typedef _Deque_iterator<_Tp,const _Tp&,const _Tp*> const_iterator; _Deque_base(const allocator_type& __a, size_t __num_elements) : _Base(__a), _M_start(), _M_finish() { _M_initialize_map(__num_elements); } _Deque_base(const allocator_type& __a) : _Base(__a), _M_start(), _M_finish() {} ~_Deque_base(); protected: void _M_initialize_map(size_t); void _M_create_nodes(_Tp** __nstart, _Tp** __nfinish); void _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish); enum { _S_initial_map_size = 8 };protected: iterator _M_start; iterator _M_finish;};template <class _Tp, class _Alloc>_Deque_base<_Tp,_Alloc>::~_Deque_base(){ if (_M_map) { _M_destroy_nodes(_M_start._M_node, _M_finish._M_node + 1); _M_deallocate_map(_M_map, _M_map_size); }}/** * @if maint * @brief Layout storage. * @param num_elements The count of T's for which to allocate space at first. * @return Nothing. * * The initial underlying memory layout is a bit complicated... * @endif*/template <class _Tp, class _Alloc>void_Deque_base<_Tp,_Alloc>::_M_initialize_map(size_t __num_elements){ size_t __num_nodes = __num_elements / __deque_buf_size(sizeof(_Tp)) + 1; _M_map_size = max((size_t) _S_initial_map_size, __num_nodes + 2); _M_map = _M_allocate_map(_M_map_size); _Tp** __nstart = _M_map + (_M_map_size - __num_nodes) / 2; _Tp** __nfinish = __nstart + __num_nodes; try { _M_create_nodes(__nstart, __nfinish); } catch(...) { _M_deallocate_map(_M_map, _M_map_size); _M_map = 0; _M_map_size = 0; __throw_exception_again; } _M_start._M_set_node(__nstart); _M_finish._M_set_node(__nfinish - 1); _M_start._M_cur = _M_start._M_first; _M_finish._M_cur = _M_finish._M_first + __num_elements % __deque_buf_size(sizeof(_Tp));}template <class _Tp, class _Alloc>void _Deque_base<_Tp,_Alloc>::_M_create_nodes(_Tp** __nstart, _Tp** __nfinish){ _Tp** __cur; try { for (__cur = __nstart; __cur < __nfinish; ++__cur) *__cur = _M_allocate_node(); } catch(...) { _M_destroy_nodes(__nstart, __cur); __throw_exception_again; }}template <class _Tp, class _Alloc>void_Deque_base<_Tp,_Alloc>::_M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish){ for (_Tp** __n = __nstart; __n < __nfinish; ++__n) _M_deallocate_node(*__n);}/** * @ingroup Containers * @ingroup Sequences * * Meets the requirements of a <a href="tables.html#65">container</a>, a * <a href="tables.html#66">reversible container</a>, and a * <a href="tables.html#67">sequence</a>, including the * <a href="tables.html#68">optional sequence requirements</a>. * * Placeholder: see http://www.sgi.com/tech/stl/Deque.html for now. * * In previous HP/SGI versions of deque, there was an extra template parameter * so users could control the node size. This extension turned out to violate * the C++ standard (it can be detected using template template parameters), * and it was removed. * * @if maint * Here's how a deque<Tp> manages memory. Each deque has 4 members: * * - Tp** _M_map * - size_t _M_map_size * - iterator _M_start, _M_finish * * map_size is at least 8. %map is an array of map_size pointers-to-"nodes". * (The name has nothing to do with the std::map class.) * * A "node" has no specific type name as such, but it is referred to as * "node" in this file. It is a simple array-of-Tp. If Tp is very large, * there will be one Tp element per node (i.e., an "array" of one). * For non-huge Tp's, node size is inversely related to Tp size: the * larger the Tp, the fewer Tp's will fit in a node. The goal here is to * keep the total size of a node relatively small and constant over different * Tp's, to improve allocator efficiency. * * **** As I write this, the nodes are /not/ allocated using the high-speed * memory pool. There are 20 hours left in the year; perhaps I can fix * this before 2002. * * Not every pointer in the %map array will point to a node. If the initial * number of elements in the deque is small, the /middle/ %map pointers will * be valid, and the ones at the edges will be unused. This same situation * will arise as the %map grows: available %map pointers, if any, will be on * the ends. As new nodes are created, only a subset of the %map's pointers * need to be copied "outward". * * Class invariants: * - For any nonsingular iterator i: * - i.node points to a member of the %map array. (Yes, you read that * correctly: i.node does not actually point to a node.) The member of * the %map array is what actually points to the node. * - i.first == *(i.node) (This points to the node (first Tp element).) * - i.last == i.first + node_size * - i.cur is a pointer in the range [i.first, i.last). NOTE: * the implication of this is that i.cur is always a dereferenceable * pointer, even if i is a past-the-end iterator. * - Start and Finish are always nonsingular iterators. NOTE: this means that * an empty deque must have one node, a deque with <N elements (where N is * the node buffer size) must have one node, a deque with N through (2N-1) * elements must have two nodes, etc. * - For every node other than start.node and finish.node, every element in the * node is an initialized object. If start.node == finish.node, then * [start.cur, finish.cur) are initialized objects, and the elements outside * that range are uninitialized storage. Otherwise, [start.cur, start.last) * and [finish.first, finish.cur) are initialized objects, and [start.first, * start.cur) and [finish.cur, finish.last) are uninitialized storage. * - [%map, %map + map_size) is a valid, non-empty range. * - [start.node, finish.node] is a valid range contained within * [%map, %map + map_size). * - A pointer in the range [%map, %map + map_size) points to an allocated node * if and only if the pointer is in the range [start.node, finish.node]. * * Here's the magic: nothing in deque is "aware" of the discontiguous storage! * * The memory setup and layout occurs in the parent, _Base, and the iterator * class is entirely responsible for "leaping" from one node to the next. All * the implementation routines for deque itself work only through the start * and finish iterators. This keeps the routines simple and sane, and we can * use other standard algorithms as well. * @endif*/template <class _Tp, class _Alloc = allocator<_Tp> >class deque : protected _Deque_base<_Tp, _Alloc>{ // concept requirements __glibcpp_class_requires(_Tp, _SGIAssignableConcept) typedef _Deque_base<_Tp, _Alloc> _Base;public: typedef _Tp value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef typename _Base::allocator_type allocator_type; allocator_type get_allocator() const { return _Base::get_allocator(); } typedef typename _Base::iterator iterator; typedef typename _Base::const_iterator const_iterator; typedef reverse_iterator<const_iterator> const_reverse_iterator; typedef reverse_iterator<iterator> reverse_iterator;protected: typedef pointer* _Map_pointer; static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); } // Functions controlling memory layout, and nothing else. using _Base::_M_initialize_map; using _Base::_M_create_nodes; using _Base::_M_destroy_nodes; using _Base::_M_allocate_node; using _Base::_M_deallocate_node; using _Base::_M_allocate_map; using _Base::_M_deallocate_map; /** @if maint * A total of four data members accumulated down the heirarchy. If the * _Alloc type requires separate instances, then two of them will also be * included in each deque. * @endif */ using _Base::_M_map; using _Base::_M_map_size; using _Base::_M_start; using _Base::_M_finish;public: // Basic accessors iterator begin() { return _M_start; } iterator end() { return _M_finish; } const_iterator begin() const { return _M_start; } const_iterator end() const { return _M_finish; } reverse_iterator rbegin() { return reverse_iterator(_M_finish); } reverse_iterator rend() { return reverse_iterator(_M_start); } const_reverse_iterator rbegin() const { return const_reverse_iterator(_M_finish); } const_reverse_iterator rend() const { return const_reverse_iterator(_M_start); } reference operator[](size_type __n) { return _M_start[difference_type(__n)]; } const_reference operator[](size_type __n) const { return _M_start[difference_type(__n)]; } void _M_range_check(size_type __n) const { if (__n >= this->size()) __throw_out_of_range("deque"); } reference at(size_type __n) { _M_range_check(__n); return (*this)[__n]; } const_reference at(size_type __n) const { _M_range_check(__n); return (*this)[__n]; } reference front() { return *_M_start; } reference back() { iterator __tmp = _M_finish; --__tmp; return *__tmp; } const_reference front() const { return *_M_start; } const_reference back() const { const_iterator __tmp = _M_finish; --__tmp; return *__tmp; } size_type size() const { return _M_finish - _M_start; } size_type max_size() const { return size_type(-1); } bool empty() const { return _M_finish == _M_start; }public: // Constructor, destructor. explicit deque(const allocator_type& __a = allocator_type()) : _Base(__a, 0) {} deque(const deque& __x) : _Base(__x.get_allocator(), __x.size()) { uninitialized_copy(__x.begin(), __x.end(), _M_start); } deque(size_type __n, const value_type& __value, const allocator_type& __a = allocator_type()) : _Base(__a, __n) { _M_fill_initialize(__value); } explicit deque(size_type __n) : _Base(allocator_type(), __n) { _M_fill_initialize(value_type()); } // Check whether it's an integral type. If so, it's not an iterator. template<class _InputIterator> deque(_InputIterator __first, _InputIterator __last, const allocator_type& __a = allocator_type()) : _Base(__a) { typedef typename _Is_integer<_InputIterator>::_Integral _Integral; _M_initialize_dispatch(__first, __last, _Integral()); } template<class _Integer> void _M_initialize_dispatch(_Integer __n, _Integer __x, __true_type) { _M_initialize_map(__n); _M_fill_initialize(__x); } template<class _InputIter> void _M_initialize_dispatch(_InputIter __first, _InputIter __last, __false_type) { typedef typename iterator_traits<_InputIter>::iterator_category _IterCategory; _M_range_initialize(__first, __last, _IterCategory()); } ~deque() { _Destroy(_M_start, _M_finish); } deque& operator= (const deque& __x) { const size_type __len = size(); if (&__x != this) { if (__len >= __x.size()) erase(copy(__x.begin(), __x.end(), _M_start), _M_finish); else { const_iterator __mid = __x.begin() + difference_type(__len); copy(__x.begin(), __mid, _M_start); insert(_M_finish, __mid, __x.end()); } } return *this; } void swap(deque& __x) { std::swap(_M_start, __x._M_start); std::swap(_M_finish, __x._M_finish); std::swap(_M_map, __x._M_map); std::swap(_M_map_size, __x._M_map_size); }public: // assign(), a generalized assignment member function. Two // versions: one that takes a count, and one that takes a range. // The range version is a member template, so we dispatch on whether // or not the type is an integer. void _M_fill_assign(size_type __n, const _Tp& __val) { if (__n > size()) { fill(begin(), end(), __val); insert(end(), __n - size(), __val); } else { erase(begin() + __n, end()); fill(begin(), end(), __val); } } void assign(size_type __n, const _Tp& __val) { _M_fill_assign(__n, __val); } template<class _InputIterator> void assign(_InputIterator __first, _InputIterator __last) { typedef typename _Is_integer<_InputIterator>::_Integral _Integral; _M_assign_dispatch(__first, __last, _Integral()); }private: // helper functions for assign() template<class _Integer> void _M_assign_dispatch(_Integer __n, _Integer __val, __true_type) { _M_fill_assign(static_cast<size_type>(__n), static_cast<_Tp>(__val)); } template<class _InputIterator> void _M_assign_dispatch(_InputIterator __first, _InputIterator __last, __false_type) { typedef typename iterator_traits<_InputIterator>::iterator_category _IterCategory; _M_assign_aux(__first, __last, _IterCategory()); } template <class _InputIterator> void _M_assign_aux(_InputIterator __first, _InputIterator __last, input_iterator_tag); template <class _ForwardIterator> void _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last, forward_iterator_tag) { size_type __len = distance(__first, __last); if (__len > size()) { _ForwardIterator __mid = __first; advance(__mid, size()); copy(__first, __mid, begin()); insert(end(), __mid, __last); } else erase(copy(__first, __last, begin()), end()); }public: // push_* and pop_* void push_back(const value_type& __t) { if (_M_finish._M_cur != _M_finish._M_last - 1) { _Construct(_M_finish._M_cur, __t); ++_M_finish._M_cur; } else _M_push_back_aux(__t); } void push_back() { if (_M_finish._M_cur != _M_finish._M_last - 1) { _Construct(_M_finish._M_cur); ++_M_finish._M_cur; } else _M_push_back_aux(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -