/*************************************************************************** * * deque.cc - Non-iniline definitions for the Standard Library deque class * * $Id: deque.cc 550991 2007-06-26 23:58:07Z sebor $ * *************************************************************************** * * 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. * *************************************************************************** * * 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-2006 Rogue Wave Software. * **************************************************************************/ _RWSTD_NAMESPACE (std) { template deque<_TypeT, _Allocator>& deque<_TypeT, _Allocator>:: operator= (const deque &__rhs) { _RWSTD_ASSERT (_C_is_valid ()); _RWSTD_ASSERT (__rhs._C_is_valid ()); const size_type __size = size (); if (__size < __rhs.size ()) { const const_iterator __mid = __rhs.begin () + __size; _STD::copy (__mid, __rhs.end (), _STD::inserter (*this, _STD::copy (__rhs.begin (), __mid, begin ()))); } else erase (_STD::copy (__rhs.begin (), __rhs.end (), begin ()), end ()); return *this; } template _TYPENAME deque<_TypeT, _Allocator>::iterator deque<_TypeT, _Allocator>:: insert (iterator __it, const_reference __x) { _RWSTD_ASSERT_RANGE (begin (), __it); _RWSTD_ASSERT (_C_is_valid ()); if (__it == begin ()) { push_front (__x); return begin (); } if (__it == end ()) { push_back (__x); __it = end () - 1; return __it; } const size_type __inx = _DISTANCE (begin (), __it, size_type); _RWSTD_ASSERT (__inx < size ()); if (__inx < size () - __inx) { push_front (front ()); _STD::copy (begin () + 2, begin () + (__inx + 1), begin () + 1); } else { push_back (back ()); _STD::copy_backward (begin () + __inx, end () - 2, end () - 1); } __it = begin () + __inx; *__it = __x; return __it; } template _TYPENAME deque<_TypeT, _Allocator>::iterator deque<_TypeT, _Allocator>:: erase (iterator __it) { // `it' must be a dereferenceable iterator into `*this' _RWSTD_ASSERT_RANGE (begin (), __it); _RWSTD_ASSERT (!(__it == end ())); _RWSTD_ASSERT (_C_is_valid (0 /* valid and non-empty */)); const iterator __next = ++iterator (__it); if (__it - begin () < end () - __it) { _STD::copy_backward (begin (), __it, __next); pop_front (); return empty () ? end () : __next; } _STD::copy (__next, end (), __it); pop_back (); return __it; } template _TYPENAME deque<_TypeT, _Allocator>::iterator deque<_TypeT, _Allocator>:: erase (iterator __first, iterator __last) { // (`first', `last'] must be a valid range into `*this' _RWSTD_ASSERT_RANGE (__first, __last); _RWSTD_ASSERT_RANGE (begin (), __first); _RWSTD_ASSERT (_C_is_valid ()); size_type __n = _DISTANCE (__first, __last, size_type); _RWSTD_ASSERT (__n <= size ()); if (__first - begin () < end () - __last) { _STD::copy_backward (begin (), __first, __last); while (__n-- != 0) pop_front (); return __last; } _STD::copy (__last, end (), __first); while (__n-- != 0) pop_back (); return __first; } template void deque<_TypeT, _Allocator>:: swap (deque<_TypeT, _Allocator> &__rhs) { _RWSTD_ASSERT (_C_is_valid ()); _RWSTD_ASSERT (__rhs._C_is_valid ()); if (get_allocator () == __rhs.get_allocator ()) { _STD::swap (_C_beg, __rhs._C_beg); _STD::swap (_C_end, __rhs._C_end); _STD::swap (_C_nodes, __rhs._C_nodes); _STD::swap (_C_node_size, __rhs._C_node_size); if (pointer() == _C_beg._C_cur) { _RWSTD_ASSERT (pointer() == _C_end._C_cur); _RWSTD_ASSERT ( _C_beg._C_node == &__rhs._C_end._C_cur && _C_end._C_node == &__rhs._C_end._C_cur); _C_beg._C_node = _C_end._C_node = &_C_end._C_cur; } else { _RWSTD_ASSERT (pointer() != _C_end._C_cur); } if (pointer() == __rhs._C_beg._C_cur) { _RWSTD_ASSERT (pointer() == __rhs._C_end._C_cur); _RWSTD_ASSERT ( __rhs._C_beg._C_node == &_C_end._C_cur && __rhs._C_end._C_node == &_C_end._C_cur); __rhs._C_beg._C_node = __rhs._C_end._C_node = &__rhs._C_end._C_cur; } else { _RWSTD_ASSERT (pointer() != __rhs._C_end._C_cur); } } else { deque __tmp (*this); *this = __rhs; __rhs = __tmp; } } template void deque<_TypeT, _Allocator>:: _C_push (bool __at_back, const_reference __x) { _RWSTD_ASSERT (_C_is_valid ()); const size_type __bufsize = _C_bufsize (); _C_value_alloc_type __alloc (*this); // allocate a new buffer to store elements in const pointer __buf = __alloc.allocate (__bufsize, pointer ()); const bool __empty = empty (); if ( __empty || __at_back && _C_end._C_node == _C_nodes + _C_node_size - 1 || !__at_back && _C_beg._C_node == _C_nodes) { _C_node_alloc_type __node_alloc (*this); _RWSTD_ASSERT (_C_beg._C_node <= _C_end._C_node); // compute the current number of used nodes // and the new number of nodes const _C_node_pointer __end = _C_end._C_node + !__empty; const size_type __nodes = size_type (__end - _C_beg._C_node); // obtain the next greater number of nodes for the new vector const size_type __nvecsize = _C_vecsize (__nodes); _RWSTD_ASSERT (__nvecsize > __nodes); // compute the beginning of the old (current) vector const _C_node_pointer __ovec = _C_nodes - !__empty; _C_node_pointer __nvec; _TRY { // allocate enough for two extra unused nodes __nvec = __node_alloc.allocate (__nvecsize + 2, __ovec); _RWSTD_ASSERT (!(_C_node_pointer () == __nvec)); const pointer __where = __buf + ( __empty ? __bufsize / 2 - !__at_back : __at_back ? 0 : __bufsize - 1); _TRY { __alloc.construct (__where, __x); } _CATCH (...) { __node_alloc.deallocate (__nvec, __nvecsize + 2); _RETHROW; } // reserve the first and last nodes (must always be 0) ++__nvec; } _CATCH (...) { // deallocate buffer and rethrow __alloc.deallocate (__buf, __bufsize); _RETHROW; } // compute the new indices into the newly allocated vector // of the first and last occuppied node, respectively const size_type __beg_inx = __nvecsize / (__empty ? 2 : 4); const size_type __end_inx = __beg_inx + __nodes; // copy existing nodes into the new buffer _STD::copy (_C_beg._C_node, __end, __nvec + (__beg_inx + !__at_back)); // deallocate the current buffer only when non-0 to satisfy // the requirement that deallocate() argument be non-zero if (!(__ovec == _C_node_pointer ())) __node_alloc.deallocate (__ovec, _C_node_size + 2); // set the pointer and size _C_nodes = __nvec; _C_node_size = __nvecsize; // insert the fixed-size array into the vector of nodes... if (__at_back) { // ...at the end _C_nodes [__end_inx] = __buf; _C_beg._C_node = _C_nodes + __beg_inx; _C_end = _C_deque_iter (__buf, _C_nodes + __end_inx); } else { // ...at the beginning _C_nodes [__beg_inx] = __buf; _C_beg = _C_deque_iter (__buf + __bufsize, _C_nodes + __beg_inx); _C_end._C_node = _C_nodes + __end_inx; } if (__empty) { // set the beginning and end pointers both // to point at the same (future) element _C_beg._C_cur = _C_end._C_cur = __buf + __bufsize / 2; } } else { _RWSTD_ASSERT (_C_is_valid (0 /* valid and non-empty */)); _TRY { if (__at_back) { __alloc.construct (__buf, __x); // append the newly allocated buffer to the end of the vector // of pointers and increment `end' to point at the first // element in it; zero out the following node *++_C_end._C_node = __buf; _C_end._C_cur = __buf; } else { __alloc.construct (__buf + (__bufsize - 1), __x); // prepend the newly allocated buffer to the beginning of // the vector of pointers and decrement `begin' to point // at the last element in it; zero out the preceding node *--_C_beg._C_node = __buf; _C_beg._C_cur = __buf + __bufsize; } } _CATCH (...) { __alloc.deallocate (__buf, __bufsize); _RETHROW; } } _C_end._C_node [+1] = pointer (); _C_beg._C_node [-1] = pointer (); } template void deque<_TypeT, _Allocator>:: _C_free_at_begin () { const size_type __bufsize = _C_bufsize (); _RWSTD_VALUE_ALLOC (_C_value_alloc_type, *this, deallocate (*_C_beg._C_node, __bufsize)); if (empty ()) { _C_node_alloc_type (*this). deallocate (_C_nodes - 1, _C_node_size + 2); _C_init (); } else { *_C_beg._C_node++ = pointer (); _C_beg = _C_deque_iter (*_C_beg._C_node, _C_beg._C_node); } } template void deque<_TypeT, _Allocator>:: _C_free_at_end () { const size_type __bufsize = _C_bufsize (); _RWSTD_VALUE_ALLOC (_C_value_alloc_type, *this, deallocate (*_C_end._C_node, __bufsize)); if (empty ()) { _C_node_alloc_type (*this). deallocate (_C_nodes - 1, _C_node_size + 2); _C_init (); } else { *_C_end._C_node-- = pointer (); _C_end = _C_deque_iter (*_C_end._C_node + __bufsize, _C_end._C_node); } } template void deque<_TypeT, _Allocator>:: _C_assign_n (size_type __n, const_reference __x) { _RWSTD_ASSERT (_C_is_valid ()); #ifndef _RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE // assign over existing elements for better efficiency // and exception safety // complexity: linear in n // exception safety: // -- nothrow if size() >= n, and value_type's assignment operator // and iterator operations do not throw // -- basic otherwise const iterator __end = end (); // avoid using the name __i or __it below so as not to trigger // a (bogus) gcc 2.95.2 -Wshadow warning: declaration of `__i' // shadows previous local for (iterator __ix = begin (); !(__ix == __end); ++__ix, --__n) { if (size_type () == __n) { erase (__ix, __end); return; } *__ix = __x; } insert (__end, __n, __x); #else // if defined (_RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE) // follow the inefficient requirement in 23.2.1.1, p8 // complexity: linear in n // exception safety: basic clear (); insert (begin (), __n, __x); #endif // _RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE } template void deque<_TypeT, _Allocator>:: _C_insert_n (const iterator &__it, size_type __n, const_reference __x) { _RWSTD_ASSERT_RANGE (begin (), __it); _RWSTD_ASSERT (_C_is_valid ()); const size_type __inx = _DISTANCE (begin (), __it, size_type); const size_type __rem = size () - __inx; _RWSTD_ASSERT (__inx <= size ()); if (__inx < __rem) { // inserting `x' into the first half of the container if (__inx < __n) { for (size_type __i = __n - __inx; __i; --__i) push_front (__x); for (size_type __j = __inx; __j; --__j) push_front (*(begin () + (__n - 1))); _STD::fill (begin () + __n, begin () + (__n + __inx), __x); } else if (__n) { for (size_type __i = __n; __i; --__i) push_front (*(begin () + __n - 1)); const iterator __tmp = begin () + __n; _STD::copy (__tmp + __n, __tmp + __inx, __tmp); _STD::fill (begin () + __inx, __tmp + __inx, __x); } } else { // inserting `x' into the second half of the container const size_type __size0 = size (); if (__rem < __n) { for (size_type __i = __n - __rem; __i; --__i) push_back (__x); for (size_type __j = 0; __j != __rem; ++__j) push_back (*(begin () + (__inx + __j))); _STD::fill (begin () + __inx, begin () + __size0, __x); } else if (__n) { for (size_type __i = 0;__i != __n; ++__i) push_back (*(begin () + __size0 - __n + __i)); const iterator __tmp = begin () + __inx; _STD::copy_backward (__tmp, begin () + __size0 - __n, begin () + __size0); _STD::fill (__tmp, __tmp + __n, __x); } } } #ifndef _RWSTD_NO_MEMBER_TEMPLATES template template void deque<_TypeT, _Allocator>:: _C_assign_range (_InputIter __first, _InputIter __last, input_iterator_tag) { typedef deque _Deque; deque* const __self = this; #else // if defined (_RWSTD_NO_MEMBER_TEMPLATES) template void __rw_assign_range (deque<_TypeT, _Allocator> *__self, _InputIter __first, _InputIter __last, input_iterator_tag) { typedef deque<_TypeT, _Allocator> _Deque; typedef _TYPENAME _Deque::iterator iterator; #endif // _RWSTD_NO_MEMBER_TEMPLATES _RWSTD_ASSERT_RANGE (__first, __last); _RWSTD_ASSERT (__self->_C_is_valid ()); #ifndef _RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE // assign over existing elements for better efficiency // and exception safety // complexity: linear in distance(first, last) // exception safety: // -- nothrow if size() >= distance(first, last), and value_type's // assignment operator and iterator operations do not throw // -- basic otherwise const iterator __end = __self->end (); // avoid using the name __i or __it below so as not to trigger // a (bogus) gcc 2.95.2 -Wshadow warning: declaration of `__i' // shadows previous local for (iterator __ix = __self->begin (); !(__ix == __end); ++__ix, ++__first) { if (__first == __last) { __self->erase (__ix, __end); return; } *__ix = *__first; } __self->insert (__end, __first, __last); #else // if defined (_RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE) // follow the inefficient requirement in 23.2.1.1, p7 // complexity: linear in distance(first, last) // exception safety: basic __self->clear (); __self->insert (__self->begin (), __first, __last); #endif // _RWSTD_NO_EXT_DEQUE_ASSIGN_IN_PLACE } #ifndef _RWSTD_NO_MEMBER_TEMPLATES template template void deque<_TypeT, _Allocator>:: _C_insert_range (iterator __it, _InputIter __first, _InputIter __last, input_iterator_tag) { typedef deque _Deque; _Deque* const __self = this; #else // if defined (_RWSTD_NO_MEMBER_TEMPLATES) template void __rw_insert_range (deque<_TypeT, _Allocator> *__self, _DequeIter __it, _InputIter __first, _InputIter __last, input_iterator_tag) { typedef deque<_TypeT, _Allocator> _Deque; #endif // _RWSTD_NO_MEMBER_TEMPLATES _RWSTD_ASSERT_RANGE (__it, __self->end ()); _RWSTD_ASSERT_RANGE (__first, __last); #ifndef _RWSTD_NO_EXT_DEQUE_INSERT_IN_PLACE // insert one element at a time to prevent a loss of data // from the input sequence in the case of an exception for ( ; !(__first == __last); ++__it, ++__first) __it = __self->insert (__it, *__first); #else // if defined (_RWSTD_NO_EXT_DEQUE_INSERT_IN_PLACE) // 23.2.1.3, p2: if an exception is thrown other than by the copy // constructor or assignment operator of T there are no effects. _Deque __tmp (__self->begin (), __it, __self->get_allocator ()); for (; !(__first == __last); ++__first) __tmp.push_back (*__first); __tmp.insert (__tmp.end (), __it, __self->end ()); __self->swap (__tmp); #endif // _RWSTD_NO_EXT_DEQUE_INSERT_IN_PLACE } // #ifndef _RWSTD_NO_MEMBER_TEMPLATES // template // template // void deque<_TypeT, _Allocator>:: // _C_insert_range (iterator __it, // _FwdIter __first, _FwdIter __last, // forward_iterator_tag) // { // typedef deque _Deque; // _Deque* const __self = this; // #else // if defined (_RWSTD_NO_MEMBER_TEMPLATES) // template // void // __rw_insert_range (deque<_TypeT, _Allocator> *__self, _DequeIter __it, // _FwdIter __first, _FwdIter __last, forward_iterator_tag) // { // typedef deque<_TypeT, _Allocator> _Deque; // #endif // _RWSTD_NO_MEMBER_TEMPLATES // // implemented in terms of the Input Iterator overload // _RWSTD_INSERT_RANGE (__it, __first, __last, input_iterator_tag ()); // } #ifndef _RWSTD_NO_MEMBER_TEMPLATES template template void deque<_TypeT, _Allocator>:: _C_insert_range (iterator __it, _BidirIter __first, _BidirIter __last, bidirectional_iterator_tag) { typedef deque _Deque; _Deque* const __self = this; #else // if defined (_RWSTD_NO_MEMBER_TEMPLATES) template void __rw_insert_range (deque<_TypeT, _Allocator> *__self, _DequeIter __it, _BidirIter __first, _BidirIter __last, bidirectional_iterator_tag) { typedef deque<_TypeT, _Allocator> _Deque; typedef _TYPENAME _Deque::difference_type difference_type; typedef _TYPENAME _Deque::size_type size_type; typedef _TYPENAME _Deque::iterator iterator; #endif // _RWSTD_NO_MEMBER_TEMPLATES _RWSTD_ASSERT_RANGE (__self->begin (), __it); _RWSTD_ASSERT_RANGE (__first, __last); _RWSTD_ASSERT (__self->_C_is_valid ()); // compute the distance of `it' from the beginning of the container, // the distance of `it' to the end of the container, and the number // of elements to be inserted const size_type __sz0 = __self->size (); const size_type __inx = _DISTANCE (__self->begin (), __it, size_type); const size_type __rem = __sz0 - __inx; const size_type __n = _DISTANCE (__first, __last, size_type); _RWSTD_ASSERT (__inx <= __sz0); if (__inx < __rem) { // inserting into the first half of the container if (__inx < __n) { // the number of elements in the range controlled by *this, // [begin, it), is less than the number of elements in the // range [first, last) _BidirIter __from (__last); _STD::advance (__from, -difference_type (__inx)); const _BidirIter __mid (__from); while (!(__from == __first)) __self->push_front (*--__from); for (size_type __i = __inx; __i; --__i) __self->push_front (*(__self->begin () + (__n - 1))); _STD::copy (__mid, __last, __self->begin () + __n); } else { // the number of elements in the range to be inserted, // [first, last), is less than or equal to the number // of elements in the range [begin, it) for (size_type __i = __n; __i; --__i) __self->push_front (*(__self->begin () + (__n - 1))); const iterator __to = __self->begin () + __n; _STD::copy (__to + __n, __to + __inx, __to); _STD::copy (__first, __last, __self->begin () + __inx); } } else { // inserting into the second half of the container if (__rem < __n) { _BidirIter __from (__first); _STD::advance (__from, __rem); const _BidirIter __to (__from); for ( ; !(__from == __last); ++__from) __self->push_back (*__from); for (size_type __i = 0; __i != __rem; ++__i) __self->push_back (*(__self->begin () + (__inx + __i))); _STD::copy (__first, __to, __self->begin () + __inx); } else { for (size_type __i = 0; __i != __n; ++__i) __self->push_back (*(__self->begin () + (__sz0 - __n + __i))); const iterator __to = __self->begin () + __sz0; const iterator __from = __self->begin () + __inx; const iterator __from_end = __self->begin () + (__sz0 - __n); _STD::copy_backward (__from, __from_end, __to); _STD::copy (__first, __last, __from); } } } template bool deque<_TypeT, _Allocator>:: _C_is_valid (int __emptyfl) const { #ifdef _RWSTDDEBUG if (__emptyfl < 0 /* don't care */) return _C_is_valid (0 + empty ()); // the nodes just prior the first valid node and // just past the last valid node must always be 0 if (_C_node_pointer () != _C_nodes) { _RWSTD_ASSERT (pointer () == _C_beg._C_node [-1]); _RWSTD_ASSERT (pointer () == _C_end._C_node [+1]); } if (__emptyfl) { // container must be empty _RWSTD_ASSERT (empty ()); // both `current' pointers must be 0 _RWSTD_ASSERT (pointer () == _C_beg._C_cur); _RWSTD_ASSERT (pointer () == _C_end._C_cur); // node pointers must be dereferenceable... _RWSTD_ASSERT (_C_node_pointer () != _C_beg._C_node); _RWSTD_ASSERT (_C_node_pointer () != _C_end._C_node); // ...and both must dereference the same pointer _RWSTD_ASSERT (*_C_beg._C_node == *_C_end._C_node); return true; } const size_type __bufsize = _C_bufsize (); // container must be non-empty _RWSTD_ASSERT (!empty ()); // current pointers must be non-0 _RWSTD_ASSERT (pointer () != _C_beg._C_cur); _RWSTD_ASSERT (pointer () != _C_end._C_cur); // `begin' must be less than `end' _RWSTD_ASSERT (_C_beg._C_node <= _C_end._C_node); // `begin' must point into the vector of nodes _RWSTD_ASSERT (_C_nodes <= _C_beg._C_node); _RWSTD_ASSERT (_C_beg._C_node <= _C_nodes + _C_node_size); // `begin' must point to a non-empty array of elements _RWSTD_ASSERT (pointer () != *_C_beg._C_node); // `begin' must point into an array of `bufsize' elements _RWSTD_ASSERT (_C_beg._C_cur >= *_C_beg._C_node); _RWSTD_ASSERT (_C_beg._C_cur <= *_C_beg._C_node + __bufsize); // `end' must point into the vector of nodes _RWSTD_ASSERT (_C_nodes <= _C_end._C_node); _RWSTD_ASSERT (_C_end._C_node <= _C_nodes + _C_node_size); // `end' must point to a non-empty array of elements _RWSTD_ASSERT (pointer () != *_C_end._C_node); // `end' must point into an array of `bufsize' elements _RWSTD_ASSERT (_C_end._C_cur >= *_C_end._C_node); _RWSTD_ASSERT (_C_end._C_cur <= *_C_end._C_node + __bufsize); #else // if !defined (_RWSTDDEBUG) _RWSTD_UNUSED (__emptyfl); #endif // _RWSTDDEBUG return true; } } // namespace std