Commit 5cb6369d by Phil Edwards

stl_deque.h, [...]: Reformat to (mostly) match C++STYLE.

2002-06-03  Phil Edwards  <pme@gcc.gnu.org>

	* include/bits/stl_deque.h, include/bits/stl_list.h,
	include/bits/stl_vector.h:  Reformat to (mostly) match C++STYLE.
	Reorder to match 14882.  Doxygen blocks for all public members.

From-SVN: r54198
parent 0fb7aeda
2002-06-03 Phil Edwards <pme@gcc.gnu.org>
* include/bits/stl_deque.h, include/bits/stl_list.h,
include/bits/stl_vector.h: Reformat to (mostly) match C++STYLE.
Reorder to match 14882. Doxygen blocks for all public members.
2002-05-31 Marcus Meissner <meissner@suse.de> 2002-05-31 Marcus Meissner <meissner@suse.de>
PR libstdc++/6886 PR libstdc++/6886
......
// deque implementation -*- C++ -*- // Deque implementation -*- C++ -*-
// Copyright (C) 2001, 2002 Free Software Foundation, Inc. // Copyright (C) 2001, 2002 Free Software Foundation, Inc.
// //
...@@ -58,13 +58,12 @@ ...@@ -58,13 +58,12 @@
* You should not attempt to use it directly. * You should not attempt to use it directly.
*/ */
#include <bits/concept_check.h>
#include <bits/stl_iterator_base_types.h>
#include <bits/stl_iterator_base_funcs.h>
#ifndef __GLIBCPP_INTERNAL_DEQUE_H #ifndef __GLIBCPP_INTERNAL_DEQUE_H
#define __GLIBCPP_INTERNAL_DEQUE_H #define __GLIBCPP_INTERNAL_DEQUE_H
#include <bits/concept_check.h>
#include <bits/stl_iterator_base_types.h>
#include <bits/stl_iterator_base_funcs.h>
// Since this entire file is within namespace std, there's no reason to // Since this entire file is within namespace std, there's no reason to
// waste two spaces along the left column. Thus the leading indentation is // waste two spaces along the left column. Thus the leading indentation is
...@@ -76,19 +75,22 @@ namespace std ...@@ -76,19 +75,22 @@ namespace std
* @if maint * @if maint
* @brief This function controls the size of memory nodes. * @brief This function controls the size of memory nodes.
* @param size The size of an element. * @param size The size of an element.
* @return The number (not bytesize) of elements per node. * @return The number (not byte size) of elements per node.
* *
* This function started off as a compiler kludge from SGI, but seems to * This function started off as a compiler kludge from SGI, but seems to
* be a useful wrapper around a repeated constant expression. * be a useful wrapper around a repeated constant expression. The '512' is
* tuneable (and no other code needs to change), but no investigation has
* been done since inheriting the SGI code.
* @endif * @endif
*/ */
inline size_t inline size_t
__deque_buf_size(size_t __size) __deque_buf_size(size_t __size)
{ return __size < 512 ? size_t(512 / __size) : size_t(1); } { return __size < 512 ? size_t(512 / __size) : size_t(1); }
/// A deque::iterator.
/** /**
* @brief A deque::iterator.
*
* Quite a bit of intelligence here. Much of the functionality of deque is * Quite a bit of intelligence here. Much of the functionality of deque is
* actually passed off to this class. A deque holds two of these internally, * actually passed off to this class. A deque holds two of these internally,
* marking its valid range. Access to elements is done as offsets of either * marking its valid range. Access to elements is done as offsets of either
...@@ -99,7 +101,7 @@ __deque_buf_size(size_t __size) ...@@ -99,7 +101,7 @@ __deque_buf_size(size_t __size)
* @endif * @endif
*/ */
template <class _Tp, class _Ref, class _Ptr> template <class _Tp, class _Ref, class _Ptr>
struct _Deque_iterator struct _Deque_iterator
{ {
typedef _Deque_iterator<_Tp, _Tp&, _Tp*> iterator; typedef _Deque_iterator<_Tp, _Tp&, _Tp*> iterator;
typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator; typedef _Deque_iterator<_Tp, const _Tp&, const _Tp*> const_iterator;
...@@ -200,7 +202,9 @@ struct _Deque_iterator ...@@ -200,7 +202,9 @@ struct _Deque_iterator
* _M_first and _M_last. * _M_first and _M_last.
* @endif * @endif
*/ */
void _M_set_node(_Map_pointer __new_node) { void
_M_set_node(_Map_pointer __new_node)
{
_M_node = __new_node; _M_node = __new_node;
_M_first = *__new_node; _M_first = *__new_node;
_M_last = _M_first + difference_type(_S_buffer_size()); _M_last = _M_first + difference_type(_S_buffer_size());
...@@ -208,7 +212,7 @@ struct _Deque_iterator ...@@ -208,7 +212,7 @@ struct _Deque_iterator
}; };
// Note: we also provide overloads whose operands are of the same type in // Note: we also provide overloads whose operands are of the same type in
// order to avoid ambiguos overload resolution when std::rel_ops operators // order to avoid ambiguous overload resolution when std::rel_ops operators
// are in scope (for additional details, see libstdc++/3628) // are in scope (for additional details, see libstdc++/3628)
template <class _Tp, class _Ref, class _Ptr> template <class _Tp, class _Ref, class _Ptr>
inline bool inline bool
...@@ -321,14 +325,15 @@ operator+(ptrdiff_t __n, const _Deque_iterator<_Tp, _Ref, _Ptr>& __x) ...@@ -321,14 +325,15 @@ operator+(ptrdiff_t __n, const _Deque_iterator<_Tp, _Ref, _Ptr>& __x)
* @if maint * @if maint
* Deque base class. It has two purposes. First, its constructor * Deque base class. It has two purposes. First, its constructor
* and destructor allocate (but don't initialize) storage. This makes * and destructor allocate (but don't initialize) storage. This makes
* exception safety easier. Second, the base class encapsulates all of * %exception safety easier. Second, the base class encapsulates all of
* the differences between SGI-style allocators and standard-conforming * the differences between SGI-style allocators and standard-conforming
* allocators. There are two versions: this ordinary one, and the * allocators. (See stl_alloc.h for more on this topic.) There are two
* space-saving specialization for instanceless allocators. * versions: this ordinary one, and the space-saving specialization for
* instanceless allocators.
* @endif * @endif
*/ */
template <class _Tp, class _Alloc, bool __is_static> template <class _Tp, class _Alloc, bool __is_static>
class _Deque_alloc_base class _Deque_alloc_base
{ {
public: public:
typedef typename _Alloc_traits<_Tp,_Alloc>::allocator_type allocator_type; typedef typename _Alloc_traits<_Tp,_Alloc>::allocator_type allocator_type;
...@@ -343,51 +348,70 @@ protected: ...@@ -343,51 +348,70 @@ protected:
typedef typename _Alloc_traits<_Tp*, _Alloc>::allocator_type typedef typename _Alloc_traits<_Tp*, _Alloc>::allocator_type
_Map_allocator_type; _Map_allocator_type;
allocator_type _M_node_allocator; _Tp*
_Map_allocator_type _M_map_allocator; _M_allocate_node()
{
_Tp* _M_allocate_node() {
return _M_node_allocator.allocate(__deque_buf_size(sizeof(_Tp))); return _M_node_allocator.allocate(__deque_buf_size(sizeof(_Tp)));
} }
void _M_deallocate_node(_Tp* __p) {
void
_M_deallocate_node(_Tp* __p)
{
_M_node_allocator.deallocate(__p, __deque_buf_size(sizeof(_Tp))); _M_node_allocator.deallocate(__p, __deque_buf_size(sizeof(_Tp)));
} }
_Tp** _M_allocate_map(size_t __n)
_Tp**
_M_allocate_map(size_t __n)
{ return _M_map_allocator.allocate(__n); } { return _M_map_allocator.allocate(__n); }
void _M_deallocate_map(_Tp** __p, size_t __n)
void
_M_deallocate_map(_Tp** __p, size_t __n)
{ _M_map_allocator.deallocate(__p, __n); } { _M_map_allocator.deallocate(__p, __n); }
_Tp** _M_map; _Tp** _M_map;
size_t _M_map_size; size_t _M_map_size;
allocator_type _M_node_allocator;
_Map_allocator_type _M_map_allocator;
}; };
/// @if maint Specialization for instanceless allocators. @endif /// @if maint Specialization for instanceless allocators. @endif
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
class _Deque_alloc_base<_Tp, _Alloc, true> class _Deque_alloc_base<_Tp, _Alloc, true>
{ {
public: public:
typedef typename _Alloc_traits<_Tp,_Alloc>::allocator_type allocator_type; typedef typename _Alloc_traits<_Tp,_Alloc>::allocator_type allocator_type;
allocator_type get_allocator() const { return allocator_type(); } allocator_type get_allocator() const { return allocator_type(); }
_Deque_alloc_base(const allocator_type&) : _M_map(0), _M_map_size(0) {} _Deque_alloc_base(const allocator_type&)
: _M_map(0), _M_map_size(0)
{}
protected: protected:
typedef typename _Alloc_traits<_Tp, _Alloc>::_Alloc_type _Node_alloc_type; typedef typename _Alloc_traits<_Tp,_Alloc>::_Alloc_type _Node_alloc_type;
typedef typename _Alloc_traits<_Tp*, _Alloc>::_Alloc_type _Map_alloc_type; typedef typename _Alloc_traits<_Tp*,_Alloc>::_Alloc_type _Map_alloc_type;
_Tp* _M_allocate_node() { _Tp*
_M_allocate_node()
{
return _Node_alloc_type::allocate(__deque_buf_size(sizeof(_Tp))); return _Node_alloc_type::allocate(__deque_buf_size(sizeof(_Tp)));
} }
void _M_deallocate_node(_Tp* __p) {
void
_M_deallocate_node(_Tp* __p)
{
_Node_alloc_type::deallocate(__p, __deque_buf_size(sizeof(_Tp))); _Node_alloc_type::deallocate(__p, __deque_buf_size(sizeof(_Tp)));
} }
_Tp** _M_allocate_map(size_t __n)
_Tp**
_M_allocate_map(size_t __n)
{ return _Map_alloc_type::allocate(__n); } { return _Map_alloc_type::allocate(__n); }
void _M_deallocate_map(_Tp** __p, size_t __n)
void
_M_deallocate_map(_Tp** __p, size_t __n)
{ _Map_alloc_type::deallocate(__p, __n); } { _Map_alloc_type::deallocate(__p, __n); }
_Tp** _M_map; _Tp** _M_map;
size_t _M_map_size; size_t _M_map_size;
}; };
...@@ -395,14 +419,14 @@ protected: ...@@ -395,14 +419,14 @@ protected:
* @if maint * @if maint
* Deque base class. Using _Alloc_traits in the instantiation of the parent * Deque base class. Using _Alloc_traits in the instantiation of the parent
* class provides the compile-time dispatching mentioned in the parent's docs. * class provides the compile-time dispatching mentioned in the parent's docs.
* This class provides the unified face for deque's allocation. * This class provides the unified face for %deque's allocation.
* *
* Nothing in this class ever constructs or destroys an actual Tp element. * Nothing in this class ever constructs or destroys an actual Tp element.
* (Deque handles that itself.) Only/All memory management is performed here. * (Deque handles that itself.) Only/All memory management is performed here.
* @endif * @endif
*/ */
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
class _Deque_base class _Deque_base
: public _Deque_alloc_base<_Tp,_Alloc, : public _Deque_alloc_base<_Tp,_Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless> _Alloc_traits<_Tp, _Alloc>::_S_instanceless>
{ {
...@@ -427,7 +451,6 @@ protected: ...@@ -427,7 +451,6 @@ protected:
void _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish); void _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish);
enum { _S_initial_map_size = 8 }; enum { _S_initial_map_size = 8 };
protected:
iterator _M_start; iterator _M_start;
iterator _M_finish; iterator _M_finish;
}; };
...@@ -436,7 +459,8 @@ protected: ...@@ -436,7 +459,8 @@ protected:
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
_Deque_base<_Tp,_Alloc>::~_Deque_base() _Deque_base<_Tp,_Alloc>::~_Deque_base()
{ {
if (_M_map) { if (_M_map)
{
_M_destroy_nodes(_M_start._M_node, _M_finish._M_node + 1); _M_destroy_nodes(_M_start._M_node, _M_finish._M_node + 1);
_M_deallocate_map(_M_map, _M_map_size); _M_deallocate_map(_M_map, _M_map_size);
} }
...@@ -461,6 +485,10 @@ _Deque_base<_Tp,_Alloc>::_M_initialize_map(size_t __num_elements) ...@@ -461,6 +485,10 @@ _Deque_base<_Tp,_Alloc>::_M_initialize_map(size_t __num_elements)
_M_map_size = max((size_t) _S_initial_map_size, __num_nodes + 2); _M_map_size = max((size_t) _S_initial_map_size, __num_nodes + 2);
_M_map = _M_allocate_map(_M_map_size); _M_map = _M_allocate_map(_M_map_size);
// For "small" maps (needing less than _M_map_size nodes), allocation
// starts in the middle elements and grows outwards. So nstart may be the
// beginning of _M_map, but for small maps it may be as far in as _M_map+3.
_Tp** __nstart = _M_map + (_M_map_size - __num_nodes) / 2; _Tp** __nstart = _M_map + (_M_map_size - __num_nodes) / 2;
_Tp** __nfinish = __nstart + __num_nodes; _Tp** __nfinish = __nstart + __num_nodes;
...@@ -478,17 +506,18 @@ _Deque_base<_Tp,_Alloc>::_M_initialize_map(size_t __num_elements) ...@@ -478,17 +506,18 @@ _Deque_base<_Tp,_Alloc>::_M_initialize_map(size_t __num_elements)
_M_finish._M_set_node(__nfinish - 1); _M_finish._M_set_node(__nfinish - 1);
_M_start._M_cur = _M_start._M_first; _M_start._M_cur = _M_start._M_first;
_M_finish._M_cur = _M_finish._M_first + _M_finish._M_cur = _M_finish._M_first +
__num_elements % __deque_buf_size(sizeof(_Tp)); __num_elements % __deque_buf_size(sizeof(_Tp));
} }
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
void _Deque_base<_Tp,_Alloc>::_M_create_nodes(_Tp** __nstart, _Tp** __nfinish) void _Deque_base<_Tp,_Alloc>::_M_create_nodes(_Tp** __nstart, _Tp** __nfinish)
{ {
_Tp** __cur; _Tp** __cur;
try { try
for (__cur = __nstart; __cur < __nfinish; ++__cur) {
*__cur = _M_allocate_node(); for (__cur = __nstart; __cur < __nfinish; ++__cur)
} *__cur = _M_allocate_node();
}
catch(...) catch(...)
{ {
_M_destroy_nodes(__nstart, __cur); _M_destroy_nodes(__nstart, __cur);
...@@ -506,6 +535,9 @@ _Deque_base<_Tp,_Alloc>::_M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish) ...@@ -506,6 +535,9 @@ _Deque_base<_Tp,_Alloc>::_M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish)
/** /**
* @brief A standard container using fixed-size memory allocation and
* constant-time manipulation of elements at either end.
*
* @ingroup Containers * @ingroup Containers
* @ingroup Sequences * @ingroup Sequences
* *
...@@ -514,8 +546,6 @@ _Deque_base<_Tp,_Alloc>::_M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish) ...@@ -514,8 +546,6 @@ _Deque_base<_Tp,_Alloc>::_M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish)
* <a href="tables.html#67">sequence</a>, including the * <a href="tables.html#67">sequence</a>, including the
* <a href="tables.html#68">optional sequence requirements</a>. * <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 * 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 * so users could control the node size. This extension turned out to violate
* the C++ standard (it can be detected using template template parameters), * the C++ standard (it can be detected using template template parameters),
...@@ -529,7 +559,8 @@ _Deque_base<_Tp,_Alloc>::_M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish) ...@@ -529,7 +559,8 @@ _Deque_base<_Tp,_Alloc>::_M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish)
* - iterator _M_start, _M_finish * - iterator _M_start, _M_finish
* *
* map_size is at least 8. %map is an array of map_size pointers-to-"nodes". * 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.) * (The name %map has nothing to do with the std::map class, and "nodes"
* should not be confused with std::list's usage of "node".)
* *
* A "node" has no specific type name as such, but it is referred to as * 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, * "node" in this file. It is a simple array-of-Tp. If Tp is very large,
...@@ -586,32 +617,29 @@ _Deque_base<_Tp,_Alloc>::_M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish) ...@@ -586,32 +617,29 @@ _Deque_base<_Tp,_Alloc>::_M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish)
* @endif * @endif
*/ */
template <class _Tp, class _Alloc = allocator<_Tp> > template <class _Tp, class _Alloc = allocator<_Tp> >
class deque : protected _Deque_base<_Tp, _Alloc> class deque : protected _Deque_base<_Tp, _Alloc>
{ {
// concept requirements // concept requirements
__glibcpp_class_requires(_Tp, _SGIAssignableConcept) __glibcpp_class_requires(_Tp, _SGIAssignableConcept)
typedef _Deque_base<_Tp, _Alloc> _Base; typedef _Deque_base<_Tp, _Alloc> _Base;
public: public:
typedef _Tp value_type; typedef _Tp value_type;
typedef value_type* pointer; typedef value_type* pointer;
typedef const value_type* const_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::iterator iterator;
typedef typename _Base::const_iterator const_iterator; typedef typename _Base::const_iterator const_iterator;
typedef reverse_iterator<const_iterator> const_reverse_iterator; typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator; typedef reverse_iterator<iterator> reverse_iterator;
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;
protected: protected:
typedef pointer* _Map_pointer; typedef pointer* _Map_pointer;
static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); } static size_t _S_buffer_size() { return __deque_buf_size(sizeof(_Tp)); }
// Functions controlling memory layout, and nothing else. // Functions controlling memory layout, and nothing else.
...@@ -634,95 +662,91 @@ protected: ...@@ -634,95 +662,91 @@ protected:
using _Base::_M_start; using _Base::_M_start;
using _Base::_M_finish; using _Base::_M_finish;
public: // Basic accessors public:
iterator begin() { return _M_start; } // [23.2.1.1] construct/copy/destroy
iterator end() { return _M_finish; } // (assign() and get_allocator() are also listed in this section)
const_iterator begin() const { return _M_start; } /**
const_iterator end() const { return _M_finish; } * @brief Default constructor creates no elements.
*/
reverse_iterator rbegin() { return reverse_iterator(_M_finish); } explicit
reverse_iterator rend() { return reverse_iterator(_M_start); } deque(const allocator_type& __a = allocator_type())
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_range_error("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) {} : _Base(__a, 0) {}
deque(const deque& __x) : _Base(__x.get_allocator(), __x.size())
{ uninitialized_copy(__x.begin(), __x.end(), _M_start); } /**
* @brief Create a %deque with copies of an exemplar element.
* @param n The number of elements to initially create.
* @param value An element to copy.
*
* This constructor fills the %deque with @a n copies of @a value.
*/
deque(size_type __n, const value_type& __value, deque(size_type __n, const value_type& __value,
const allocator_type& __a = allocator_type()) : _Base(__a, __n) const allocator_type& __a = allocator_type())
: _Base(__a, __n)
{ _M_fill_initialize(__value); } { _M_fill_initialize(__value); }
/**
* @brief Create a %deque with default elements.
* @param n The number of elements to initially create.
*
* This constructor fills the %deque with @a n copies of a
* default-constructed element.
*/
explicit explicit
deque(size_type __n) deque(size_type __n)
: _Base(allocator_type(), __n) : _Base(allocator_type(), __n)
{ _M_fill_initialize(value_type()); } { _M_fill_initialize(value_type()); }
/**
* @brief %Deque copy constructor.
* @param x A %deque of identical element and allocator types.
*
* The newly-created %deque uses a copy of the allocation object used
* by @a x.
*/
deque(const deque& __x)
: _Base(__x.get_allocator(), __x.size())
{ uninitialized_copy(__x.begin(), __x.end(), _M_start); }
// Check whether it's an integral type. If so, it's not an iterator. /**
* @brief Builds a %deque from a range.
* @param first An input iterator.
* @param last An input iterator.
*
* Creats a %deque consisting of copies of the elements from [first,last).
*
* If the iterators are forward, bidirectional, or random-access, then
* this will call the elements' copy constructor N times (where N is
* distance(first,last)) and do no memory reallocation. But if only
* input iterators are used, then this will do at most 2N calls to the
* copy constructor, and logN memory reallocations.
*/
template<class _InputIterator> template<class _InputIterator>
deque(_InputIterator __first, _InputIterator __last, deque(_InputIterator __first, _InputIterator __last,
const allocator_type& __a = allocator_type()) const allocator_type& __a = allocator_type())
: _Base(__a) : _Base(__a)
{ {
// Check whether it's an integral type. If so, it's not an iterator.
typedef typename _Is_integer<_InputIterator>::_Integral _Integral; typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
_M_initialize_dispatch(__first, __last, _Integral()); _M_initialize_dispatch(__first, __last, _Integral());
} }
template<class _Integer> /**
void * The dtor only erases the elements, and note that if the elements
_M_initialize_dispatch(_Integer __n, _Integer __x, __true_type) * themselves are pointers, the pointed-to memory is not touched in any
{ * way. Managing the pointer is the user's responsibilty.
_M_initialize_map(__n); */
_M_fill_initialize(__x); ~deque() { _Destroy(_M_start, _M_finish); }
}
/**
template<class _InputIter> * @brief %Deque assignment operator.
void * @param x A %deque of identical element and allocator types.
_M_initialize_dispatch(_InputIter __first, _InputIter __last, __false_type) *
{ * All the elements of @a x are copied, but unlike the copy constructor, the
typedef typename iterator_traits<_InputIter>::iterator_category _IterCategory; * allocator object is not copied.
_M_range_initialize(__first, __last, _IterCategory()); */
} deque&
operator=(const deque& __x) // FIXME move to tcc
~deque() {
{ _Destroy(_M_start, _M_finish); }
deque& operator= (const deque& __x) {
const size_type __len = size(); const size_type __len = size();
if (&__x != this) { if (&__x != this) {
if (__len >= __x.size()) if (__len >= __x.size())
...@@ -736,34 +760,31 @@ public: // Constructor, destructor. ...@@ -736,34 +760,31 @@ public: // Constructor, destructor.
return *this; return *this;
} }
void swap(deque& __x) { /**
std::swap(_M_start, __x._M_start); * @brief Assigns a given value to a %deque.
std::swap(_M_finish, __x._M_finish); * @param n Number of elements to be assigned.
std::swap(_M_map, __x._M_map); * @param val Value to be assigned.
std::swap(_M_map_size, __x._M_map_size); *
} * This function fills a %deque with @a n copies of the given value.
* Note that the assignment completely changes the %deque and that the
public: * resulting %deque's size is the same as the number of elements assigned.
// assign(), a generalized assignment member function. Two * Old data may be lost.
// 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 void
assign(size_type __n, const _Tp& __val) assign(size_type __n, const value_type& __val) { _M_fill_assign(__n, __val); }
{ _M_fill_assign(__n, __val); }
/**
* @brief Assigns a range to a %deque.
* @param first An input iterator.
* @param last An input iterator.
*
* This function fills a %deque with copies of the elements in the
* range [first,last).
*
* Note that the assignment completely changes the %deque and that the
* resulting %deque's size is the same as the number of elements assigned.
* Old data may be lost.
*/
template<class _InputIterator> template<class _InputIterator>
void void
assign(_InputIterator __first, _InputIterator __last) assign(_InputIterator __first, _InputIterator __last)
...@@ -772,74 +793,247 @@ public: ...@@ -772,74 +793,247 @@ public:
_M_assign_dispatch(__first, __last, _Integral()); _M_assign_dispatch(__first, __last, _Integral());
} }
private: // helper functions for assign() /// Get a copy of the memory allocation object.
allocator_type
get_allocator() const { return _Base::get_allocator(); }
template<class _Integer> // iterators
void /**
_M_assign_dispatch(_Integer __n, _Integer __val, __true_type) * Returns a read/write iterator that points to the first element in the
{ _M_fill_assign(static_cast<size_type>(__n), static_cast<_Tp>(__val)); } * %deque. Iteration is done in ordinary element order.
*/
iterator
begin() { return _M_start; }
template<class _InputIterator> /**
void * Returns a read-only (constant) iterator that points to the first element
_M_assign_dispatch(_InputIterator __first, _InputIterator __last, __false_type) * in the %deque. Iteration is done in ordinary element order.
{ */
typedef typename iterator_traits<_InputIterator>::iterator_category _IterCategory; const_iterator
_M_assign_aux(__first, __last, _IterCategory()); begin() const { return _M_start; }
}
template <class _InputIterator> /**
void _M_assign_aux(_InputIterator __first, _InputIterator __last, * Returns a read/write iterator that points one past the last element in
input_iterator_tag); * the %deque. Iteration is done in ordinary element order.
*/
iterator
end() { return _M_finish; }
template <class _ForwardIterator> /**
void _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last, * Returns a read-only (constant) iterator that points one past the last
forward_iterator_tag) { * element in the %deque. Iteration is done in ordinary element order.
size_type __len = distance(__first, __last); */
if (__len > size()) { const_iterator
_ForwardIterator __mid = __first; end() const { return _M_finish; }
advance(__mid, size());
copy(__first, __mid, begin());
insert(end(), __mid, __last);
}
else
erase(copy(__first, __last, begin()), end());
}
public: // push_* and pop_* /**
* Returns a read/write reverse iterator that points to the last element in
* the %deque. Iteration is done in reverse element order.
*/
reverse_iterator
rbegin() { return reverse_iterator(_M_finish); }
/**
* Returns a read-only (constant) reverse iterator that points to the last
* element in the %deque. Iteration is done in reverse element order.
*/
const_reverse_iterator
rbegin() const { return const_reverse_iterator(_M_finish); }
/**
* Returns a read/write reverse iterator that points to one before the
* first element in the %deque. Iteration is done in reverse element
* order.
*/
reverse_iterator
rend() { return reverse_iterator(_M_start); }
/**
* Returns a read-only (constant) reverse iterator that points to one
* before the first element in the %deque. Iteration is done in reverse
* element order.
*/
const_reverse_iterator
rend() const { return const_reverse_iterator(_M_start); }
// [23.2.1.2] capacity
/** Returns the number of elements in the %deque. */
size_type
size() const { return _M_finish - _M_start; }
/** Returns the size() of the largest possible %deque. */
size_type
max_size() const { return size_type(-1); }
/**
* @brief Resizes the %deque to the specified number of elements.
* @param new_size Number of elements the %deque should contain.
* @param x Data with which new elements should be populated.
*
* This function will %resize the %deque to the specified number of
* elements. If the number is smaller than the %deque's current size the
* %deque is truncated, otherwise the %deque is extended and new elements
* are populated with given data.
*/
void void
push_back(const value_type& __t) resize(size_type __new_size, const value_type& __x)
{ {
if (_M_finish._M_cur != _M_finish._M_last - 1) { const size_type __len = size();
_Construct(_M_finish._M_cur, __t); if (__new_size < __len)
++_M_finish._M_cur; erase(_M_start + __new_size, _M_finish);
}
else else
_M_push_back_aux(__t); insert(_M_finish, __new_size - __len, __x);
} }
/**
* @brief Resizes the %deque to the specified number of elements.
* @param new_size Number of elements the %deque should contain.
*
* This function will resize the %deque to the specified number of
* elements. If the number is smaller than the %deque's current size the
* %deque is truncated, otherwise the %deque is extended and new elements
* are default-constructed.
*/
void void
push_back() resize(size_type new_size) { resize(new_size, value_type()); }
/**
* Returns true if the %deque is empty. (Thus begin() would equal end().)
*/
bool empty() const { return _M_finish == _M_start; }
// element access
/**
* @brief Subscript access to the data contained in the %deque.
* @param n The index of the element for which data should be accessed.
* @return Read/write reference to data.
*
* This operator allows for easy, array-style, data access.
* Note that data access with this operator is unchecked and out_of_range
* lookups are not defined. (For checked lookups see at().)
*/
reference
operator[](size_type __n) { return _M_start[difference_type(__n)]; }
/**
* @brief Subscript access to the data contained in the %deque.
* @param n The index of the element for which data should be accessed.
* @return Read-only (constant) reference to data.
*
* This operator allows for easy, array-style, data access.
* Note that data access with this operator is unchecked and out_of_range
* lookups are not defined. (For checked lookups see at().)
*/
const_reference
operator[](size_type __n) const { return _M_start[difference_type(__n)]; }
protected:
/// @if maint Safety check used only from at(). @endif
void
_M_range_check(size_type __n) const
{ {
if (_M_finish._M_cur != _M_finish._M_last - 1) { if (__n >= this->size())
_Construct(_M_finish._M_cur); __throw_out_of_range("deque [] access out of range");
++_M_finish._M_cur;
}
else
_M_push_back_aux();
} }
public:
/**
* @brief Provides access to the data contained in the %deque.
* @param n The index of the element for which data should be accessed.
* @return Read/write reference to data.
* @throw std::out_of_range If @a n is an invalid index.
*
* This function provides for safer data access. The parameter is first
* checked that it is in the range of the deque. The function throws
* out_of_range if the check fails.
*/
reference
at(size_type __n) { _M_range_check(__n); return (*this)[__n]; }
/**
* @brief Provides access to the data contained in the %deque.
* @param n The index of the element for which data should be accessed.
* @return Read-only (constant) reference to data.
* @throw std::out_of_range If @a n is an invalid index.
*
* This function provides for safer data access. The parameter is first
* checked that it is in the range of the deque. The function throws
* out_of_range if the check fails.
*/
const_reference
at(size_type __n) const { _M_range_check(__n); return (*this)[__n]; }
/**
* Returns a read/write reference to the data at the first element of the
* %deque.
*/
reference
front() { return *_M_start; }
/**
* Returns a read-only (constant) reference to the data at the first
* element of the %deque.
*/
const_reference
front() const { return *_M_start; }
/**
* Returns a read/write reference to the data at the last element of the
* %deque.
*/
reference
back()
{
iterator __tmp = _M_finish;
--__tmp;
return *__tmp;
}
/**
* Returns a read-only (constant) reference to the data at the last
* element of the %deque.
*/
const_reference
back() const
{
const_iterator __tmp = _M_finish;
--__tmp;
return *__tmp;
}
// [23.2.1.2] modifiers
/**
* @brief Add data to the front of the %deque.
* @param x Data to be added.
*
* This is a typical stack operation. The function creates an element at
* the front of the %deque and assigns the given data to it. Due to the
* nature of a %deque this operation can be done in constant time.
*/
void void
push_front(const value_type& __t) push_front(const value_type& __x)
{ {
if (_M_start._M_cur != _M_start._M_first) { if (_M_start._M_cur != _M_start._M_first) {
_Construct(_M_start._M_cur - 1, __t); _Construct(_M_start._M_cur - 1, __x);
--_M_start._M_cur; --_M_start._M_cur;
} }
else else
_M_push_front_aux(__t); _M_push_front_aux(__x);
} }
#ifdef _GLIBCPP_DEPRECATED
/**
* @brief Add data to the front of the %deque.
*
* This is a typical stack operation. The function creates a
* default-constructed element at the front of the %deque. Due to the nature
* of a %deque this operation can be done in constant time. You should
* consider using push_front(value_type()) instead.
*
* @note This was deprecated in 3.2 and will be removed in 3.3. You must
* define @c _GLIBCPP_DEPRECATED to make this visible in 3.2; see
* c++config.h.
*/
void void
push_front() push_front()
{ {
...@@ -850,19 +1044,60 @@ public: // push_* and pop_* ...@@ -850,19 +1044,60 @@ public: // push_* and pop_*
else else
_M_push_front_aux(); _M_push_front_aux();
} }
#endif
/**
* @brief Add data to the end of the %deque.
* @param x Data to be added.
*
* This is a typical stack operation. The function creates an element at
* the end of the %deque and assigns the given data to it. Due to the
* nature of a %deque this operation can be done in constant time.
*/
void void
pop_back() push_back(const value_type& __x)
{ {
if (_M_finish._M_cur != _M_finish._M_first) { if (_M_finish._M_cur != _M_finish._M_last - 1) {
--_M_finish._M_cur; _Construct(_M_finish._M_cur, __x);
_Destroy(_M_finish._M_cur); ++_M_finish._M_cur;
} }
else else
_M_pop_back_aux(); _M_push_back_aux(__x);
} }
#ifdef _GLIBCPP_DEPRECATED
/**
* @brief Add data to the end of the %deque.
*
* This is a typical stack operation. The function creates a
* default-constructed element at the end of the %deque. Due to the nature
* of a %deque this operation can be done in constant time. You should
* consider using push_back(value_type()) instead.
*
* @note This was deprecated in 3.2 and will be removed in 3.3. You must
* define @c _GLIBCPP_DEPRECATED to make this visible in 3.2; see
* c++config.h.
*/
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();
}
#endif
/**
* @brief Removes first element.
*
* This is a typical stack operation. It shrinks the %deque by one.
*
* Note that no data is returned, and if the first element's data is
* needed, it should be retrieved before pop_front() is called.
*/
void void
pop_front() pop_front()
{ {
...@@ -874,8 +1109,34 @@ public: // push_* and pop_* ...@@ -874,8 +1109,34 @@ public: // push_* and pop_*
_M_pop_front_aux(); _M_pop_front_aux();
} }
public: // Insert /**
* @brief Removes last element.
*
* This is a typical stack operation. It shrinks the %deque by one.
*
* Note that no data is returned, and if the last element's data is
* needed, it should be retrieved before pop_back() is called.
*/
void
pop_back()
{
if (_M_finish._M_cur != _M_finish._M_first) {
--_M_finish._M_cur;
_Destroy(_M_finish._M_cur);
}
else
_M_pop_back_aux();
}
/**
* @brief Inserts given value into %deque before specified iterator.
* @param position An iterator into the %deque.
* @param x Data to be inserted.
* @return An iterator that points to the inserted data.
*
* This function will insert a copy of the given value before the specified
* location.
*/
iterator iterator
insert(iterator position, const value_type& __x) insert(iterator position, const value_type& __x)
{ {
...@@ -894,148 +1155,381 @@ public: // Insert ...@@ -894,148 +1155,381 @@ public: // Insert
} }
} }
#ifdef _GLIBCPP_DEPRECATED
/**
* @brief Inserts an element into the %deque.
* @param position An iterator into the %deque.
* @return An iterator that points to the inserted element.
*
* This function will insert a default-constructed element before the
* specified location. You should consider using
* insert(position,value_type()) instead.
*
* @note This was deprecated in 3.2 and will be removed in 3.3. You must
* define @c _GLIBCPP_DEPRECATED to make this visible in 3.2; see
* c++config.h.
*/
iterator iterator
insert(iterator __position) insert(iterator __position)
{ return insert(__position, value_type()); } { return insert(__position, value_type()); }
#endif
void
insert(iterator __pos, size_type __n, const value_type& __x) /**
{ _M_fill_insert(__pos, __n, __x); } * @brief Inserts a number of copies of given data into the %deque.
* @param position An iterator into the %deque.
* @param n Number of elements to be inserted.
* @param x Data to be inserted.
*
* This function will insert a specified number of copies of the given data
* before the location specified by @a position.
*/
void void
_M_fill_insert(iterator __pos, size_type __n, const value_type& __x); insert(iterator __position, size_type __n, const value_type& __x)
{ _M_fill_insert(__position, __n, __x); }
// Check whether it's an integral type. If so, it's not an iterator.
/**
* @brief Inserts a range into the %deque.
* @param pos An iterator into the %deque.
* @param first An input iterator.
* @param last An input iterator.
*
* This function will insert copies of the data in the range [first,last)
* into the %deque before the location specified by @a pos. This is
* known as "range insert."
*/
template<class _InputIterator> template<class _InputIterator>
void void
insert(iterator __pos, _InputIterator __first, _InputIterator __last) insert(iterator __pos, _InputIterator __first, _InputIterator __last)
{ {
// Check whether it's an integral type. If so, it's not an iterator.
typedef typename _Is_integer<_InputIterator>::_Integral _Integral; typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
_M_insert_dispatch(__pos, __first, __last, _Integral()); _M_insert_dispatch(__pos, __first, __last, _Integral());
} }
template<class _Integer> /**
void * @brief Remove element at given position.
_M_insert_dispatch(iterator __pos, _Integer __n, _Integer __x, __true_type) * @param position Iterator pointing to element to be erased.
{ _M_fill_insert(__pos, static_cast<size_type>(__n), static_cast<value_type>(__x)); } * @return An iterator pointing to the next element (or end()).
*
template<class _InputIterator> * This function will erase the element at the given position and thus
void * shorten the %deque by one.
_M_insert_dispatch(iterator __pos, *
_InputIterator __first, _InputIterator __last, * The user is cautioned that
__false_type) * this function only erases the element, and that if the element is itself
{ * a pointer, the pointed-to memory is not touched in any way. Managing
typedef typename iterator_traits<_InputIterator>::iterator_category _IterCategory; * the pointer is the user's responsibilty.
insert(__pos, __first, __last, _IterCategory()); */
} iterator
erase(iterator __position)
void resize(size_type __new_size, const value_type& __x) { {
const size_type __len = size(); iterator __next = __position;
if (__new_size < __len)
erase(_M_start + __new_size, _M_finish);
else
insert(_M_finish, __new_size - __len, __x);
}
void resize(size_type new_size) { resize(new_size, value_type()); }
public: // Erase
iterator erase(iterator __pos) {
iterator __next = __pos;
++__next; ++__next;
size_type __index = __pos - _M_start; size_type __index = __position - _M_start;
if (__index < (size() >> 1)) { if (__index < (size() >> 1)) {
copy_backward(_M_start, __pos, __next); copy_backward(_M_start, __position, __next);
pop_front(); pop_front();
} }
else { else {
copy(__next, _M_finish, __pos); copy(__next, _M_finish, __position);
pop_back(); pop_back();
} }
return _M_start + __index; return _M_start + __index;
} }
iterator erase(iterator __first, iterator __last); /**
* @brief Remove a range of elements.
* @param first Iterator pointing to the first element to be erased.
* @param last Iterator pointing to one past the last element to be erased.
* @return An iterator pointing to the element pointed to by @a last
* prior to erasing (or end()).
*
* This function will erase the elements in the range [first,last) and
* shorten the %deque accordingly.
*
* The user is cautioned that
* this function only erases the elements, and that if the elements
* themselves are pointers, the pointed-to memory is not touched in any
* way. Managing the pointer is the user's responsibilty.
*/
iterator
erase(iterator __first, iterator __last);
/**
* @brief Swaps data with another %deque.
* @param x A %deque of the same element and allocator types.
*
* This exchanges the elements between two deques in constant time.
* (Four pointers, so it should be quite fast.)
* Note that the global std::swap() function is specialized such that
* std::swap(d1,d2) will feed to this function.
*/
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);
}
/**
* Erases all the elements. Note that this function only erases the
* elements, and that if the elements themselves are pointers, the
* pointed-to memory is not touched in any way. Managing the pointer is
* the user's responsibilty.
*/
void clear(); void clear();
protected: // Internal construction/destruction protected:
// Internal constructor functions follow.
void _M_fill_initialize(const value_type& __value); // called by the range constructor to implement [23.1.1]/9
template<class _Integer>
void
_M_initialize_dispatch(_Integer __n, _Integer __x, __true_type)
{
_M_initialize_map(__n);
_M_fill_initialize(__x);
}
// called by the range constructor to implement [23.1.1]/9
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());
}
// called by the second initialize_dispatch above
template <class _InputIterator> template <class _InputIterator>
void _M_range_initialize(_InputIterator __first, _InputIterator __last, void
_M_range_initialize(_InputIterator __first, _InputIterator __last,
input_iterator_tag); input_iterator_tag);
// called by the second initialize_dispatch above
template <class _ForwardIterator> template <class _ForwardIterator>
void _M_range_initialize(_ForwardIterator __first, _ForwardIterator __last, void
_M_range_initialize(_ForwardIterator __first, _ForwardIterator __last,
forward_iterator_tag); forward_iterator_tag);
protected: // Internal push_* and pop_* /**
* @if maint
* @brief Fills the %deque with copies of value.
* @param value Initial value.
* @return Nothing.
* @pre _M_start and _M_finish have already been initialized, but none of
* the %deque's elements have yet been constructed.
*
* This function is called only when the user provides an explicit size
* (with or without an explicit exemplar value).
* @endif
*/
void
_M_fill_initialize(const value_type& __value);
// Internal assign functions follow. The *_aux functions do the actual
// assignment work for the range versions.
// called by the range assign to implement [23.1.1]/9
template<class _Integer>
void
_M_assign_dispatch(_Integer __n, _Integer __val, __true_type)
{
_M_fill_assign(static_cast<size_type>(__n),
static_cast<value_type>(__val));
}
// called by the range assign to implement [23.1.1]/9
template<class _InputIter>
void
_M_assign_dispatch(_InputIter __first, _InputIter __last, __false_type)
{
typedef typename iterator_traits<_InputIter>::iterator_category
_IterCategory;
_M_assign_aux(__first, __last, _IterCategory());
}
// called by the second assign_dispatch above
template <class _InputIterator>
void
_M_assign_aux(_InputIterator __first, _InputIterator __last,
input_iterator_tag);
// called by the second assign_dispatch above
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());
}
// Called by assign(n,t), and the range assign when it turns out to be the
// same thing.
void
_M_fill_assign(size_type __n, const value_type& __val)
{
if (__n > size())
{
fill(begin(), end(), __val);
insert(end(), __n - size(), __val);
}
else
{
erase(begin() + __n, end());
fill(begin(), end(), __val);
}
}
/** @{
* @if maint
* @brief Helper functions for push_* and pop_*.
* @endif
*/
void _M_push_back_aux(const value_type&); void _M_push_back_aux(const value_type&);
void _M_push_back_aux();
void _M_push_front_aux(const value_type&); void _M_push_front_aux(const value_type&);
#ifdef _GLIBCPP_DEPRECATED
void _M_push_back_aux();
void _M_push_front_aux(); void _M_push_front_aux();
#endif
void _M_pop_back_aux(); void _M_pop_back_aux();
void _M_pop_front_aux(); void _M_pop_front_aux();
/** @} */
// Internal insert functions follow. The *_aux functions do the actual
// insertion work when all shortcuts fail.
// called by the range insert to implement [23.1.1]/9
template<class _Integer>
void
_M_insert_dispatch(iterator __pos, _Integer __n, _Integer __x, __true_type)
{
_M_fill_insert(__pos, static_cast<size_type>(__n),
static_cast<value_type>(__x));
}
protected: // Internal insert functions // called by the range insert to implement [23.1.1]/9
template<class _InputIterator>
void
_M_insert_dispatch(iterator __pos,
_InputIterator __first, _InputIterator __last,
__false_type)
{
typedef typename iterator_traits<_InputIterator>::iterator_category
_IterCategory;
_M_range_insert_aux(__pos, __first, __last, _IterCategory());
}
// called by the second insert_dispatch above
template <class _InputIterator> template <class _InputIterator>
void insert(iterator __pos, _InputIterator __first, _InputIterator __last, void
input_iterator_tag); _M_range_insert_aux(iterator __pos, _InputIterator __first,
_InputIterator __last, input_iterator_tag);
// called by the second insert_dispatch above
template <class _ForwardIterator> template <class _ForwardIterator>
void insert(iterator __pos, void
_ForwardIterator __first, _ForwardIterator __last, _M_range_insert_aux(iterator __pos, _ForwardIterator __first,
forward_iterator_tag); _ForwardIterator __last, forward_iterator_tag);
iterator _M_insert_aux(iterator __pos, const value_type& __x); // Called by insert(p,n,x), and the range insert when it turns out to be
iterator _M_insert_aux(iterator __pos); // the same thing. Can use fill functions in optimal situations, otherwise
void _M_insert_aux(iterator __pos, size_type __n, const value_type& __x); // passes off to insert_aux(p,n,x).
void
_M_fill_insert(iterator __pos, size_type __n, const value_type& __x);
// called by insert(p,x)
iterator
_M_insert_aux(iterator __pos, const value_type& __x);
// called by insert(p,n,x) via fill_insert
void
_M_insert_aux(iterator __pos, size_type __n, const value_type& __x);
// called by range_insert_aux for forward iterators
template <class _ForwardIterator> template <class _ForwardIterator>
void _M_insert_aux(iterator __pos, void
_ForwardIterator __first, _ForwardIterator __last, _M_insert_aux(iterator __pos,
size_type __n); _ForwardIterator __first, _ForwardIterator __last,
size_type __n);
iterator _M_reserve_elements_at_front(size_type __n) { #ifdef _GLIBCPP_DEPRECATED
// unused, see comment in implementation
iterator _M_insert_aux(iterator __pos);
#endif
/** @{
* @if maint
* @brief Memory-handling helpers for the previous internal insert functions.
* @endif
*/
iterator
_M_reserve_elements_at_front(size_type __n)
{
size_type __vacancies = _M_start._M_cur - _M_start._M_first; size_type __vacancies = _M_start._M_cur - _M_start._M_first;
if (__n > __vacancies) if (__n > __vacancies)
_M_new_elements_at_front(__n - __vacancies); _M_new_elements_at_front(__n - __vacancies);
return _M_start - difference_type(__n); return _M_start - difference_type(__n);
} }
iterator _M_reserve_elements_at_back(size_type __n) { iterator
_M_reserve_elements_at_back(size_type __n)
{
size_type __vacancies = (_M_finish._M_last - _M_finish._M_cur) - 1; size_type __vacancies = (_M_finish._M_last - _M_finish._M_cur) - 1;
if (__n > __vacancies) if (__n > __vacancies)
_M_new_elements_at_back(__n - __vacancies); _M_new_elements_at_back(__n - __vacancies);
return _M_finish + difference_type(__n); return _M_finish + difference_type(__n);
} }
void _M_new_elements_at_front(size_type __new_elements); void
void _M_new_elements_at_back(size_type __new_elements); _M_new_elements_at_front(size_type __new_elements);
protected: // Allocation of _M_map and nodes void
_M_new_elements_at_back(size_type __new_elements);
/** @} */
// Makes sure the _M_map has space for new nodes. Does not actually
// add the nodes. Can invalidate _M_map pointers. (And consequently,
// deque iterators.)
void _M_reserve_map_at_back (size_type __nodes_to_add = 1) { /** @{
* @if maint
* @brief Memory-handling helpers for the major %map.
*
* Makes sure the _M_map has space for new nodes. Does not actually add
* the nodes. Can invalidate _M_map pointers. (And consequently, %deque
* iterators.)
* @endif
*/
void
_M_reserve_map_at_back (size_type __nodes_to_add = 1)
{
if (__nodes_to_add + 1 > _M_map_size - (_M_finish._M_node - _M_map)) if (__nodes_to_add + 1 > _M_map_size - (_M_finish._M_node - _M_map))
_M_reallocate_map(__nodes_to_add, false); _M_reallocate_map(__nodes_to_add, false);
} }
void _M_reserve_map_at_front (size_type __nodes_to_add = 1) { void
_M_reserve_map_at_front (size_type __nodes_to_add = 1)
{
if (__nodes_to_add > size_type(_M_start._M_node - _M_map)) if (__nodes_to_add > size_type(_M_start._M_node - _M_map))
_M_reallocate_map(__nodes_to_add, true); _M_reallocate_map(__nodes_to_add, true);
} }
void _M_reallocate_map(size_type __nodes_to_add, bool __add_at_front); void
_M_reallocate_map(size_type __nodes_to_add, bool __add_at_front);
/** @} */
}; };
// Non-inline member functions
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
template <class _InputIter> template <class _InputIter>
...@@ -1055,7 +1549,8 @@ template <class _Tp, class _Alloc> ...@@ -1055,7 +1549,8 @@ template <class _Tp, class _Alloc>
void deque<_Tp, _Alloc>::_M_fill_insert(iterator __pos, void deque<_Tp, _Alloc>::_M_fill_insert(iterator __pos,
size_type __n, const value_type& __x) size_type __n, const value_type& __x)
{ {
if (__pos._M_cur == _M_start._M_cur) { if (__pos._M_cur == _M_start._M_cur)
{
iterator __new_start = _M_reserve_elements_at_front(__n); iterator __new_start = _M_reserve_elements_at_front(__n);
try { try {
uninitialized_fill(__new_start, _M_start, __x); uninitialized_fill(__new_start, _M_start, __x);
...@@ -1067,7 +1562,8 @@ void deque<_Tp, _Alloc>::_M_fill_insert(iterator __pos, ...@@ -1067,7 +1562,8 @@ void deque<_Tp, _Alloc>::_M_fill_insert(iterator __pos,
__throw_exception_again; __throw_exception_again;
} }
} }
else if (__pos._M_cur == _M_finish._M_cur) { else if (__pos._M_cur == _M_finish._M_cur)
{
iterator __new_finish = _M_reserve_elements_at_back(__n); iterator __new_finish = _M_reserve_elements_at_back(__n);
try { try {
uninitialized_fill(_M_finish, __new_finish, __x); uninitialized_fill(_M_finish, __new_finish, __x);
...@@ -1133,18 +1629,6 @@ void deque<_Tp,_Alloc>::clear() ...@@ -1133,18 +1629,6 @@ void deque<_Tp,_Alloc>::clear()
_M_finish = _M_start; _M_finish = _M_start;
} }
/**
* @if maint
* @brief Fills the deque with copies of value.
* @param value Initial value.
* @return Nothing.
* @pre _M_start and _M_finish have already been initialized, but none of the
* deque's elements have yet been constructed.
*
* This function is called only when the user provides an explicit size (with
* or without an explicit exemplar value).
* @endif
*/
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
void deque<_Tp,_Alloc>::_M_fill_initialize(const value_type& __value) void deque<_Tp,_Alloc>::_M_fill_initialize(const value_type& __value)
{ {
...@@ -1238,6 +1722,7 @@ deque<_Tp,_Alloc>::_M_push_back_aux(const value_type& __t) ...@@ -1238,6 +1722,7 @@ deque<_Tp,_Alloc>::_M_push_back_aux(const value_type& __t)
} }
} }
#ifdef _GLIBCPP_DEPRECATED
// Called only if _M_finish._M_cur == _M_finish._M_last - 1. // Called only if _M_finish._M_cur == _M_finish._M_last - 1.
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
void void
...@@ -1256,6 +1741,7 @@ deque<_Tp,_Alloc>::_M_push_back_aux() ...@@ -1256,6 +1741,7 @@ deque<_Tp,_Alloc>::_M_push_back_aux()
__throw_exception_again; __throw_exception_again;
} }
} }
#endif
// Called only if _M_start._M_cur == _M_start._M_first. // Called only if _M_start._M_cur == _M_start._M_first.
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
...@@ -1278,6 +1764,7 @@ deque<_Tp,_Alloc>::_M_push_front_aux(const value_type& __t) ...@@ -1278,6 +1764,7 @@ deque<_Tp,_Alloc>::_M_push_front_aux(const value_type& __t)
} }
} }
#ifdef _GLIBCPP_DEPRECATED
// Called only if _M_start._M_cur == _M_start._M_first. // Called only if _M_start._M_cur == _M_start._M_first.
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
void void
...@@ -1297,6 +1784,7 @@ deque<_Tp,_Alloc>::_M_push_front_aux() ...@@ -1297,6 +1784,7 @@ deque<_Tp,_Alloc>::_M_push_front_aux()
__throw_exception_again; __throw_exception_again;
} }
} }
#endif
// Called only if _M_finish._M_cur == _M_finish._M_first. // Called only if _M_finish._M_cur == _M_finish._M_first.
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
...@@ -1322,7 +1810,7 @@ void deque<_Tp,_Alloc>::_M_pop_front_aux() ...@@ -1322,7 +1810,7 @@ void deque<_Tp,_Alloc>::_M_pop_front_aux()
} }
template <class _Tp, class _Alloc> template <class _InputIterator> template <class _Tp, class _Alloc> template <class _InputIterator>
void deque<_Tp,_Alloc>::insert(iterator __pos, void deque<_Tp,_Alloc>::_M_range_insert_aux(iterator __pos,
_InputIterator __first, _InputIterator __last, _InputIterator __first, _InputIterator __last,
input_iterator_tag) input_iterator_tag)
{ {
...@@ -1331,7 +1819,7 @@ void deque<_Tp,_Alloc>::insert(iterator __pos, ...@@ -1331,7 +1819,7 @@ void deque<_Tp,_Alloc>::insert(iterator __pos,
template <class _Tp, class _Alloc> template <class _ForwardIterator> template <class _Tp, class _Alloc> template <class _ForwardIterator>
void void
deque<_Tp,_Alloc>::insert(iterator __pos, deque<_Tp,_Alloc>::_M_range_insert_aux(iterator __pos,
_ForwardIterator __first, _ForwardIterator __last, _ForwardIterator __first, _ForwardIterator __last,
forward_iterator_tag) { forward_iterator_tag) {
size_type __n = distance(__first, __last); size_type __n = distance(__first, __last);
...@@ -1368,7 +1856,7 @@ typename deque<_Tp, _Alloc>::iterator ...@@ -1368,7 +1856,7 @@ typename deque<_Tp, _Alloc>::iterator
deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos, const value_type& __x) deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos, const value_type& __x)
{ {
difference_type __index = __pos - _M_start; difference_type __index = __pos - _M_start;
value_type __x_copy = __x; value_type __x_copy = __x; // XXX copy
if (static_cast<size_type>(__index) < size() / 2) { if (static_cast<size_type>(__index) < size() / 2) {
push_front(front()); push_front(front());
iterator __front1 = _M_start; iterator __front1 = _M_start;
...@@ -1393,6 +1881,11 @@ deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos, const value_type& __x) ...@@ -1393,6 +1881,11 @@ deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos, const value_type& __x)
return __pos; return __pos;
} }
#ifdef _GLIBCPP_DEPRECATED
// Nothing seems to actually use this. According to the pattern followed by
// the rest of the SGI code, it would be called by the deprecated insert(pos)
// function, but that has been replaced. We'll take our time removing this
// anyhow; mark for 3.3. -pme
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
typename deque<_Tp,_Alloc>::iterator typename deque<_Tp,_Alloc>::iterator
deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos) deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos)
...@@ -1421,6 +1914,7 @@ deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos) ...@@ -1421,6 +1914,7 @@ deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos)
*__pos = value_type(); *__pos = value_type();
return __pos; return __pos;
} }
#endif
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
void deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos, void deque<_Tp,_Alloc>::_M_insert_aux(iterator __pos,
...@@ -1621,47 +2115,75 @@ void deque<_Tp,_Alloc>::_M_reallocate_map(size_type __nodes_to_add, ...@@ -1621,47 +2115,75 @@ void deque<_Tp,_Alloc>::_M_reallocate_map(size_type __nodes_to_add,
} }
// Nonmember functions. /**
* @brief Deque equality comparison.
* @param x A %deque.
* @param y A %deque of the same type as @a x.
* @return True iff the size and elements of the deques are equal.
*
* This is an equivalence relation. It is linear in the size of the
* deques. Deques are considered equivalent if their sizes are equal,
* and if corresponding elements compare equal.
*/
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
inline bool operator==(const deque<_Tp, _Alloc>& __x, inline bool operator==(const deque<_Tp, _Alloc>& __x,
const deque<_Tp, _Alloc>& __y) { const deque<_Tp, _Alloc>& __y)
{
return __x.size() == __y.size() && return __x.size() == __y.size() &&
equal(__x.begin(), __x.end(), __y.begin()); equal(__x.begin(), __x.end(), __y.begin());
} }
/**
* @brief Deque ordering relation.
* @param x A %deque.
* @param y A %deque of the same type as @a x.
* @return True iff @a x is lexographically less than @a y.
*
* This is a total ordering relation. It is linear in the size of the
* deques. The elements must be comparable with @c <.
*
* See std::lexographical_compare() for how the determination is made.
*/
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
inline bool operator<(const deque<_Tp, _Alloc>& __x, inline bool operator<(const deque<_Tp, _Alloc>& __x,
const deque<_Tp, _Alloc>& __y) { const deque<_Tp, _Alloc>& __y)
{
return lexicographical_compare(__x.begin(), __x.end(), return lexicographical_compare(__x.begin(), __x.end(),
__y.begin(), __y.end()); __y.begin(), __y.end());
} }
/// Based on operator==
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
inline bool operator!=(const deque<_Tp, _Alloc>& __x, inline bool operator!=(const deque<_Tp, _Alloc>& __x,
const deque<_Tp, _Alloc>& __y) { const deque<_Tp, _Alloc>& __y) {
return !(__x == __y); return !(__x == __y);
} }
/// Based on operator<
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
inline bool operator>(const deque<_Tp, _Alloc>& __x, inline bool operator>(const deque<_Tp, _Alloc>& __x,
const deque<_Tp, _Alloc>& __y) { const deque<_Tp, _Alloc>& __y) {
return __y < __x; return __y < __x;
} }
/// Based on operator<
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
inline bool operator<=(const deque<_Tp, _Alloc>& __x, inline bool operator<=(const deque<_Tp, _Alloc>& __x,
const deque<_Tp, _Alloc>& __y) { const deque<_Tp, _Alloc>& __y) {
return !(__y < __x); return !(__y < __x);
} }
/// Based on operator<
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
inline bool operator>=(const deque<_Tp, _Alloc>& __x, inline bool operator>=(const deque<_Tp, _Alloc>& __x,
const deque<_Tp, _Alloc>& __y) { const deque<_Tp, _Alloc>& __y) {
return !(__x < __y); return !(__x < __y);
} }
/// See std::deque::swap().
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
inline void swap(deque<_Tp,_Alloc>& __x, deque<_Tp,_Alloc>& __y) { inline void swap(deque<_Tp,_Alloc>& __x, deque<_Tp,_Alloc>& __y)
{
__x.swap(__y); __x.swap(__y);
} }
......
...@@ -63,775 +63,1332 @@ ...@@ -63,775 +63,1332 @@
#include <bits/concept_check.h> #include <bits/concept_check.h>
// Since this entire file is within namespace std, there's no reason to
// waste two spaces along the left column. Thus the leading indentation is
// slightly violated from here on.
namespace std namespace std
{ {
struct _List_node_base // Supporting structures are split into common and templated types; the
{ // latter publicly inherits from the former in an effort to reduce code
_List_node_base* _M_next; // duplication. This results in some "needless" static_cast'ing later on,
_List_node_base* _M_prev; // but it's all safe downcasting.
};
template<typename _Tp> /// @if maint Common part of a node in the %list. @endif
struct _List_node : public _List_node_base struct _List_node_base
{ {
_Tp _M_data; _List_node_base* _M_next; ///< Self-explanatory
}; _List_node_base* _M_prev; ///< Self-explanatory
};
/// @if maint An actual node in the %list. @endif
template<typename _Tp>
struct _List_node : public _List_node_base
{
_Tp _M_data; ///< User's data.
};
struct _List_iterator_base
{
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef bidirectional_iterator_tag iterator_category;
_List_node_base* _M_node; /**
* @if maint
* @brief Common part of a list::iterator.
*
* A simple type to walk a doubly-linked list. All operations here should
* be self-explanatory after taking any decent introductory data structures
* course.
* @endif
*/
struct _List_iterator_base
{
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef bidirectional_iterator_tag iterator_category;
_List_iterator_base(_List_node_base* __x) /// The only member points to the %list element.
: _M_node(__x) _List_node_base* _M_node;
{ }
_List_iterator_base() _List_iterator_base(_List_node_base* __x)
{ } : _M_node(__x)
{ }
void _List_iterator_base()
_M_incr() { }
/// Walk the %list forward.
void
_M_incr()
{ _M_node = _M_node->_M_next; } { _M_node = _M_node->_M_next; }
void /// Walk the %list backward.
_M_decr() void
_M_decr()
{ _M_node = _M_node->_M_prev; } { _M_node = _M_node->_M_prev; }
bool bool
operator==(const _List_iterator_base& __x) const operator==(const _List_iterator_base& __x) const
{ return _M_node == __x._M_node; } { return _M_node == __x._M_node; }
bool bool
operator!=(const _List_iterator_base& __x) const operator!=(const _List_iterator_base& __x) const
{ return _M_node != __x._M_node; } { return _M_node != __x._M_node; }
}; };
template<typename _Tp, typename _Ref, typename _Ptr> /**
struct _List_iterator : public _List_iterator_base * @brief A list::iterator.
{ *
typedef _List_iterator<_Tp,_Tp&,_Tp*> iterator; * In addition to being used externally, a list holds one of these internally,
typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator; * pointing to the sequence of data.
typedef _List_iterator<_Tp,_Ref,_Ptr> _Self; *
* @if maint
typedef _Tp value_type; * All the functions are op overloads.
typedef _Ptr pointer; * @endif
typedef _Ref reference; */
typedef _List_node<_Tp> _Node; template<typename _Tp, typename _Ref, typename _Ptr>
struct _List_iterator : public _List_iterator_base
_List_iterator(_Node* __x) {
: _List_iterator_base(__x) typedef _List_iterator<_Tp,_Tp&,_Tp*> iterator;
{ } typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
typedef _List_iterator<_Tp,_Ref,_Ptr> _Self;
_List_iterator()
{ }
_List_iterator(const iterator& __x)
: _List_iterator_base(__x._M_node)
{ }
reference
operator*() const
{ return ((_Node*) _M_node)->_M_data; }
pointer
operator->() const
{ return &(operator*()); }
_Self&
operator++()
{
this->_M_incr();
return *this;
}
_Self typedef _Tp value_type;
operator++(int) typedef _Ptr pointer;
{ typedef _Ref reference;
_Self __tmp = *this; typedef _List_node<_Tp> _Node;
this->_M_incr();
return __tmp;
}
_Self& _List_iterator(_Node* __x)
operator--() : _List_iterator_base(__x)
{ { }
this->_M_decr();
return *this;
}
_Self _List_iterator()
operator--(int) { }
{
_Self __tmp = *this;
this->_M_decr();
return __tmp;
}
};
_List_iterator(const iterator& __x)
: _List_iterator_base(__x._M_node)
{ }
// Base class that encapsulates details of allocators. Three cases: reference
// an ordinary standard-conforming allocator, a standard-conforming operator*() const
// allocator with no non-static data, and an SGI-style allocator. { return static_cast<_Node*>(_M_node)->_M_data; }
// This complexity is necessary only because we're worrying about backward // Must downcast from List_node_base to _List_node to get to _M_data.
// compatibility and because we want to avoid wasting storage on an
// allocator instance if it isn't necessary.
pointer
operator->() const
{ return &(operator*()); }
// Base for general standard-conforming allocators. _Self&
template<typename _Tp, typename _Allocator, bool _IsStatic> operator++()
class _List_alloc_base {
{ this->_M_incr();
public: return *this;
typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type }
allocator_type;
allocator_type _Self
get_allocator() const operator++(int)
{ return _Node_allocator; } {
_Self __tmp = *this;
this->_M_incr();
return __tmp;
}
_Self&
operator--()
{
this->_M_decr();
return *this;
}
_List_alloc_base(const allocator_type& __a) _Self
: _Node_allocator(__a) operator--(int)
{ } {
_Self __tmp = *this;
this->_M_decr();
return __tmp;
}
};
protected:
_List_node<_Tp>*
_M_get_node()
{ return _Node_allocator.allocate(1); }
void /// @if maint Primary default version. @endif
_M_put_node(_List_node<_Tp>* __p) /**
{ _Node_allocator.deallocate(__p, 1); } * @if maint
* See bits/stl_deque.h's _Deque_alloc_base for an explanation.
* @endif
*/
template<typename _Tp, typename _Allocator, bool _IsStatic>
class _List_alloc_base
{
public:
typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type
allocator_type;
allocator_type
get_allocator() const { return _M_node_allocator; }
_List_alloc_base(const allocator_type& __a)
: _M_node_allocator(__a)
{ }
protected:
_List_node<_Tp>*
_M_get_node()
{ return _M_node_allocator.allocate(1); }
void
_M_put_node(_List_node<_Tp>* __p)
{ _M_node_allocator.deallocate(__p, 1); }
// NOTA BENE
// The stored instance is not actually of "allocator_type"'s type. Instead
// we rebind the type to Allocator<List_node<Tp>>, which according to
// [20.1.5]/4 should probably be the same. List_node<Tp> is not the same
// size as Tp (it's two pointers larger), and specializations on Tp may go
// unused because List_node<Tp> is being bound instead.
//
// We put this to the test in get_allocator above; if the two types are
// actually different, there had better be a conversion between them.
//
// None of the predefined allocators shipped with the library (as of 3.1)
// use this instantiation anyhow; they're all instanceless.
typename _Alloc_traits<_List_node<_Tp>, _Allocator>::allocator_type
_M_node_allocator;
_List_node<_Tp>* _M_node;
};
/// @if maint Specialization for instanceless allocators. @endif
template<typename _Tp, typename _Allocator>
class _List_alloc_base<_Tp, _Allocator, true>
{
public:
typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type
allocator_type;
allocator_type
get_allocator() const { return allocator_type(); }
_List_alloc_base(const allocator_type&)
{ }
protected:
// See comment in primary template class about why this is safe for the
// standard predefined classes.
typedef typename _Alloc_traits<_List_node<_Tp>, _Allocator>::_Alloc_type
_Alloc_type;
_List_node<_Tp>*
_M_get_node()
{ return _Alloc_type::allocate(1); }
void
_M_put_node(_List_node<_Tp>* __p)
{ _Alloc_type::deallocate(__p, 1); }
_List_node<_Tp>* _M_node;
};
/**
* @if maint
* See bits/stl_deque.h's _Deque_base for an explanation.
* @endif
*/
template <typename _Tp, typename _Alloc>
class _List_base
: public _List_alloc_base<_Tp, _Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless>
{
public:
typedef _List_alloc_base<_Tp, _Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless>
_Base;
typedef typename _Base::allocator_type allocator_type;
_List_base(const allocator_type& __a)
: _Base(__a)
{
_M_node = _M_get_node();
_M_node->_M_next = _M_node;
_M_node->_M_prev = _M_node;
}
protected: // This is what actually destroys the list.
typename _Alloc_traits<_List_node<_Tp>, _Allocator>::allocator_type ~_List_base()
_Node_allocator; {
__clear();
_M_put_node(_M_node);
}
_List_node<_Tp>* _M_node; void
}; __clear();
};
// Specialization for instanceless allocators.
template<typename _Tp, typename _Allocator> /**
class _List_alloc_base<_Tp, _Allocator, true> * @brief A standard container with linear time access to elements, and
* fixed time insertion/deletion at any point in the sequence.
*
* @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> with the
* %exception of @c at and @c operator[].
*
* This is a @e doubly @e linked %list. Traversal up and down the %list
* requires linear time, but adding and removing elements (or @e nodes) is
* done in constant time, regardless of where the change takes place.
* Unlike std::vector and std::deque, random-access iterators are not
* provided, so subscripting ( @c [] ) access is not allowed. For algorithms
* which only need sequential access, this lack makes no difference.
*
* Also unlike the other standard containers, std::list provides specialized
* algorithms %unique to linked lists, such as splicing, sorting, and
* in-place reversal.
*
* @if maint
* A couple points on memory allocation for list<Tp>:
*
* First, we never actually allocate a Tp, we actally allocate List_node<Tp>'s
* and trust [20.1.5]/4 to DTRT. This is to ensure that after elements from
* %list<X,Alloc1> are spliced into %list<X,Alloc2>, destroying the memory of
* the second %list is a valid operation, i.e., Alloc1 giveth and Alloc2
* taketh away.
*
* Second, a %list conceptually represented as
* @code
* A <---> B <---> C <---> D
* @endcode
* is actually circular; a link exists between A and D. The %list class
* holds (as its only data member) a private list::iterator pointing to
* @e D, not to @e A! To get to the head of the %list, we start at the tail
* and move forward by one. When this member iterator's next/previous
* pointers refer to itself, the %list is %empty.
* @endif
*/
template<typename _Tp, typename _Alloc = allocator<_Tp> >
class list : protected _List_base<_Tp, _Alloc>
{
// concept requirements
__glibcpp_class_requires(_Tp, _SGIAssignableConcept)
typedef _List_base<_Tp, _Alloc> _Base;
public:
typedef _Tp value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef _List_iterator<_Tp,_Tp&,_Tp*> iterator;
typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
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;
protected:
// Note that pointers-to-_Node's can be ctor-converted to iterator types.
typedef _List_node<_Tp> _Node;
/** @if maint
* One data member plus two memory-handling functions. If the _Alloc
* type requires separate instances, then one of those will also be
* included, accumulated from the topmost parent.
* @endif
*/
using _Base::_M_node;
using _Base::_M_put_node;
using _Base::_M_get_node;
/**
* @if maint
* @param x An instance of user data.
*
* Allocates space for a new node and constructs a copy of @a x in it.
* @endif
*/
_Node*
_M_create_node(const value_type& __x)
{
_Node* __p = _M_get_node();
try {
_Construct(&__p->_M_data, __x);
}
catch(...)
{
_M_put_node(__p);
__throw_exception_again;
}
return __p;
}
/**
* @if maint
* Allocates space for a new node and default-constructs a new instance
* of @c value_type in it.
* @endif
*/
_Node*
_M_create_node()
{
_Node* __p = _M_get_node();
try {
_Construct(&__p->_M_data);
}
catch(...)
{ {
public: _M_put_node(__p);
typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type __throw_exception_again;
allocator_type; }
return __p;
}
public:
// [23.2.2.1] construct/copy/destroy
// (assign() and get_allocator() are also listed in this section)
/**
* @brief Default constructor creates no elements.
*/
explicit
list(const allocator_type& __a = allocator_type())
: _Base(__a) { }
/**
* @brief Create a %list with copies of an exemplar element.
* @param n The number of elements to initially create.
* @param value An element to copy.
*
* This constructor fills the %list with @a n copies of @a value.
*/
list(size_type __n, const value_type& __value,
const allocator_type& __a = allocator_type())
: _Base(__a)
{ this->insert(begin(), __n, __value); }
allocator_type /**
get_allocator() const * @brief Create a %list with default elements.
{ return allocator_type(); } * @param n The number of elements to initially create.
*
* This constructor fills the %list with @a n copies of a
* default-constructed element.
*/
explicit
list(size_type __n)
: _Base(allocator_type())
{ this->insert(begin(), __n, value_type()); }
_List_alloc_base(const allocator_type&) /**
{ } * @brief %List copy constructor.
* @param x A %list of identical element and allocator types.
*
* The newly-created %list uses a copy of the allocation object used
* by @a x.
*/
list(const list& __x)
: _Base(__x.get_allocator())
{ this->insert(begin(), __x.begin(), __x.end()); }
protected: /**
typedef typename _Alloc_traits<_List_node<_Tp>, _Allocator>::_Alloc_type * @brief Builds a %list from a range.
_Alloc_type; * @param first An input iterator.
* @param last An input iterator.
*
* Creats a %list consisting of copies of the elements from [first,last).
* This is linear in N (where N is distance(first,last)).
*
* @if maint
* We don't need any dispatching tricks here, because insert does all of
* that anyway.
* @endif
*/
template<typename _InputIterator>
list(_InputIterator __first, _InputIterator __last,
const allocator_type& __a = allocator_type())
: _Base(__a)
{ this->insert(begin(), __first, __last); }
_List_node<_Tp>* /**
_M_get_node() * The dtor only erases the elements, and note that if the elements
{ return _Alloc_type::allocate(1); } * themselves are pointers, the pointed-to memory is not touched in any
* way. Managing the pointer is the user's responsibilty.
*/
~list() { }
void /**
_M_put_node(_List_node<_Tp>* __p) * @brief %List assignment operator.
{ _Alloc_type::deallocate(__p, 1); } * @param x A %list of identical element and allocator types.
*
* All the elements of @a x are copied, but unlike the copy constructor, the
* allocator object is not copied.
*/
list&
operator=(const list& __x);
protected: /**
_List_node<_Tp>* _M_node; * @brief Assigns a given value to a %list.
}; * @param n Number of elements to be assigned.
* @param val Value to be assigned.
*
* This function fills a %list with @a n copies of the given value.
* Note that the assignment completely changes the %list and that the
* resulting %list's size is the same as the number of elements assigned.
* Old data may be lost.
*/
void
assign(size_type __n, const value_type& __val) { _M_fill_assign(__n, __val); }
template<typename _Tp, typename _Alloc> /**
class _List_base * @brief Assigns a range to a %list.
: public _List_alloc_base<_Tp, _Alloc, * @param first An input iterator.
_Alloc_traits<_Tp, _Alloc>::_S_instanceless> * @param last An input iterator.
*
* This function fills a %list with copies of the elements in the
* range [first,last).
*
* Note that the assignment completely changes the %list and that the
* resulting %list's size is the same as the number of elements assigned.
* Old data may be lost.
*/
template<typename _InputIterator>
void
assign(_InputIterator __first, _InputIterator __last)
{ {
public: // Check whether it's an integral type. If so, it's not an iterator.
typedef _List_alloc_base<_Tp, _Alloc, typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
_Alloc_traits<_Tp, _Alloc>::_S_instanceless> _M_assign_dispatch(__first, __last, _Integral());
_Base; }
typedef typename _Base::allocator_type allocator_type;
_List_base(const allocator_type& __a)
: _Base(__a)
{
_M_node = _M_get_node();
_M_node->_M_next = _M_node;
_M_node->_M_prev = _M_node;
}
~_List_base() /// Get a copy of the memory allocation object.
{ allocator_type
clear(); get_allocator() const { return _Base::get_allocator(); }
_M_put_node(_M_node);
} // iterators
/**
* Returns a read/write iterator that points to the first element in the
* %list. Iteration is done in ordinary element order.
*/
iterator
begin() { return static_cast<_Node*>(_M_node->_M_next); }
/**
* Returns a read-only (constant) iterator that points to the first element
* in the %list. Iteration is done in ordinary element order.
*/
const_iterator
begin() const { return static_cast<_Node*>(_M_node->_M_next); }
/**
* Returns a read/write iterator that points one past the last element in
* the %list. Iteration is done in ordinary element order.
*/
iterator
end() { return _M_node; }
void clear(); /**
}; * Returns a read-only (constant) iterator that points one past the last
* element in the %list. Iteration is done in ordinary element order.
*/
const_iterator
end() const { return _M_node; }
/** /**
* @ingroup Containers * Returns a read/write reverse iterator that points to the last element in
* @ingroup Sequences * the %list. Iteration is done in reverse element order.
*/
reverse_iterator
rbegin() { return reverse_iterator(end()); }
/**
* Returns a read-only (constant) reverse iterator that points to the last
* element in the %list. Iteration is done in reverse element order.
*/
const_reverse_iterator
rbegin() const { return const_reverse_iterator(end()); }
/**
* Returns a read/write reverse iterator that points to one before the
* first element in the %list. Iteration is done in reverse element
* order.
*/
reverse_iterator
rend() { return reverse_iterator(begin()); }
/**
* Returns a read-only (constant) reverse iterator that points to one
* before the first element in the %list. Iteration is done in reverse
* element order.
*/
const_reverse_iterator
rend() const
{ return const_reverse_iterator(begin()); }
// [23.2.2.2] capacity
/**
* Returns true if the %list is empty. (Thus begin() would equal end().)
*/
bool
empty() const { return _M_node->_M_next == _M_node; }
/** Returns the number of elements in the %list. */
size_type
size() const { return distance(begin(), end()); }
/** Returns the size() of the largest possible %list. */
size_type
max_size() const { return size_type(-1); }
/**
* @brief Resizes the %list to the specified number of elements.
* @param new_size Number of elements the %list should contain.
* @param x Data with which new elements should be populated.
* *
* Meets the requirements of a <a href="tables.html#65">container</a>, a * This function will %resize the %list to the specified number of
* <a href="tables.html#66">reversible container</a>, and a * elements. If the number is smaller than the %list's current size the
* <a href="tables.html#67">sequence</a>, including the * %list is truncated, otherwise the %list is extended and new elements
* <a href="tables.html#68">optional sequence requirements</a> with the * are populated with given data.
* %exception of @c at and @c operator[]. */
void
resize(size_type __new_size, const value_type& __x);
/**
* @brief Resizes the %list to the specified number of elements.
* @param new_size Number of elements the %list should contain.
* *
* @doctodo * This function will resize the %list to the specified number of
* elements. If the number is smaller than the %list's current size the
* %list is truncated, otherwise the %list is extended and new elements
* are default-constructed.
*/
void
resize(size_type __new_size) { this->resize(__new_size, value_type()); }
// element access
/**
* Returns a read/write reference to the data at the first element of the
* %list.
*/
reference
front() { return *begin(); }
/**
* Returns a read-only (constant) reference to the data at the first
* element of the %list.
*/
const_reference
front() const { return *begin(); }
/**
* Returns a read/write reference to the data at the last element of the
* %list.
*/
reference
back() { return *(--end()); }
/**
* Returns a read-only (constant) reference to the data at the last
* element of the %list.
*/
const_reference
back() const { return *(--end()); }
// [23.2.2.3] modifiers
/**
* @brief Add data to the front of the %list.
* @param x Data to be added.
* *
* This is a typical stack operation. The function creates an element at
* the front of the %list and assigns the given data to it. Due to the
* nature of a %list this operation can be done in constant time, and
* does not invalidate iterators and references.
*/ */
template<typename _Tp, typename _Alloc = allocator<_Tp> > void
class list : protected _List_base<_Tp, _Alloc> push_front(const value_type& __x) { this->insert(begin(), __x); }
{
// concept requirements
__glibcpp_class_requires(_Tp, _SGIAssignableConcept)
typedef _List_base<_Tp, _Alloc> _Base;
protected:
typedef void* _Void_pointer;
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 _List_node<_Tp> _Node;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef typename _Base::allocator_type allocator_type;
typedef _List_iterator<_Tp,_Tp&,_Tp*> iterator;
typedef _List_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
protected:
using _Base::_M_node;
using _Base::_M_put_node;
using _Base::_M_get_node;
protected:
_Node*
_M_create_node(const _Tp& __x)
{
_Node* __p = _M_get_node();
try {
_Construct(&__p->_M_data, __x);
}
catch(...)
{
_M_put_node(__p);
__throw_exception_again;
}
return __p;
}
_Node* #ifdef _GLIBCPP_DEPRECATED
_M_create_node() /**
{ * @brief Add data to the front of the %list.
_Node* __p = _M_get_node(); *
try { * This is a typical stack operation. The function creates a
_Construct(&__p->_M_data); * default-constructed element at the front of the %list. Due to the nature
} * of a %list this operation can be done in constant time. You should
catch(...) * consider using push_front(value_type()) instead.
{ *
_M_put_node(__p); * @note This was deprecated in 3.2 and will be removed in 3.3. You must
__throw_exception_again; * define @c _GLIBCPP_DEPRECATED to make this visible in 3.2; see
} * c++config.h.
return __p; */
} void
push_front() { this->insert(begin(), value_type()); }
#endif
public: /**
allocator_type * @brief Removes first element.
get_allocator() const *
{ return _Base::get_allocator(); } * This is a typical stack operation. It shrinks the %list by one.
* Due to the nature of a %list this operation can be done in constant
explicit * time, and only invalidates iterators/references to the element being
list(const allocator_type& __a = allocator_type()) * removed.
: _Base(__a) *
{ } * Note that no data is returned, and if the first element's data is
* needed, it should be retrieved before pop_front() is called.
iterator */
begin() void
{ return static_cast<_Node*>(_M_node->_M_next); } pop_front() { this->erase(begin()); }
const_iterator /**
begin() const * @brief Add data to the end of the %list.
{ return static_cast<_Node*>(_M_node->_M_next); } * @param x Data to be added.
*
iterator * This is a typical stack operation. The function creates an element at
end() * the end of the %list and assigns the given data to it. Due to the
{ return _M_node; } * nature of a %list this operation can be done in constant time, and
* does not invalidate iterators and references.
const_iterator */
end() const void
{ return _M_node; } push_back(const value_type& __x) { this->insert(end(), __x); }
reverse_iterator #ifdef _GLIBCPP_DEPRECATED
rbegin() /**
{ return reverse_iterator(end()); } * @brief Add data to the end of the %list.
*
const_reverse_iterator * This is a typical stack operation. The function creates a
rbegin() const * default-constructed element at the end of the %list. Due to the nature
{ return const_reverse_iterator(end()); } * of a %list this operation can be done in constant time. You should
* consider using push_back(value_type()) instead.
reverse_iterator *
rend() * @note This was deprecated in 3.2 and will be removed in 3.3. You must
{ return reverse_iterator(begin()); } * define @c _GLIBCPP_DEPRECATED to make this visible in 3.2; see
* c++config.h.
const_reverse_iterator */
rend() const void
{ return const_reverse_iterator(begin()); } push_back() { this->insert(end(), value_type()); }
#endif
bool
empty() const /**
{ return _M_node->_M_next == _M_node; } * @brief Removes last element.
*
size_type * This is a typical stack operation. It shrinks the %list by one.
size() const * Due to the nature of a %list this operation can be done in constant
{ return distance(begin(), end()); } * time, and only invalidates iterators/references to the element being
* removed.
size_type *
max_size() const * Note that no data is returned, and if the last element's data is
{ return size_type(-1); } * needed, it should be retrieved before pop_back() is called.
*/
reference void
front() pop_back()
{ return *begin(); } {
iterator __tmp = end();
const_reference this->erase(--__tmp);
front() const }
{ return *begin(); }
/**
reference * @brief Inserts given value into %list before specified iterator.
back() * @param position An iterator into the %list.
{ return *(--end()); } * @param x Data to be inserted.
* @return An iterator that points to the inserted data.
const_reference *
back() const * This function will insert a copy of the given value before the specified
{ return *(--end()); } * location.
* Due to the nature of a %list this operation can be done in constant
void * time, and does not invalidate iterators and references.
swap(list<_Tp, _Alloc>& __x) */
{ std::swap(_M_node, __x._M_node); } iterator
insert(iterator __position, const value_type& __x)
iterator {
insert(iterator __position, const _Tp& __x) _Node* __tmp = _M_create_node(__x);
{ __tmp->_M_next = __position._M_node;
_Node* __tmp = _M_create_node(__x); __tmp->_M_prev = __position._M_node->_M_prev;
__tmp->_M_next = __position._M_node; __position._M_node->_M_prev->_M_next = __tmp;
__tmp->_M_prev = __position._M_node->_M_prev; __position._M_node->_M_prev = __tmp;
__position._M_node->_M_prev->_M_next = __tmp; return __tmp;
__position._M_node->_M_prev = __tmp; }
return __tmp;
} #ifdef _GLIBCPP_DEPRECATED
/**
* @brief Inserts an element into the %list.
* @param position An iterator into the %list.
* @return An iterator that points to the inserted element.
*
* This function will insert a default-constructed element before the
* specified location. You should consider using
* insert(position,value_type()) instead.
* Due to the nature of a %list this operation can be done in constant
* time, and does not invalidate iterators and references.
*
* @note This was deprecated in 3.2 and will be removed in 3.3. You must
* define @c _GLIBCPP_DEPRECATED to make this visible in 3.2; see
* c++config.h.
*/
iterator
insert(iterator __position) { return insert(__position, value_type()); }
#endif
iterator /**
insert(iterator __position) * @brief Inserts a number of copies of given data into the %list.
{ return insert(__position, _Tp()); } * @param position An iterator into the %list.
* @param n Number of elements to be inserted.
* @param x Data to be inserted.
*
* This function will insert a specified number of copies of the given data
* before the location specified by @a position.
*
* Due to the nature of a %list this operation can be done in constant
* time, and does not invalidate iterators and references.
*/
void
insert(iterator __pos, size_type __n, const value_type& __x)
{ _M_fill_insert(__pos, __n, __x); }
/**
* @brief Inserts a range into the %list.
* @param pos An iterator into the %list.
* @param first An input iterator.
* @param last An input iterator.
*
* This function will insert copies of the data in the range [first,last)
* into the %list before the location specified by @a pos.
*
* Due to the nature of a %list this operation can be done in constant
* time, and does not invalidate iterators and references.
*/
template<typename _InputIterator>
void
insert(iterator __pos, _InputIterator __first, _InputIterator __last)
{
// Check whether it's an integral type. If so, it's not an iterator. // Check whether it's an integral type. If so, it's not an iterator.
template<typename _Integer> typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
void _M_insert_dispatch(__pos, __first, __last, _Integral());
_M_insert_dispatch(iterator __pos, _Integer __n, _Integer __x, __true_type) }
{ _M_fill_insert(__pos, (size_type) __n, (_Tp) __x); }
template<typename _InputIterator>
void
_M_insert_dispatch(iterator __pos,
_InputIterator __first, _InputIterator __last,
__false_type);
template<typename _InputIterator>
void
insert(iterator __pos, _InputIterator __first, _InputIterator __last)
{
typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
_M_insert_dispatch(__pos, __first, __last, _Integral());
}
void /**
insert(iterator __pos, size_type __n, const _Tp& __x) * @brief Remove element at given position.
{ _M_fill_insert(__pos, __n, __x); } * @param position Iterator pointing to element to be erased.
* @return An iterator pointing to the next element (or end()).
void *
_M_fill_insert(iterator __pos, size_type __n, const _Tp& __x); * This function will erase the element at the given position and thus
* shorten the %list by one.
void *
push_front(const _Tp& __x) * Due to the nature of a %list this operation can be done in constant
{ insert(begin(), __x); } * time, and only invalidates iterators/references to the element being
* removed.
void * The user is also cautioned that
push_front() * this function only erases the element, and that if the element is itself
{ insert(begin()); } * a pointer, the pointed-to memory is not touched in any way. Managing
* the pointer is the user's responsibilty.
void */
push_back(const _Tp& __x) iterator
{ insert(end(), __x); } erase(iterator __position)
{
void _List_node_base* __next_node = __position._M_node->_M_next;
push_back() _List_node_base* __prev_node = __position._M_node->_M_prev;
{ insert(end()); } _Node* __n = static_cast<_Node*>(__position._M_node);
__prev_node->_M_next = __next_node;
iterator __next_node->_M_prev = __prev_node;
erase(iterator __position) _Destroy(&__n->_M_data);
{ _M_put_node(__n);
_List_node_base* __next_node = __position._M_node->_M_next; return iterator(static_cast<_Node*>(__next_node));
_List_node_base* __prev_node = __position._M_node->_M_prev; }
_Node* __n = static_cast<_Node*>(__position._M_node);
__prev_node->_M_next = __next_node;
__next_node->_M_prev = __prev_node;
_Destroy(&__n->_M_data);
_M_put_node(__n);
return iterator(static_cast<_Node*>(__next_node));
}
iterator /**
erase(iterator __first, iterator __last); * @brief Remove a range of elements.
* @param first Iterator pointing to the first element to be erased.
void * @param last Iterator pointing to one past the last element to be erased.
clear() * @return An iterator pointing to the element pointed to by @a last
{ _Base::clear(); } * prior to erasing (or end()).
*
void * This function will erase the elements in the range [first,last) and
resize(size_type __new_size, const _Tp& __x); * shorten the %list accordingly.
*
void * Due to the nature of a %list this operation can be done in constant
resize(size_type __new_size) * time, and only invalidates iterators/references to the element being
{ this->resize(__new_size, _Tp()); } * removed.
* The user is also cautioned that
void * this function only erases the elements, and that if the elements
pop_front() * themselves are pointers, the pointed-to memory is not touched in any
{ erase(begin()); } * way. Managing the pointer is the user's responsibilty.
*/
void iterator
pop_back() erase(iterator __first, iterator __last);
{
iterator __tmp = end();
erase(--__tmp);
}
list(size_type __n, const _Tp& __value, /**
const allocator_type& __a = allocator_type()) * @brief Swaps data with another %list.
: _Base(__a) * @param x A %list of the same element and allocator types.
{ insert(begin(), __n, __value); } *
* This exchanges the elements between two lists in constant time.
explicit * (It is only swapping a single pointer, so it should be quite fast.)
list(size_type __n) * Note that the global std::swap() function is specialized such that
: _Base(allocator_type()) * std::swap(l1,l2) will feed to this function.
{ insert(begin(), __n, _Tp()); } */
void
// We don't need any dispatching tricks here, because insert does all of swap(list& __x) { std::swap(_M_node, __x._M_node); }
// that anyway.
template<typename _InputIterator>
list(_InputIterator __first, _InputIterator __last,
const allocator_type& __a = allocator_type())
: _Base(__a)
{ insert(begin(), __first, __last); }
list(const list<_Tp, _Alloc>& __x)
: _Base(__x.get_allocator())
{ insert(begin(), __x.begin(), __x.end()); }
~list()
{ }
list<_Tp, _Alloc>&
operator=(const list<_Tp, _Alloc>& __x);
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
assign(size_type __n, const _Tp& __val)
{ _M_fill_assign(__n, __val); }
void
_M_fill_assign(size_type __n, const _Tp& __val);
template<typename _InputIterator>
void
assign(_InputIterator __first, _InputIterator __last)
{
typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
_M_assign_dispatch(__first, __last, _Integral());
}
template<typename _Integer> /**
void * Erases all the elements. Note that this function only erases the
_M_assign_dispatch(_Integer __n, _Integer __val, __true_type) * elements, and that if the elements themselves are pointers, the
{ _M_fill_assign((size_type) __n, (_Tp) __val); } * pointed-to memory is not touched in any way. Managing the pointer is
* the user's responsibilty.
template<typename _InputIterator> */
void void
_M_assign_dispatch(_InputIterator __first, _InputIterator __last, clear() { _Base::__clear(); }
__false_type);
protected:
void
_M_transfer(iterator __position, iterator __first, iterator __last)
{
if (__position != __last) {
// Remove [first, last) from its old position.
__last._M_node->_M_prev->_M_next = __position._M_node;
__first._M_node->_M_prev->_M_next = __last._M_node;
__position._M_node->_M_prev->_M_next = __first._M_node;
// Splice [first, last) into its new position.
_List_node_base* __tmp = __position._M_node->_M_prev;
__position._M_node->_M_prev = __last._M_node->_M_prev;
__last._M_node->_M_prev = __first._M_node->_M_prev;
__first._M_node->_M_prev = __tmp;
}
}
public: // [23.2.2.4] list operations
void /**
splice(iterator __position, list& __x) * @doctodo
{ */
if (!__x.empty()) void
this->_M_transfer(__position, __x.begin(), __x.end()); splice(iterator __position, list& __x)
} {
if (!__x.empty())
this->_M_transfer(__position, __x.begin(), __x.end());
}
void /**
splice(iterator __position, list&, iterator __i) * @doctodo
{ */
iterator __j = __i; void
++__j; splice(iterator __position, list&, iterator __i)
if (__position == __i || __position == __j) return; {
this->_M_transfer(__position, __i, __j); iterator __j = __i;
} ++__j;
if (__position == __i || __position == __j) return;
this->_M_transfer(__position, __i, __j);
}
void /**
splice(iterator __position, list&, iterator __first, iterator __last) * @doctodo
{ */
if (__first != __last) void
this->_M_transfer(__position, __first, __last); splice(iterator __position, list&, iterator __first, iterator __last)
} {
if (__first != __last)
this->_M_transfer(__position, __first, __last);
}
/**
* @doctodo
*/
void
remove(const _Tp& __value);
void /**
remove(const _Tp& __value); * @doctodo
*/
template<typename _Predicate>
void
remove_if(_Predicate);
void /**
unique(); * @doctodo
*/
void
unique();
void /**
merge(list& __x); * @doctodo
*/
template<typename _BinaryPredicate>
void
unique(_BinaryPredicate);
void /**
reverse(); * @doctodo
*/
void
merge(list& __x);
void /**
sort(); * @doctodo
*/
template<typename _StrictWeakOrdering>
void
merge(list&, _StrictWeakOrdering);
template<typename _Predicate> /**
void * @doctodo
remove_if(_Predicate); */
void
reverse();
template<typename _BinaryPredicate> /**
void * @doctodo
unique(_BinaryPredicate); */
void
sort();
template<typename _StrictWeakOrdering> /**
void * @doctodo
merge(list&, _StrictWeakOrdering); */
template<typename _StrictWeakOrdering>
void
sort(_StrictWeakOrdering);
template<typename _StrictWeakOrdering> protected:
void // Internal assign functions follow.
sort(_StrictWeakOrdering);
};
template<typename _Tp, typename _Alloc> // called by the range assign to implement [23.1.1]/9
inline bool template<typename _Integer>
operator==(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y) void
_M_assign_dispatch(_Integer __n, _Integer __val, __true_type)
{ {
typedef typename list<_Tp,_Alloc>::const_iterator const_iterator; _M_fill_assign(static_cast<size_type>(__n),
const_iterator __end1 = __x.end(); static_cast<value_type>(__val));
const_iterator __end2 = __y.end();
const_iterator __i1 = __x.begin();
const_iterator __i2 = __y.begin();
while (__i1 != __end1 && __i2 != __end2 && *__i1 == *__i2) {
++__i1;
++__i2;
}
return __i1 == __end1 && __i2 == __end2;
} }
template<typename _Tp, typename _Alloc> // called by the range assign to implement [23.1.1]/9
inline bool template<typename _InputIter>
operator<(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y) void
_M_assign_dispatch(_InputIter __first, _InputIter __last, __false_type);
// Called by assign(n,t), and the range assign when it turns out to be the
// same thing.
void
_M_fill_assign(size_type __n, const value_type& __val);
// Internal insert functions follow.
// called by the range insert to implement [23.1.1]/9
template<typename _Integer>
void
_M_insert_dispatch(iterator __pos, _Integer __n, _Integer __x, __true_type)
{ {
return lexicographical_compare(__x.begin(), __x.end(), _M_fill_insert(__pos, static_cast<size_type>(__n),
__y.begin(), __y.end()); static_cast<value_type>(__x));
} }
template<typename _Tp, typename _Alloc> // called by the range insert to implement [23.1.1]/9
inline bool template<typename _InputIterator>
operator!=(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y) void
{ return !(__x == __y); } _M_insert_dispatch(iterator __pos,
_InputIterator __first, _InputIterator __last,
template<typename _Tp, typename _Alloc> __false_type);
inline bool
operator>(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y)
{ return __y < __x; }
template<typename _Tp, typename _Alloc> // Called by insert(p,n,x), and the range insert when it turns out to be
inline bool // the same thing.
operator<=(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y) void
{ return !(__y < __x); } _M_fill_insert(iterator __pos, size_type __n, const value_type& __x);
template<typename _Tp, typename _Alloc>
inline bool
operator>=(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y)
{ return !(__x < __y); }
template<typename _Tp, typename _Alloc> // Moves the elements from [first,last) before position.
inline void void
swap(list<_Tp, _Alloc>& __x, list<_Tp, _Alloc>& __y) _M_transfer(iterator __position, iterator __first, iterator __last)
{ __x.swap(__y); } {
if (__position != __last) {
// Remove [first, last) from its old position.
__last._M_node->_M_prev->_M_next = __position._M_node;
__first._M_node->_M_prev->_M_next = __last._M_node;
__position._M_node->_M_prev->_M_next = __first._M_node;
// Splice [first, last) into its new position.
_List_node_base* __tmp = __position._M_node->_M_prev;
__position._M_node->_M_prev = __last._M_node->_M_prev;
__last._M_node->_M_prev = __first._M_node->_M_prev;
__first._M_node->_M_prev = __tmp;
}
}
};
// move these to stl_list.tcc
template<typename _Tp, typename _Alloc> /**
void _List_base<_Tp,_Alloc>:: * @brief List equality comparison.
clear() * @param x A %list.
{ * @param y A %list of the same type as @a x.
_List_node<_Tp>* __cur = static_cast<_List_node<_Tp>*>(_M_node->_M_next); * @return True iff the size and elements of the lists are equal.
while (__cur != _M_node) { *
_List_node<_Tp>* __tmp = __cur; * This is an equivalence relation. It is linear in the size of the
__cur = static_cast<_List_node<_Tp>*>(__cur->_M_next); * lists. Lists are considered equivalent if their sizes are equal,
_Destroy(&__tmp->_M_data); * and if corresponding elements compare equal.
_M_put_node(__tmp); */
} template<typename _Tp, typename _Alloc>
_M_node->_M_next = _M_node; inline bool
_M_node->_M_prev = _M_node; operator==(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y)
{
typedef typename list<_Tp,_Alloc>::const_iterator const_iterator;
const_iterator __end1 = __x.end();
const_iterator __end2 = __y.end();
const_iterator __i1 = __x.begin();
const_iterator __i2 = __y.begin();
while (__i1 != __end1 && __i2 != __end2 && *__i1 == *__i2) {
++__i1;
++__i2;
} }
return __i1 == __end1 && __i2 == __end2;
}
template<typename _Tp, typename _Alloc> /**
template <typename _InputIter> * @brief List ordering relation.
void list<_Tp, _Alloc>:: * @param x A %list.
_M_insert_dispatch(iterator __position, _InputIter __first, _InputIter __last, * @param y A %list of the same type as @a x.
__false_type) * @return True iff @a x is lexographically less than @a y.
{ *
for ( ; __first != __last; ++__first) * This is a total ordering relation. It is linear in the size of the
insert(__position, *__first); * lists. The elements must be comparable with @c <.
*
} * See std::lexographical_compare() for how the determination is made.
*/
template<typename _Tp, typename _Alloc>
inline bool
operator<(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y)
{
return lexicographical_compare(__x.begin(), __x.end(),
__y.begin(), __y.end());
}
template<typename _Tp, typename _Alloc> /// Based on operator==
template<typename _Tp, typename _Alloc>
inline bool
operator!=(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y)
{ return !(__x == __y); }
/// Based on operator<
template<typename _Tp, typename _Alloc>
inline bool
operator>(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y)
{ return __y < __x; }
/// Based on operator<
template<typename _Tp, typename _Alloc>
inline bool
operator<=(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y)
{ return !(__y < __x); }
/// Based on operator<
template<typename _Tp, typename _Alloc>
inline bool
operator>=(const list<_Tp,_Alloc>& __x, const list<_Tp,_Alloc>& __y)
{ return !(__x < __y); }
/// See std::list::swap().
template<typename _Tp, typename _Alloc>
inline void
swap(list<_Tp, _Alloc>& __x, list<_Tp, _Alloc>& __y)
{ __x.swap(__y); }
template<typename _Tp, typename _Alloc>
void _List_base<_Tp,_Alloc>::
__clear()
{
_List_node<_Tp>* __cur = static_cast<_List_node<_Tp>*>(_M_node->_M_next);
while (__cur != _M_node) {
_List_node<_Tp>* __tmp = __cur;
__cur = static_cast<_List_node<_Tp>*>(__cur->_M_next);
_Destroy(&__tmp->_M_data);
_M_put_node(__tmp);
}
_M_node->_M_next = _M_node;
_M_node->_M_prev = _M_node;
}
template<typename _Tp, typename _Alloc>
template <typename _InputIter>
void list<_Tp, _Alloc>:: void list<_Tp, _Alloc>::
_M_fill_insert(iterator __position, size_type __n, const _Tp& __x) _M_insert_dispatch(iterator __position, _InputIter __first, _InputIter __last,
__false_type)
{ {
for ( ; __n > 0; --__n) for ( ; __first != __last; ++__first)
insert(__position, __x); insert(__position, *__first);
} }
template<typename _Tp, typename _Alloc> template<typename _Tp, typename _Alloc>
typename list<_Tp,_Alloc>::iterator list<_Tp, _Alloc>:: void list<_Tp, _Alloc>::
erase(iterator __first, iterator __last) _M_fill_insert(iterator __position, size_type __n, const _Tp& __x)
{ {
while (__first != __last) for ( ; __n > 0; --__n)
erase(__first++); insert(__position, __x);
return __last; }
template<typename _Tp, typename _Alloc>
typename list<_Tp,_Alloc>::iterator list<_Tp, _Alloc>::
erase(iterator __first, iterator __last)
{
while (__first != __last)
erase(__first++);
return __last;
}
template<typename _Tp, typename _Alloc>
void list<_Tp, _Alloc>::
resize(size_type __new_size, const _Tp& __x)
{
iterator __i = begin();
size_type __len = 0;
for ( ; __i != end() && __len < __new_size; ++__i, ++__len)
;
if (__len == __new_size)
erase(__i, end());
else // __i == end()
insert(end(), __new_size - __len, __x);
}
template<typename _Tp, typename _Alloc>
list<_Tp, _Alloc>& list<_Tp, _Alloc>::
operator=(const list<_Tp, _Alloc>& __x)
{
if (this != &__x) {
iterator __first1 = begin();
iterator __last1 = end();
const_iterator __first2 = __x.begin();
const_iterator __last2 = __x.end();
while (__first1 != __last1 && __first2 != __last2)
*__first1++ = *__first2++;
if (__first2 == __last2)
erase(__first1, __last1);
else
insert(__last1, __first2, __last2);
} }
return *this;
}
template<typename _Tp, typename _Alloc> template<typename _Tp, typename _Alloc>
void list<_Tp, _Alloc>::
_M_fill_assign(size_type __n, const _Tp& __val) {
iterator __i = begin();
for ( ; __i != end() && __n > 0; ++__i, --__n)
*__i = __val;
if (__n > 0)
insert(end(), __n, __val);
else
erase(__i, end());
}
template<typename _Tp, typename _Alloc>
template <typename _InputIter>
void list<_Tp, _Alloc>:: void list<_Tp, _Alloc>::
resize(size_type __new_size, const _Tp& __x) _M_assign_dispatch(_InputIter __first2, _InputIter __last2, __false_type)
{ {
iterator __i = begin(); iterator __first1 = begin();
size_type __len = 0; iterator __last1 = end();
for ( ; __i != end() && __len < __new_size; ++__i, ++__len) for ( ; __first1 != __last1 && __first2 != __last2; ++__first1, ++__first2)
; *__first1 = *__first2;
if (__len == __new_size) if (__first2 == __last2)
erase(__i, end()); erase(__first1, __last1);
else // __i == end() else
insert(end(), __new_size - __len, __x); insert(__last1, __first2, __last2);
} }
template<typename _Tp, typename _Alloc> template<typename _Tp, typename _Alloc>
list<_Tp, _Alloc>& list<_Tp, _Alloc>:: void list<_Tp, _Alloc>::
operator=(const list<_Tp, _Alloc>& __x) remove(const _Tp& __value)
{ {
if (this != &__x) { iterator __first = begin();
iterator __first1 = begin(); iterator __last = end();
iterator __last1 = end(); while (__first != __last) {
const_iterator __first2 = __x.begin(); iterator __next = __first;
const_iterator __last2 = __x.end(); ++__next;
while (__first1 != __last1 && __first2 != __last2) if (*__first == __value) erase(__first);
*__first1++ = *__first2++; __first = __next;
if (__first2 == __last2)
erase(__first1, __last1);
else
insert(__last1, __first2, __last2);
}
return *this;
} }
}
template<typename _Tp, typename _Alloc> template<typename _Tp, typename _Alloc>
void list<_Tp, _Alloc>:: void list<_Tp, _Alloc>::
_M_fill_assign(size_type __n, const _Tp& __val) { unique()
iterator __i = begin(); {
for ( ; __i != end() && __n > 0; ++__i, --__n) iterator __first = begin();
*__i = __val; iterator __last = end();
if (__n > 0) if (__first == __last) return;
insert(end(), __n, __val); iterator __next = __first;
while (++__next != __last) {
if (*__first == *__next)
erase(__next);
else else
erase(__i, end()); __first = __next;
__next = __first;
} }
}
template<typename _Tp, typename _Alloc> template<typename _Tp, typename _Alloc>
template <typename _InputIter> void list<_Tp, _Alloc>::
void list<_Tp, _Alloc>:: merge(list<_Tp, _Alloc>& __x)
_M_assign_dispatch(_InputIter __first2, _InputIter __last2, __false_type) {
{ iterator __first1 = begin();
iterator __first1 = begin(); iterator __last1 = end();
iterator __last1 = end(); iterator __first2 = __x.begin();
for ( ; __first1 != __last1 && __first2 != __last2; ++__first1, ++__first2) iterator __last2 = __x.end();
*__first1 = *__first2; while (__first1 != __last1 && __first2 != __last2)
if (__first2 == __last2) if (*__first2 < *__first1) {
erase(__first1, __last1); iterator __next = __first2;
else _M_transfer(__first1, __first2, ++__next);
insert(__last1, __first2, __last2); __first2 = __next;
} }
else
++__first1;
if (__first2 != __last2) _M_transfer(__last1, __first2, __last2);
}
inline void
__List_base_reverse(_List_node_base* __p)
{
_List_node_base* __tmp = __p;
do {
std::swap(__tmp->_M_next, __tmp->_M_prev);
__tmp = __tmp->_M_prev; // Old next node is now prev.
} while (__tmp != __p);
}
template<typename _Tp, typename _Alloc>
inline void list<_Tp, _Alloc>::
reverse()
{ __List_base_reverse(this->_M_node); }
template<typename _Tp, typename _Alloc>
void list<_Tp, _Alloc>::
sort()
{
// Do nothing if the list has length 0 or 1.
if (_M_node->_M_next != _M_node && _M_node->_M_next->_M_next != _M_node) {
list<_Tp, _Alloc> __carry;
list<_Tp, _Alloc> __counter[64];
int __fill = 0;
while (!empty()) {
__carry.splice(__carry.begin(), *this, begin());
int __i = 0;
while(__i < __fill && !__counter[__i].empty()) {
__counter[__i].merge(__carry);
__carry.swap(__counter[__i++]);
}
__carry.swap(__counter[__i]);
if (__i == __fill) ++__fill;
}
for (int __i = 1; __i < __fill; ++__i)
__counter[__i].merge(__counter[__i-1]);
swap(__counter[__fill-1]);
}
}
template<typename _Tp, typename _Alloc> template<typename _Tp, typename _Alloc>
template <typename _Predicate>
void list<_Tp, _Alloc>:: void list<_Tp, _Alloc>::
remove(const _Tp& __value) remove_if(_Predicate __pred)
{ {
iterator __first = begin(); iterator __first = begin();
iterator __last = end(); iterator __last = end();
while (__first != __last) { while (__first != __last) {
iterator __next = __first; iterator __next = __first;
++__next; ++__next;
if (*__first == __value) erase(__first); if (__pred(*__first)) erase(__first);
__first = __next; __first = __next;
} }
} }
template<typename _Tp, typename _Alloc> template<typename _Tp, typename _Alloc>
template <typename _BinaryPredicate>
void list<_Tp, _Alloc>:: void list<_Tp, _Alloc>::
unique() unique(_BinaryPredicate __binary_pred)
{ {
iterator __first = begin(); iterator __first = begin();
iterator __last = end(); iterator __last = end();
if (__first == __last) return; if (__first == __last) return;
iterator __next = __first; iterator __next = __first;
while (++__next != __last) { while (++__next != __last) {
if (*__first == *__next) if (__binary_pred(*__first, *__next))
erase(__next); erase(__next);
else else
__first = __next; __first = __next;
...@@ -839,16 +1396,17 @@ namespace std ...@@ -839,16 +1396,17 @@ namespace std
} }
} }
template<typename _Tp, typename _Alloc> template<typename _Tp, typename _Alloc>
template <typename _StrictWeakOrdering>
void list<_Tp, _Alloc>:: void list<_Tp, _Alloc>::
merge(list<_Tp, _Alloc>& __x) merge(list<_Tp, _Alloc>& __x, _StrictWeakOrdering __comp)
{ {
iterator __first1 = begin(); iterator __first1 = begin();
iterator __last1 = end(); iterator __last1 = end();
iterator __first2 = __x.begin(); iterator __first2 = __x.begin();
iterator __last2 = __x.end(); iterator __last2 = __x.end();
while (__first1 != __last1 && __first2 != __last2) while (__first1 != __last1 && __first2 != __last2)
if (*__first2 < *__first1) { if (__comp(*__first2, *__first1)) {
iterator __next = __first2; iterator __next = __first2;
_M_transfer(__first1, __first2, ++__next); _M_transfer(__first1, __first2, ++__next);
__first2 = __next; __first2 = __next;
...@@ -858,132 +1416,34 @@ namespace std ...@@ -858,132 +1416,34 @@ namespace std
if (__first2 != __last2) _M_transfer(__last1, __first2, __last2); if (__first2 != __last2) _M_transfer(__last1, __first2, __last2);
} }
inline void template<typename _Tp, typename _Alloc>
__List_base_reverse(_List_node_base* __p) template <typename _StrictWeakOrdering>
void list<_Tp, _Alloc>::
sort(_StrictWeakOrdering __comp)
{ {
_List_node_base* __tmp = __p; // Do nothing if the list has length 0 or 1.
do { if (_M_node->_M_next != _M_node && _M_node->_M_next->_M_next != _M_node) {
std::swap(__tmp->_M_next, __tmp->_M_prev); list<_Tp, _Alloc> __carry;
__tmp = __tmp->_M_prev; // Old next node is now prev. list<_Tp, _Alloc> __counter[64];
} while (__tmp != __p); int __fill = 0;
} while (!empty()) {
__carry.splice(__carry.begin(), *this, begin());
template<typename _Tp, typename _Alloc> int __i = 0;
inline void list<_Tp, _Alloc>:: while(__i < __fill && !__counter[__i].empty()) {
reverse() __counter[__i].merge(__carry, __comp);
{ __List_base_reverse(this->_M_node); } __carry.swap(__counter[__i++]);
template<typename _Tp, typename _Alloc>
void list<_Tp, _Alloc>::
sort()
{
// Do nothing if the list has length 0 or 1.
if (_M_node->_M_next != _M_node && _M_node->_M_next->_M_next != _M_node) {
list<_Tp, _Alloc> __carry;
list<_Tp, _Alloc> __counter[64];
int __fill = 0;
while (!empty()) {
__carry.splice(__carry.begin(), *this, begin());
int __i = 0;
while(__i < __fill && !__counter[__i].empty()) {
__counter[__i].merge(__carry);
__carry.swap(__counter[__i++]);
}
__carry.swap(__counter[__i]);
if (__i == __fill) ++__fill;
}
for (int __i = 1; __i < __fill; ++__i)
__counter[__i].merge(__counter[__i-1]);
swap(__counter[__fill-1]);
}
}
template<typename _Tp, typename _Alloc>
template <typename _Predicate>
void list<_Tp, _Alloc>::
remove_if(_Predicate __pred)
{
iterator __first = begin();
iterator __last = end();
while (__first != __last) {
iterator __next = __first;
++__next;
if (__pred(*__first)) erase(__first);
__first = __next;
}
}
template<typename _Tp, typename _Alloc>
template <typename _BinaryPredicate>
void list<_Tp, _Alloc>::
unique(_BinaryPredicate __binary_pred)
{
iterator __first = begin();
iterator __last = end();
if (__first == __last) return;
iterator __next = __first;
while (++__next != __last) {
if (__binary_pred(*__first, *__next))
erase(__next);
else
__first = __next;
__next = __first;
} }
__carry.swap(__counter[__i]);
if (__i == __fill) ++__fill;
} }
template<typename _Tp, typename _Alloc> for (int __i = 1; __i < __fill; ++__i)
template <typename _StrictWeakOrdering> __counter[__i].merge(__counter[__i-1], __comp);
void list<_Tp, _Alloc>:: swap(__counter[__fill-1]);
merge(list<_Tp, _Alloc>& __x, _StrictWeakOrdering __comp)
{
iterator __first1 = begin();
iterator __last1 = end();
iterator __first2 = __x.begin();
iterator __last2 = __x.end();
while (__first1 != __last1 && __first2 != __last2)
if (__comp(*__first2, *__first1)) {
iterator __next = __first2;
_M_transfer(__first1, __first2, ++__next);
__first2 = __next;
}
else
++__first1;
if (__first2 != __last2) _M_transfer(__last1, __first2, __last2);
}
template<typename _Tp, typename _Alloc>
template <typename _StrictWeakOrdering>
void list<_Tp, _Alloc>::
sort(_StrictWeakOrdering __comp)
{
// Do nothing if the list has length 0 or 1.
if (_M_node->_M_next != _M_node && _M_node->_M_next->_M_next != _M_node) {
list<_Tp, _Alloc> __carry;
list<_Tp, _Alloc> __counter[64];
int __fill = 0;
while (!empty()) {
__carry.splice(__carry.begin(), *this, begin());
int __i = 0;
while(__i < __fill && !__counter[__i].empty()) {
__counter[__i].merge(__carry, __comp);
__carry.swap(__counter[__i++]);
}
__carry.swap(__counter[__i]);
if (__i == __fill) ++__fill;
}
for (int __i = 1; __i < __fill; ++__i)
__counter[__i].merge(__counter[__i-1], __comp);
swap(__counter[__fill-1]);
}
} }
}
} // namespace std } // namespace std
#endif /* __GLIBCPP_INTERNAL_LIST_H */ #endif /* __GLIBCPP_INTERNAL_LIST_H */
// vi:set ts=2 sw=2:
// Local Variables:
// mode:C++
// End:
...@@ -78,7 +78,7 @@ namespace std ...@@ -78,7 +78,7 @@ namespace std
* @endif * @endif
*/ */
template <class _Tp, class _Allocator, bool _IsStatic> template <class _Tp, class _Allocator, bool _IsStatic>
class _Vector_alloc_base class _Vector_alloc_base
{ {
public: public:
typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type
...@@ -93,9 +93,9 @@ public: ...@@ -93,9 +93,9 @@ public:
protected: protected:
allocator_type _M_data_allocator; allocator_type _M_data_allocator;
_Tp* _M_start; _Tp* _M_start;
_Tp* _M_finish; _Tp* _M_finish;
_Tp* _M_end_of_storage; _Tp* _M_end_of_storage;
_Tp* _Tp*
_M_allocate(size_t __n) { return _M_data_allocator.allocate(__n); } _M_allocate(size_t __n) { return _M_data_allocator.allocate(__n); }
...@@ -107,7 +107,7 @@ protected: ...@@ -107,7 +107,7 @@ protected:
/// @if maint Specialization for instanceless allocators. @endif /// @if maint Specialization for instanceless allocators. @endif
template <class _Tp, class _Allocator> template <class _Tp, class _Allocator>
class _Vector_alloc_base<_Tp, _Allocator, true> class _Vector_alloc_base<_Tp, _Allocator, true>
{ {
public: public:
typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type
...@@ -141,10 +141,11 @@ protected: ...@@ -141,10 +141,11 @@ protected:
* @endif * @endif
*/ */
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
struct _Vector_base struct _Vector_base
: public _Vector_alloc_base<_Tp, _Alloc, : public _Vector_alloc_base<_Tp, _Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless> _Alloc_traits<_Tp, _Alloc>::_S_instanceless>
{ {
public:
typedef _Vector_alloc_base<_Tp, _Alloc, typedef _Vector_alloc_base<_Tp, _Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless> _Alloc_traits<_Tp, _Alloc>::_S_instanceless>
_Base; _Base;
...@@ -183,7 +184,7 @@ struct _Vector_base ...@@ -183,7 +184,7 @@ struct _Vector_base
* Subscripting ( @c [] ) access is also provided as with C-style arrays. * Subscripting ( @c [] ) access is also provided as with C-style arrays.
*/ */
template <class _Tp, class _Alloc = allocator<_Tp> > template <class _Tp, class _Alloc = allocator<_Tp> >
class vector : protected _Vector_base<_Tp, _Alloc> class vector : protected _Vector_base<_Tp, _Alloc>
{ {
// concept requirements // concept requirements
__glibcpp_class_requires(_Tp, _SGIAssignableConcept) __glibcpp_class_requires(_Tp, _SGIAssignableConcept)
...@@ -220,12 +221,6 @@ protected: ...@@ -220,12 +221,6 @@ protected:
using _Base::_M_finish; using _Base::_M_finish;
using _Base::_M_end_of_storage; using _Base::_M_end_of_storage;
protected:
void _M_insert_aux(iterator __position, const _Tp& __x);
#ifdef _GLIBCPP_DEPRECATED
void _M_insert_aux(iterator __position);
#endif
public: public:
// [23.2.4.1] construct/copy/destroy // [23.2.4.1] construct/copy/destroy
// (assign() and get_allocator() are also listed in this section) // (assign() and get_allocator() are also listed in this section)
...@@ -243,7 +238,7 @@ public: ...@@ -243,7 +238,7 @@ public:
* *
* This constructor fills the %vector with @a n copies of @a value. * This constructor fills the %vector with @a n copies of @a value.
*/ */
vector(size_type __n, const _Tp& __value, vector(size_type __n, const value_type& __value,
const allocator_type& __a = allocator_type()) const allocator_type& __a = allocator_type())
: _Base(__n, __a) : _Base(__n, __a)
{ _M_finish = uninitialized_fill_n(_M_start, __n, __value); } { _M_finish = uninitialized_fill_n(_M_start, __n, __value); }
...@@ -268,7 +263,7 @@ public: ...@@ -268,7 +263,7 @@ public:
* by @a x. All the elements of @a x are copied, but any extra memory in * by @a x. All the elements of @a x are copied, but any extra memory in
* @a x (for fast expansion) will not be copied. * @a x (for fast expansion) will not be copied.
*/ */
vector(const vector<_Tp, _Alloc>& __x) vector(const vector& __x)
: _Base(__x.size(), __x.get_allocator()) : _Base(__x.size(), __x.get_allocator())
{ _M_finish = uninitialized_copy(__x.begin(), __x.end(), _M_start); } { _M_finish = uninitialized_copy(__x.begin(), __x.end(), _M_start); }
...@@ -288,37 +283,15 @@ public: ...@@ -288,37 +283,15 @@ public:
template <class _InputIterator> template <class _InputIterator>
vector(_InputIterator __first, _InputIterator __last, vector(_InputIterator __first, _InputIterator __last,
const allocator_type& __a = allocator_type()) const allocator_type& __a = allocator_type())
: _Base(__a) : _Base(__a)
{ {
// Check whether it's an integral type. If so, it's not an iterator. // Check whether it's an integral type. If so, it's not an iterator.
typedef typename _Is_integer<_InputIterator>::_Integral _Integral; typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
_M_initialize_aux(__first, __last, _Integral()); _M_initialize_dispatch(__first, __last, _Integral());
} }
protected:
template<class _Integer>
void
_M_initialize_aux(_Integer __n, _Integer __value, __true_type)
{
_M_start = _M_allocate(__n);
_M_end_of_storage = _M_start + __n;
_M_finish = uninitialized_fill_n(_M_start, __n, __value);
}
template<class _InputIterator>
void
_M_initialize_aux(_InputIterator __first,_InputIterator __last,__false_type)
{
typedef typename iterator_traits<_InputIterator>::iterator_category
_IterCategory;
_M_range_initialize(__first, __last, _IterCategory());
}
public:
/** /**
* Creats a %vector consisting of copies of the elements from [first,last). * The dtor only erases the elements, and note that if the elements
*
* The dtor only erases the elements, and that if the elements
* themselves are pointers, the pointed-to memory is not touched in any * themselves are pointers, the pointed-to memory is not touched in any
* way. Managing the pointer is the user's responsibilty. * way. Managing the pointer is the user's responsibilty.
*/ */
...@@ -332,8 +305,8 @@ public: ...@@ -332,8 +305,8 @@ public:
* fast expansion) will not be copied. Unlike the copy constructor, the * fast expansion) will not be copied. Unlike the copy constructor, the
* allocator object is not copied. * allocator object is not copied.
*/ */
vector<_Tp, _Alloc>& vector&
operator=(const vector<_Tp, _Alloc>& __x); operator=(const vector& __x);
/** /**
* @brief Assigns a given value to a %vector. * @brief Assigns a given value to a %vector.
...@@ -346,13 +319,8 @@ public: ...@@ -346,13 +319,8 @@ public:
* Old data may be lost. * Old data may be lost.
*/ */
void void
assign(size_type __n, const _Tp& __val) { _M_fill_assign(__n, __val); } assign(size_type __n, const value_type& __val) { _M_fill_assign(__n, __val); }
protected:
void
_M_fill_assign(size_type __n, const _Tp& __val);
public:
/** /**
* @brief Assigns a range to a %vector. * @brief Assigns a range to a %vector.
* @param first An input iterator. * @param first An input iterator.
...@@ -369,36 +337,11 @@ public: ...@@ -369,36 +337,11 @@ public:
void void
assign(_InputIterator __first, _InputIterator __last) assign(_InputIterator __first, _InputIterator __last)
{ {
// Check whether it's an integral type. If so, it's not an iterator.
typedef typename _Is_integer<_InputIterator>::_Integral _Integral; typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
_M_assign_dispatch(__first, __last, _Integral()); _M_assign_dispatch(__first, __last, _Integral());
} }
protected:
template<class _Integer>
void
_M_assign_dispatch(_Integer __n, _Integer __val, __true_type)
{ _M_fill_assign((size_type) __n, (_Tp) __val); }
template<class _InputIter>
void
_M_assign_dispatch(_InputIter __first, _InputIter __last, __false_type)
{
typedef typename iterator_traits<_InputIter>::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);
public:
/// Get a copy of the memory allocation object. /// Get a copy of the memory allocation object.
allocator_type allocator_type
get_allocator() const { return _Base::get_allocator(); } get_allocator() const { return _Base::get_allocator(); }
...@@ -469,7 +412,7 @@ public: ...@@ -469,7 +412,7 @@ public:
/** Returns the size() of the largest possible %vector. */ /** Returns the size() of the largest possible %vector. */
size_type size_type
max_size() const { return size_type(-1) / sizeof(_Tp); } max_size() const { return size_type(-1) / sizeof(value_type); }
/** /**
* @brief Resizes the %vector to the specified number of elements. * @brief Resizes the %vector to the specified number of elements.
...@@ -482,7 +425,7 @@ public: ...@@ -482,7 +425,7 @@ public:
* are populated with given data. * are populated with given data.
*/ */
void void
resize(size_type __new_size, const _Tp& __x) resize(size_type __new_size, const value_type& __x)
{ {
if (__new_size < size()) if (__new_size < size())
erase(begin() + __new_size, end()); erase(begin() + __new_size, end());
...@@ -500,7 +443,7 @@ public: ...@@ -500,7 +443,7 @@ public:
* are default-constructed. * are default-constructed.
*/ */
void void
resize(size_type __new_size) { resize(__new_size, _Tp()); } resize(size_type __new_size) { resize(__new_size, value_type()); }
/** /**
* Returns the total number of elements that the %vector can hold before * Returns the total number of elements that the %vector can hold before
...@@ -534,7 +477,8 @@ public: ...@@ -534,7 +477,8 @@ public:
void void
reserve(size_type __n) // FIXME should be out of class reserve(size_type __n) // FIXME should be out of class
{ {
if (capacity() < __n) { if (capacity() < __n)
{
const size_type __old_size = size(); const size_type __old_size = size();
pointer __tmp = _M_allocate_and_copy(__n, _M_start, _M_finish); pointer __tmp = _M_allocate_and_copy(__n, _M_start, _M_finish);
_Destroy(_M_start, _M_finish); _Destroy(_M_start, _M_finish);
...@@ -557,6 +501,7 @@ public: ...@@ -557,6 +501,7 @@ public:
*/ */
reference reference
operator[](size_type __n) { return *(begin() + __n); } operator[](size_type __n) { return *(begin() + __n); }
// XXX do we need to convert to normal_iterator first?
/** /**
* @brief Subscript access to the data contained in the %vector. * @brief Subscript access to the data contained in the %vector.
...@@ -612,6 +557,7 @@ public: ...@@ -612,6 +557,7 @@ public:
*/ */
reference reference
front() { return *begin(); } front() { return *begin(); }
// XXX do we need to convert to normal_iterator first?
/** /**
* Returns a read-only (constant) reference to the data at the first * Returns a read-only (constant) reference to the data at the first
...@@ -645,7 +591,7 @@ public: ...@@ -645,7 +591,7 @@ public:
* time if the %vector has preallocated space available. * time if the %vector has preallocated space available.
*/ */
void void
push_back(const _Tp& __x) push_back(const value_type& __x)
{ {
if (_M_finish != _M_end_of_storage) { if (_M_finish != _M_end_of_storage) {
_Construct(_M_finish, __x); _Construct(_M_finish, __x);
...@@ -682,15 +628,16 @@ public: ...@@ -682,15 +628,16 @@ public:
* it is frequently used the user should consider using std::list. * it is frequently used the user should consider using std::list.
*/ */
iterator iterator
insert(iterator __position, const _Tp& __x) insert(iterator __position, const value_type& __x)
{ {
size_type __n = __position - begin(); size_type __n = __position - begin();
if (_M_finish != _M_end_of_storage && __position == end()) { if (_M_finish != _M_end_of_storage && __position == end())
{
_Construct(_M_finish, __x); _Construct(_M_finish, __x);
++_M_finish; ++_M_finish;
} }
else else
_M_insert_aux(iterator(__position), __x); _M_insert_aux(__position, __x);
return begin() + __n; return begin() + __n;
} }
...@@ -701,8 +648,8 @@ public: ...@@ -701,8 +648,8 @@ public:
* @return An iterator that points to the inserted element. * @return An iterator that points to the inserted element.
* *
* This function will insert a default-constructed element before the * This function will insert a default-constructed element before the
* specified location. You should consider using insert(position,Tp()) * specified location. You should consider using
* instead. * insert(position,value_type()) instead.
* Note that this kind of operation could be expensive for a vector and if * Note that this kind of operation could be expensive for a vector and if
* it is frequently used the user should consider using std::list. * it is frequently used the user should consider using std::list.
* *
...@@ -712,16 +659,7 @@ public: ...@@ -712,16 +659,7 @@ public:
*/ */
iterator iterator
insert(iterator __position) insert(iterator __position)
{ { return insert(__position, value_type()); }
size_type __n = __position - begin();
if (_M_finish != _M_end_of_storage && __position == end()) {
_Construct(_M_finish);
++_M_finish;
}
else
_M_insert_aux(iterator(__position));
return begin() + __n;
}
#endif #endif
/** /**
...@@ -737,14 +675,9 @@ public: ...@@ -737,14 +675,9 @@ public:
* it is frequently used the user should consider using std::list. * it is frequently used the user should consider using std::list.
*/ */
void void
insert (iterator __pos, size_type __n, const _Tp& __x) insert (iterator __pos, size_type __n, const value_type& __x)
{ _M_fill_insert(__pos, __n, __x); } { _M_fill_insert(__pos, __n, __x); }
protected:
void
_M_fill_insert (iterator __pos, size_type __n, const _Tp& __x);
public:
/** /**
* @brief Inserts a range into the %vector. * @brief Inserts a range into the %vector.
* @param pos An iterator into the %vector. * @param pos An iterator into the %vector.
...@@ -766,27 +699,6 @@ public: ...@@ -766,27 +699,6 @@ public:
_M_insert_dispatch(__pos, __first, __last, _Integral()); _M_insert_dispatch(__pos, __first, __last, _Integral());
} }
protected:
template<class _Integer>
void
_M_insert_dispatch(iterator __pos, _Integer __n, _Integer __val,
__true_type)
{
_M_fill_insert(__pos, static_cast<size_type>(__n),
static_cast<_Tp>(__val));
}
template<class _InputIterator>
void
_M_insert_dispatch(iterator __pos, _InputIterator __first,
_InputIterator __last, __false_type)
{
typedef typename iterator_traits<_InputIterator>::iterator_category
_IterCategory;
_M_range_insert(__pos, __first, __last, _IterCategory());
}
public:
/** /**
* @brief Remove element at given position. * @brief Remove element at given position.
* @param position Iterator pointing to element to be erased. * @param position Iterator pointing to element to be erased.
...@@ -846,7 +758,7 @@ public: ...@@ -846,7 +758,7 @@ public:
* std::swap(v1,v2) will feed to this function. * std::swap(v1,v2) will feed to this function.
*/ */
void void
swap(vector<_Tp, _Alloc>& __x) swap(vector& __x)
{ {
std::swap(_M_start, __x._M_start); std::swap(_M_start, __x._M_start);
std::swap(_M_finish, __x._M_finish); std::swap(_M_finish, __x._M_finish);
...@@ -863,10 +775,16 @@ public: ...@@ -863,10 +775,16 @@ public:
clear() { erase(begin(), end()); } clear() { erase(begin(), end()); }
protected: protected:
/**
* @if maint
* Memory expansion handler. Uses the member allocation function to
* obtain @a n bytes of memory, and then copies [first,last) into it.
* @endif
*/
template <class _ForwardIterator> template <class _ForwardIterator>
pointer pointer
_M_allocate_and_copy(size_type __n, _ForwardIterator __first, _M_allocate_and_copy(size_type __n,
_ForwardIterator __last) _ForwardIterator __first, _ForwardIterator __last)
{ {
pointer __result = _M_allocate(__n); pointer __result = _M_allocate(__n);
try try
...@@ -881,6 +799,30 @@ protected: ...@@ -881,6 +799,30 @@ protected:
} }
} }
// Internal constructor functions follow.
// called by the range constructor to implement [23.1.1]/9
template<class _Integer>
void
_M_initialize_dispatch(_Integer __n, _Integer __value, __true_type)
{
_M_start = _M_allocate(__n);
_M_end_of_storage = _M_start + __n;
_M_finish = uninitialized_fill_n(_M_start, __n, __value);
}
// called by the range constructor to implement [23.1.1]/9
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());
}
// called by the second initialize_dispatch above
template <class _InputIterator> template <class _InputIterator>
void void
_M_range_initialize(_InputIterator __first, _M_range_initialize(_InputIterator __first,
...@@ -890,7 +832,7 @@ protected: ...@@ -890,7 +832,7 @@ protected:
push_back(*__first); push_back(*__first);
} }
// This function is only called by the constructor. // called by the second initialize_dispatch above
template <class _ForwardIterator> template <class _ForwardIterator>
void _M_range_initialize(_ForwardIterator __first, void _M_range_initialize(_ForwardIterator __first,
_ForwardIterator __last, forward_iterator_tag) _ForwardIterator __last, forward_iterator_tag)
...@@ -901,15 +843,97 @@ protected: ...@@ -901,15 +843,97 @@ protected:
_M_finish = uninitialized_copy(__first, __last, _M_start); _M_finish = uninitialized_copy(__first, __last, _M_start);
} }
// Internal assign functions follow. The *_aux functions do the actual
// assignment work for the range versions.
// called by the range assign to implement [23.1.1]/9
template<class _Integer>
void
_M_assign_dispatch(_Integer __n, _Integer __val, __true_type)
{
_M_fill_assign(static_cast<size_type>(__n),
static_cast<value_type>(__val));
}
// called by the range assign to implement [23.1.1]/9
template<class _InputIter>
void
_M_assign_dispatch(_InputIter __first, _InputIter __last, __false_type)
{
typedef typename iterator_traits<_InputIter>::iterator_category
_IterCategory;
_M_assign_aux(__first, __last, _IterCategory());
}
// called by the second assign_dispatch above
template <class _InputIterator>
void
_M_assign_aux(_InputIterator __first, _InputIterator __last,
input_iterator_tag);
// called by the second assign_dispatch above
template <class _ForwardIterator>
void
_M_assign_aux(_ForwardIterator __first, _ForwardIterator __last,
forward_iterator_tag);
// Called by assign(n,t), and the range assign when it turns out to be the
// same thing.
void
_M_fill_assign(size_type __n, const value_type& __val);
// Internal insert functions follow.
// called by the range insert to implement [23.1.1]/9
template<class _Integer>
void
_M_insert_dispatch(iterator __pos, _Integer __n, _Integer __val,
__true_type)
{
_M_fill_insert(__pos, static_cast<size_type>(__n),
static_cast<value_type>(__val));
}
// called by the range insert to implement [23.1.1]/9
template<class _InputIterator>
void
_M_insert_dispatch(iterator __pos, _InputIterator __first,
_InputIterator __last, __false_type)
{
typedef typename iterator_traits<_InputIterator>::iterator_category
_IterCategory;
_M_range_insert(__pos, __first, __last, _IterCategory());
}
// called by the second insert_dispatch above
template <class _InputIterator> template <class _InputIterator>
void _M_range_insert(iterator __pos, void
_InputIterator __first, _InputIterator __last, _M_range_insert(iterator __pos,
input_iterator_tag); _InputIterator __first, _InputIterator __last,
input_iterator_tag);
// called by the second insert_dispatch above
template <class _ForwardIterator> template <class _ForwardIterator>
void _M_range_insert(iterator __pos, void
_ForwardIterator __first, _ForwardIterator __last, _M_range_insert(iterator __pos,
forward_iterator_tag); _ForwardIterator __first, _ForwardIterator __last,
forward_iterator_tag);
// Called by insert(p,n,x), and the range insert when it turns out to be
// the same thing.
void
_M_fill_insert (iterator __pos, size_type __n, const value_type& __x);
// called by insert(p,x)
void
_M_insert_aux(iterator __position, const value_type& __x);
#ifdef _GLIBCPP_DEPRECATED
// unused now (same situation as in deque)
void _M_insert_aux(iterator __position);
#endif
}; };
...@@ -924,12 +948,12 @@ protected: ...@@ -924,12 +948,12 @@ protected:
* and if corresponding elements compare equal. * and if corresponding elements compare equal.
*/ */
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
inline bool inline bool
operator==(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) operator==(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y)
{ {
return __x.size() == __y.size() && return __x.size() == __y.size() &&
equal(__x.begin(), __x.end(), __y.begin()); equal(__x.begin(), __x.end(), __y.begin());
} }
/** /**
* @brief Vector ordering relation. * @brief Vector ordering relation.
...@@ -943,19 +967,12 @@ operator==(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) ...@@ -943,19 +967,12 @@ operator==(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y)
* See std::lexographical_compare() for how the determination is made. * See std::lexographical_compare() for how the determination is made.
*/ */
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
inline bool inline bool
operator<(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) operator<(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y)
{ {
return lexicographical_compare(__x.begin(), __x.end(), return lexicographical_compare(__x.begin(), __x.end(),
__y.begin(), __y.end()); __y.begin(), __y.end());
} }
/// See std::vector::swap().
template <class _Tp, class _Alloc>
inline void swap(vector<_Tp, _Alloc>& __x, vector<_Tp, _Alloc>& __y)
{
__x.swap(__y);
}
/// Based on operator== /// Based on operator==
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
...@@ -985,10 +1002,17 @@ operator>=(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) { ...@@ -985,10 +1002,17 @@ operator>=(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) {
return !(__x < __y); return !(__x < __y);
} }
// XXX begin tcc me /// See std::vector::swap().
template <class _Tp, class _Alloc>
inline void swap(vector<_Tp, _Alloc>& __x, vector<_Tp, _Alloc>& __y)
{
__x.swap(__y);
}
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
vector<_Tp,_Alloc>& vector<_Tp,_Alloc>&
vector<_Tp,_Alloc>::operator=(const vector<_Tp, _Alloc>& __x) vector<_Tp,_Alloc>::operator=(const vector<_Tp,_Alloc>& __x)
{ {
if (&__x != this) { if (&__x != this) {
const size_type __xlen = __x.size(); const size_type __xlen = __x.size();
...@@ -1013,10 +1037,11 @@ vector<_Tp,_Alloc>::operator=(const vector<_Tp, _Alloc>& __x) ...@@ -1013,10 +1037,11 @@ vector<_Tp,_Alloc>::operator=(const vector<_Tp, _Alloc>& __x)
} }
template <class _Tp, class _Alloc> template <class _Tp, class _Alloc>
void vector<_Tp, _Alloc>::_M_fill_assign(size_t __n, const value_type& __val) void
vector<_Tp, _Alloc>::_M_fill_assign(size_t __n, const value_type& __val)
{ {
if (__n > capacity()) { if (__n > capacity()) {
vector<_Tp, _Alloc> __tmp(__n, __val, get_allocator()); vector __tmp(__n, __val, get_allocator());
__tmp.swap(*this); __tmp.swap(*this);
} }
else if (__n > size()) { else if (__n > size()) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment