blob: 551b5a67e17a468bbe9345497921f4437e605ba5 [file] [log] [blame]
// -*- C++ -*-
/***************************************************************************
*
* <list> - definition of the C++ Standard Library list class template
*
* $Id$
*
***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 1994-2005 Rogue Wave Software.
*
***************************************************************************
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
**************************************************************************/
#ifndef _RWSTD_LIST_INCLUDED
#define _RWSTD_LIST_INCLUDED
#include <memory>
#include <rw/_algobase.h>
#include <rw/_iterator.h>
#include <rw/_select.h>
#include <rw/_defs.h>
#include <rw/_error.h>
_RWSTD_NAMESPACE (std) {
template <class _TypeT>
struct __rw_list_node
{
__rw_list_node* _C_next; // pointer to next node
__rw_list_node* _C_prev; // pointer to previous node
_TypeT _C_data; // client data
};
template <class _TypeT, class _DiffT, class _Pointer, class _Reference>
class __rw_list_iter
: public iterator <bidirectional_iterator_tag,
_TypeT, _DiffT, _Pointer, _Reference>
{
typedef iterator <bidirectional_iterator_tag,
_TypeT, _DiffT, _Pointer, _Reference>
_C_iter_base;
public:
typedef typename _C_iter_base::value_type value_type;
typedef typename _C_iter_base::difference_type difference_type;
typedef typename _C_iter_base::pointer pointer;
typedef typename _C_iter_base::reference reference;
// const_pointer and const_reference must be explicity typedef'ed to
// const value_type* and const value_type& since we don't know if
// _Pointer and _Reference are const types (they aren't if this isn't
// a const iterator)
typedef const value_type* const_pointer;
typedef const value_type& const_reference;
typedef bidirectional_iterator_tag iterator_category;
typedef __rw_list_iter <value_type, difference_type,
value_type*, value_type&> _C_mutable_iter;
typedef __rw_list_node<value_type>* _C_link_type;
__rw_list_iter () { }
__rw_list_iter (const _C_link_type& __rhs)
: _C_node (__rhs) { }
// no copy ctor other than the one below defined; will use
// a compiler generated one if __rw_list_iter != _C_mutable_iter
__rw_list_iter (const _C_mutable_iter &__rhs)
: _C_node (__rhs._C_node) { }
__rw_list_iter& operator++ () {
_C_node = (_C_link_type)((*_C_node)._C_next);
return *this;
}
__rw_list_iter& operator-- () {
_C_node = (_C_link_type)((*_C_node)._C_prev);
return *this;
}
__rw_list_iter operator++ (int) {
__rw_list_iter __tmp = *this;
return ++*this, __tmp;
}
__rw_list_iter operator-- (int) {
__rw_list_iter __tmp = *this;
return --*this, __tmp;
}
reference operator* () const {
return (*_C_node)._C_data;
}
_RWSTD_OPERATOR_ARROW (pointer operator-> () const);
difference_type operator- (const __rw_list_iter&) const {
return 0;
}
bool operator== (const __rw_list_iter& __iter) const {
return _C_node == __iter._C_node;
}
bool operator!= (const __rw_list_iter& __iter) const {
return !(*this == __iter);
}
// private:
_C_link_type _C_node;
};
#undef _ITER_NODE
#define _ITER_NODE(it) (_ITER_BASE (it)._C_node)
template <class _TypeT, class _DiffT, class _Ptr1, class _Ref1,
class _Ptr2, class _Ref2>
inline bool
operator== (const __rw_list_iter<_TypeT, _DiffT, _Ptr1, _Ref1> &__x,
const __rw_list_iter<_TypeT, _DiffT, _Ptr2, _Ref2> &__y)
{
return __x._C_node == __y._C_node;
}
template <class _TypeT, class _DiffT, class _Ptr1, class _Ref1,
class _Ptr2, class _Ref2>
inline bool
operator!= (const __rw_list_iter<_TypeT, _DiffT, _Ptr1, _Ref1> &__x,
const __rw_list_iter<_TypeT, _DiffT, _Ptr2, _Ref2> &__y)
{
return !(__x == __y);
}
_EXPORT
template <class _TypeT, class _Allocator = allocator<_TypeT> >
class list : private _Allocator
{
public:
typedef _TypeT value_type;
typedef _Allocator allocator_type;
typedef typename allocator_type::reference reference;
typedef typename allocator_type::const_reference const_reference;
typedef typename allocator_type::size_type size_type;
typedef typename allocator_type::difference_type difference_type;
typedef typename allocator_type::pointer pointer;
typedef typename allocator_type::const_pointer const_pointer;
typedef __rw_list_node<value_type> _C_list_node;
typedef _C_list_node* _C_link_type;
typedef _RWSTD_REBIND (allocator_type, _C_list_node) _C_node_alloc_type;
typedef _RWSTD_ALLOC_TYPE (allocator_type, value_type) _C_value_alloc_type;
typedef __rw_list_iter<value_type, difference_type, pointer, reference>
_C_list_iter;
typedef __rw_list_iter<value_type, difference_type, const_pointer,
const_reference>
_C_list_citer;
#ifndef _RWSTD_NO_DEBUG_ITER
typedef _RW::__rw_debug_iter <list,_C_list_iter, _C_list_iter>
iterator;
typedef _RW::__rw_debug_iter <list,_C_list_citer, _C_list_iter>
const_iterator;
iterator _C_make_iter (const _C_link_type &__node) {
return iterator (*this, _C_list_iter (__node));
}
const_iterator _C_make_iter (const _C_link_type &__node) const {
return const_iterator (*this, _C_list_citer (__node));
}
#else // if defined (_RWSTD_NO_DEBUG_ITER)
typedef _C_list_iter iterator;
typedef _C_list_citer const_iterator;
iterator _C_make_iter (const _C_link_type &__node) {
return iterator (__node);
}
const_iterator _C_make_iter (const _C_link_type &__node) const {
return const_iterator (__node);
}
#endif // _RWSTD_NO_DEBUG_ITER
#if !defined (_RWSTD_NO_CLASS_PARTIAL_SPEC)
typedef _STD::reverse_iterator<const_iterator> const_reverse_iterator;
typedef _STD::reverse_iterator<iterator> reverse_iterator;
#else // if defined (_RWSTD_NO_CLASS_PARTIAL_SPEC)
typedef std::reverse_iterator<const_iterator,
bidirectional_iterator_tag, value_type,
const_reference, const_pointer, difference_type>
const_reverse_iterator;
typedef std::reverse_iterator<iterator,
bidirectional_iterator_tag, value_type,
reference, pointer, difference_type>
reverse_iterator;
#endif // _RWSTD_NO_CLASS_PARTIAL_SPEC
protected:
#ifndef _RWSTD_NO_LIST_NODE_BUFFER
// Node buffer data structure
struct _C_nodebuf {
typedef _RWSTD_REBIND (allocator_type, _C_nodebuf) _C_alloc_type;
typedef typename _C_alloc_type::pointer _C_pointer;
_C_pointer _C_next_buf;
size_type _C_bufsize;
_C_link_type _C_buffer;
};
typedef typename _C_nodebuf::_C_alloc_type _C_buf_alloc_type;
typedef typename _C_nodebuf::_C_pointer _C_buf_pointer;
void _C_add_buffer (bool);
void _C_free_buffers ();
_C_buf_pointer _C_buflist;
_C_link_type _C_free_list;
#endif // _RWSTD_USE_LIST_NODE_BUFFER
_C_link_type _C_next_avail;
_C_link_type _C_last;
_C_link_type _C_node;
size_type _C_length;
// Macros used later in node buffer management
#if !defined (_RWSTD_NO_LIST_NODE_BUFFER)
# define _RWSTD_NODE_BUFFER_INIT(blist,flist) \
_C_buflist (blist), _C_free_list (flist),
# define _RWSTD_NODE_LIST_FREE() \
_C_free_buffers ()
# define _RWSTD_NODE_LIST_SWAP(other) \
_STD::swap (_C_buflist, other._C_buflist); \
_STD::swap (_C_free_list, other._C_free_list)
# define _RWSTD_LIST_INSERT_RANGE(b,e,v) \
_TRY { \
insert (b, e, v); \
} _CATCH (...) { \
_RWSTD_NODE_LIST_FREE(); \
_RETHROW; \
} typedef void __dummy_t
_C_link_type _C_get_node (bool __empty_list = false) {
if (_C_free_list) {
_C_link_type __tmp = _C_free_list;
_C_free_list = _C_free_list->_C_next;
return __tmp;
}
if (_C_next_avail == _C_last)
_C_add_buffer (__empty_list);
return _C_next_avail++;
}
void _C_put_node (_C_link_type __link) {
__link->_C_next = _C_free_list;
_C_free_list = __link;
}
#else // defined (_RWSTD_NO_LIST_NODE_BUFFER)
# define _RWSTD_NODE_BUFFER_INIT(ignore0,ignore1)
# define _RWSTD_NODE_LIST_FREE()
# define _RWSTD_NODE_LIST_SWAP(ignore)
# define _RWSTD_LIST_INSERT_RANGE(b,e,v) \
insert (b,e,v)
_C_link_type _C_get_node (bool = false) {
return _C_node_alloc_type (*this).allocate (1, (void*)_C_last);
}
void _C_put_node (_C_link_type __link) {
_C_node_alloc_type (*this).deallocate (__link, 1);
}
#endif // _RWSTD_NO_LIST_NODE_BUFFER
# define _RWSTD_LIST_SAFE_INSERT_RANGE(__it, __first, __last) \
_RWSTD_ASSERT_RANGE (begin (), __it); \
_RWSTD_ASSERT_RANGE (__first, __last); \
\
if (!(__first == __last)) { \
iterator __start = __it; \
\
_TRY { \
__start = insert (__it, *__first); \
\
while (!(++__first == __last)) \
insert (__it, *__first); \
} _CATCH (...) { \
erase (__start, __it); \
_RETHROW; \
} \
} typedef void __dummy_t
// here and only here is _C_node initialized
void _C_init (bool __empty_list = false) {
_C_node = _C_get_node (__empty_list);
(*_C_node)._C_next = _C_node;
(*_C_node)._C_prev = _C_node;
}
void _C_init (size_type __n, const value_type& __val) {
_C_init();
_RWSTD_LIST_INSERT_RANGE (begin (), __n, __val);
}
public:
explicit
list (const allocator_type& __alloc = allocator_type ())
: allocator_type (__alloc), _RWSTD_NODE_BUFFER_INIT(0,0)
_C_next_avail (0), _C_last (0), _C_node (0), _C_length (0) {
_C_init (true);
}
explicit
list (size_type __n,
const_reference __x = value_type (),
const allocator_type &__alloc = allocator_type ())
: allocator_type (__alloc), _RWSTD_NODE_BUFFER_INIT(0,0)
_C_next_avail (0), _C_last (0), _C_node (0), _C_length (0) {
_C_init (__n, __x);
}
template<class _InputIterator>
void _C_init (_InputIterator __first, _InputIterator __last, void*) {
_RWSTD_ASSERT_RANGE (__first, __last);
_C_init();
_RWSTD_LIST_INSERT_RANGE (begin (), __first, __last);
}
template<class _InputIterator>
void _C_init (_InputIterator __first, _InputIterator __last, int) {
_RWSTD_ASSERT_RANGE (__first, __last);
_C_init (__first, __last);
}
template<class _InputIterator>
list (_InputIterator __first, _InputIterator __last,
const allocator_type& __alloc = allocator_type ())
: allocator_type (__alloc), _RWSTD_NODE_BUFFER_INIT(0,0)
_C_next_avail (0), _C_last (0), _C_node (0), _C_length (0) {
_RWSTD_ASSERT_RANGE (__first, __last);
_C_init (__first, __last, _RWSTD_DISPATCH (_InputIterator));
}
list (const list &__rhs)
: allocator_type(__rhs.get_allocator()), _RWSTD_NODE_BUFFER_INIT(0,0)
_C_next_avail (0), _C_last (0), _C_node (0), _C_length (0) {
_C_init();
_RWSTD_LIST_INSERT_RANGE (begin (), __rhs.begin (), __rhs.end ());
}
~list ();
list& operator= (const list&);
template<class _InputIterator>
void assign (_InputIterator __first, _InputIterator __last) {
_RWSTD_ASSERT_RANGE (__first, __last);
clear ();
_C_insert (begin (), __first, __last,
_RWSTD_DISPATCH (_InputIterator));
}
void assign (size_type __n, const_reference __val) {
clear ();
insert (begin (), __n, __val);
}
allocator_type get_allocator () const {
return *this;
}
iterator begin () {
return _C_make_iter ((*_C_node)._C_next);
}
const_iterator begin () const {
return _C_make_iter ((*_C_node)._C_next);
}
iterator end () {
return _C_make_iter (_C_node);
}
const_iterator end () const {
return _C_make_iter (_C_node);
}
reverse_iterator rbegin () {
return reverse_iterator (end ());
}
const_reverse_iterator rbegin () const {
return const_reverse_iterator (end ());
}
reverse_iterator rend () {
return reverse_iterator (begin ());
}
const_reverse_iterator rend () const {
return const_reverse_iterator (begin ());
}
bool empty () const {
return 0 == size ();
}
size_type size () const {
return _C_length;
}
size_type max_size () const {
return _C_node_alloc_type (*this).max_size ();
}
void resize (size_type, value_type);
void resize (size_type __n) {
resize (__n, value_type ());
}
reference front () {
_RWSTD_ASSERT (!empty ());
return *begin ();
}
const_reference front () const {
_RWSTD_ASSERT (!empty ());
return *begin ();
}
reference back () {
_RWSTD_ASSERT (!empty ());
return *--end ();
}
const_reference back () const {
_RWSTD_ASSERT (!empty ());
return *--end ();
}
void push_front (const_reference __x) {
insert (begin (), __x);
_RWSTD_ASSERT (!empty ());
}
void push_back (const_reference __x) {
insert (end (), __x);
_RWSTD_ASSERT (!empty ());
}
void pop_front () {
_RWSTD_ASSERT (!empty ());
erase (begin ());
}
void pop_back () {
_RWSTD_ASSERT (!empty ());
erase (--end ());
}
iterator insert (iterator __it, const_reference __x);
// handles nonintegral types
template<class _InputIterator>
void _C_insert (const iterator &__it,
_InputIterator __first, _InputIterator __last, void*) {
_RWSTD_LIST_SAFE_INSERT_RANGE (__it, __first, __last);
}
// handles integral types
template<class _InputIterator>
void _C_insert (const iterator &__it,
_InputIterator __first, _InputIterator __last, int) {
_C_insert (__it, size_type (__first), const_reference (__last));
}
template<class _InputIterator>
void insert (iterator __it,
_InputIterator __first, _InputIterator __last) {
_RWSTD_ASSERT_RANGE (begin (), __it);
_RWSTD_ASSERT_RANGE (__first, __last);
// calling insert on a list specialized on an integral type
// may lead to ambiguities if the actual function arguments do not
// exactly match those of the non-templatized function (below)
// the dispatch mechanism determines whether the arguments
// really are iterators or whether they are just integral types
// and calls the appropriate implementation function
_C_insert (__it, __first, __last, _RWSTD_DISPATCH (_InputIterator));
}
void insert (iterator __it, size_type __n, const_reference __val) {
_RWSTD_ASSERT_RANGE (begin (), __it);
_C_insert (__it, __n, __val);
}
iterator erase (iterator);
iterator erase (iterator, iterator);
void swap (list&);
void clear () {
erase (begin (), end ());
}
#if defined (_RWSTD_NO_PART_SPEC_OVERLOAD)
friend void swap (list& __lhs, list& __rhs) {
__lhs.swap (__rhs);
}
#endif
protected:
void _C_transfer (iterator, iterator, iterator, list&);
void _C_advance (iterator &__it, difference_type __n,
const iterator &__end) {
while (__n-- && !(__it == __end))
++__it;
}
// uses transfer_node to merge in list by transfering nodes to list
void _C_adjacent_merge (iterator, iterator, iterator);
// uses transfer_node to merge in list by transfering nodes to list
template<class _Compare>
void _C_adjacent_merge (iterator, iterator, iterator, _Compare);
void _C_insert (iterator __it, size_type __n, const_reference __x) {
_RWSTD_ASSERT_RANGE (begin (), __it);
if (__n) {
iterator __start = __it;
_TRY {
__start = insert (__it, __x);
while (--__n)
insert (__it, __x);
} _CATCH (...) {
erase (__start, __it);
_RETHROW;
}
}
}
public:
// 23.2.2.4, p4
void splice (iterator, list&);
// 23.2.2.4, p7
void splice (iterator, list&, iterator);
// 23.2.2.4, p11
void splice (iterator, list&, iterator, iterator);
void remove (const_reference);
void unique ();
void merge (list&);
void reverse ();
void sort ();
template<class _Predicate>
void remove_if (_Predicate);
template<class _BinaryPredicate>
void unique (_BinaryPredicate);
template<class _Compare>
void merge (list &__x, _Compare);
template<class _Compare>
void sort (_Compare);
};
template <class _TypeT, class _Allocator>
inline bool
operator== (const list<_TypeT, _Allocator>& __x,
const list<_TypeT, _Allocator>& __y)
{
return __x.size () == __y.size ()
&& equal (__x.begin (), __x.end (), __y.begin ());
}
template <class _TypeT, class _Allocator>
inline bool
operator< (const list<_TypeT, _Allocator>& __x,
const list<_TypeT, _Allocator>& __y)
{
return lexicographical_compare (__x.begin (), __x.end (),
__y.begin (), __y.end ());
}
template <class _TypeT, class _Allocator>
inline bool
operator!= (const list<_TypeT, _Allocator>& __x,
const list<_TypeT, _Allocator>& __y)
{
return !(__x == __y);
}
template <class _TypeT, class _Allocator>
inline bool
operator<= (const list<_TypeT, _Allocator>& __x,
const list<_TypeT, _Allocator>& __y)
{
return !(__y < __x);
}
template <class _TypeT, class _Allocator>
inline bool
operator> (const list<_TypeT, _Allocator>& __x,
const list<_TypeT, _Allocator>& __y)
{
return __y < __x;
}
template <class _TypeT, class _Allocator>
inline bool
operator>= (const list<_TypeT, _Allocator>& __x,
const list<_TypeT, _Allocator>& __y)
{
return !(__x < __y);
}
#ifndef _RWSTD_NO_PART_SPEC_OVERLOAD
template <class _TypeT, class _Allocator>
inline void swap (list<_TypeT, _Allocator>& __x,
list<_TypeT, _Allocator>& __y)
{
__x.swap (__y);
}
#endif // _RWSTD_NO_PART_SPEC_OVERLOAD
template <class _TypeT, class _Allocator>
inline typename list<_TypeT, _Allocator>::iterator
list<_TypeT, _Allocator>::insert (iterator __it, const_reference __x)
{
_RWSTD_ASSERT_RANGE (begin (), __it);
// create temporary allocator for non-conforming compilers
// which need to use allocator_interface
_C_link_type __tmp = _C_get_node (false);
_TRY {
_RWSTD_VALUE_ALLOC (_C_value_alloc_type, *this,
construct (_RWSTD_VALUE_ALLOC
(_C_value_alloc_type, *this,
address ((*__tmp)._C_data)), __x));
}
_CATCH (...) {
_C_put_node (__tmp);
_RETHROW;
}
(*__tmp)._C_next = _ITER_NODE (__it);
(*__tmp)._C_prev = (*_ITER_NODE (__it))._C_prev;
(*(_C_link_type ((*_ITER_NODE (__it))._C_prev)))._C_next = __tmp;
(*_ITER_NODE (__it))._C_prev = __tmp;
++_C_length;
return _C_make_iter (__tmp);
}
template <class _TypeT, class _Allocator>
inline typename list<_TypeT, _Allocator>::iterator
list<_TypeT, _Allocator>::erase (iterator __it)
{
_RWSTD_ASSERT_RANGE (begin (), __it);
if (__it == end ())
return end ();
iterator __tmp =
_C_make_iter (_C_link_type ((*_ITER_NODE (__it))._C_next));
(*(_C_link_type ((*_ITER_NODE (__it))._C_prev)))._C_next =
(*_ITER_NODE (__it))._C_next;
(*(_C_link_type ((*_ITER_NODE (__it))._C_next)))._C_prev =
(*_ITER_NODE (__it))._C_prev;
--_C_length;
_RWSTD_VALUE_ALLOC (_C_value_alloc_type, *this,
destroy (_RWSTD_VALUE_ALLOC (_C_value_alloc_type,
*this, address ((*_ITER_NODE (__it))._C_data))));
_C_put_node (_ITER_NODE (__it));
return __tmp;
}
template <class _TypeT, class _Allocator>
inline void
list<_TypeT, _Allocator>::swap (list &__x)
{
if (get_allocator () == __x.get_allocator ()) {
_STD::swap (_C_node, __x._C_node);
_STD::swap (_C_length, __x._C_length);
_RWSTD_NODE_LIST_SWAP(__x);
_STD::swap (_C_next_avail, __x._C_next_avail);
_STD::swap (_C_last, __x._C_last);
}
else {
list __tmp (*this);
*this = __x;
__x = __tmp;
}
}
} // namespace std
#ifdef _RWSTD_NO_IMPLICIT_INCLUSION
# include <list.cc>
#endif
#endif //_RWSTD_LIST_INCLUDED