// bslstl_deque.h -*-C++-*- #ifndef INCLUDED_BSLSTL_DEQUE #define INCLUDED_BSLSTL_DEQUE #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide an STL-compliant deque class. // //@CLASSES: // bsl::deque: STL-compliant deque template // //@CANONICAL_HEADER: bsl_deque.h // //@SEE_ALSO: bslstl_vector // //@DESCRIPTION: This component defines a single class template, 'bsl::deque', // implementing the standard sequential container, 'std::deque', holding a // dynamic sequence of values of a template parameter type. // // An instantiation of 'deque' is an allocator-aware, value-semantic type // whose salient attributes are its size (number of contained elements) and the // (ordered) sequence of values the deque contains. If 'deque' is instantiated // with a value type that is not value-semantic, then the deque will not retain // all of its value-semantic qualities. In particular, if a value type cannot // be tested for equality, then a 'deque' containing elements of that type // cannot be tested for equality. It is even possible to instantiate 'deque' // with a value type that does not have a copy-constructor, in which case the // 'deque' will not be copyable. // // A deque meets the requirements of a sequential container with random access // iterators in section [deque] of the C++ standard. The 'deque' implemented // here adheres to the C++11 standard when compiled with a C++11 compiler, and // makes the best approximation when compiled with a C++03 compiler. In // particular, for C++03 we emulate move semantics, but limit forwarding (in // 'emplace') to 'const' lvalues, and make no effort to emulate 'noexcept' or // initializer-lists. // ///Requirements on 'VALUE_TYPE' ///---------------------------- // A 'deque' is a fully Value-Semantic Type (see {'bsldoc_glossary'}) only if // the supplied 'VALUE_TYPE' template parameter is fully value-semantic. It is // possible to instantiate a 'deque' with a 'VALUE_TYPE' parameter that does // not have a full set of value-semantic operations, but then some methods of // the container may not be instantiable. The following terminology, adopted // from the C++11 standard, is used in the function documentation of 'deque' // to describe a function's requirements for the 'VALUE_TYPE' template // parameter. These terms are also defined in section [17.6.3.1] of the C++11 // standard. Note that, in the context of a 'deque' instantiation, the // requirements apply specifically to the deque's entry type, 'value_type', // which is an alias for 'VALUE_TYPE'. // ///Glossary ///-------- //.. // Legend // ------ // 'X' - denotes an allocator-aware container type (e.g., 'deque') // 'T' - 'value_type' associated with 'X' // 'A' - type of the allocator used by 'X' // 'm' - lvalue of type 'A' (allocator) // 'p', - address ('T *') of uninitialized storage for a 'T' within an 'X' // 'rv' - rvalue of type (non-'const') 'T' // 'v' - rvalue or lvalue of type (possibly 'const') 'T' // 'args' - 0 or more arguments //.. // The following terms are used to more precisely specify the requirements on // template parameter types in function-level documentation. // //: *default-insertable*: 'T' has a default constructor. More precisely, 'T' //: is 'default-insertable' into 'X' means that the following expression is //: well-formed: //: 'allocator_traits<A>::construct(m, p)' //: //: *move-insertable*: 'T' provides a constructor that takes an rvalue of type //: (non-'const') 'T'. More precisely, 'T' is 'move-insertable' into 'X' //: means that the following expression is well-formed: //: 'allocator_traits<A>::construct(m, p, rv)' //: //: *copy-insertable*: 'T' provides a constructor that takes an lvalue or //: rvalue of type (possibly 'const') 'T'. More precisely, 'T' is //: 'copy-insertable' into 'X' means that the following expression is //: well-formed: //: 'allocator_traits<A>::construct(m, p, v)' //: //: *move-assignable*: 'T' provides an assignment operator that takes an rvalue //: of type (non-'const') 'T'. //: //: *copy-assignable*: 'T' provides an assignment operator that takes an lvalue //: or rvalue of type (possibly 'const') 'T'. //: //: *emplace-constructible*: 'T' is 'emplace-constructible' into 'X' from //: 'args' means that the following expression is well-formed: //: 'allocator_traits<A>::construct(m, p, args)' //: //: *erasable*: 'T' provides a destructor. More precisely, 'T' is 'erasable' //: from 'X' means that the following expression is well-formed: //: 'allocator_traits<A>::destroy(m, p)' //: //: *equality-comparable*: The type provides an equality-comparison operator //: that defines an equivalence relationship and is both reflexive and //: transitive. // ///Memory Allocation ///----------------- // The type supplied as a deque's 'ALLOCATOR' template parameter determines // how that deque will allocate memory. The 'deque' template supports // allocators meeting the requirements of the C++03 standard, in addition it // supports scoped-allocators derived from the 'bslma::Allocator' memory // allocation protocol. Clients intending to use 'bslma' style allocators // should use the template's default 'ALLOCATOR' type: The default type for the // 'ALLOCATOR' template parameter, 'bsl::allocator', provides a C++11 // standard-compatible adapter for a 'bslma::Allocator' object. // ///'bslma'-Style Allocators /// - - - - - - - - - - - - // If the (template parameter) type 'ALLOCATOR' of a 'deque' instantiation' is // 'bsl::allocator', then objects of that deque type will conform to the // standard behavior of a 'bslma'-allocator-enabled type. Such a deque // accepts an optional 'bslma::Allocator' argument at construction. If the // address of a 'bslma::Allocator' object is explicitly supplied at // construction, it is used to supply memory for the deque throughout its // lifetime; otherwise, the deque will use the default allocator installed at // the time of the deque's construction (see 'bslma_default'). In addition to // directly allocating memory from the indicated 'bslma::Allocator', a deque // supplies that allocator's address to the constructors of contained objects // of the (template parameter) 'VALUE_TYPE' if it defines the // 'bslma::UsesBslmaAllocator' trait. // ///Operations ///---------- // This section describes the run-time complexity of operations on instances // of 'deque': //.. // Legend // ------ // 'V' - (template parameter) 'VALUE_TYPE' of the deque // 'a', 'b' - two distinct objects of type 'deque<V>' // 'rv' - modifiable rvalue of type 'deque<V>' // 'n', 'm' - number of elements in 'a' and 'b', respectively // 'i' - valid index into the deque // 'k' - non-negative integer // 'al - an STL-style memory allocator // 'i1', 'i2' - two iterators defining a sequence of 'V' objects // 'il' - object of type 'std::initializer_list<V>' // 'lil' - length of 'il' // 'vt' - object of type 'VALUE_TYPE' // 'rvt' - modifiable rvalue of type 'VALUE_TYPE' // 'p1', 'p2' - two 'const_iterator's belonging to 'a' // 'distance(i1, i2)' - number of elements in the range '[i1 .. i2)' // 'minHalf(p1)' - 'min(distance(a.begin(), p1), distance(p1, a.end()))' // 'args' - 0 or more arguments // // |-----------------------------------------+-------------------------------| // | Operation | Complexity | // |=========================================+===============================| // | deque<V> a (default construction) | O[1] | // | deque<V> a(al) | | // |-----------------------------------------+-------------------------------| // | deque<V> a(b) (copy construction) | O[n] | // | deque<V> a(b, al) | | // |-----------------------------------------+-------------------------------| // | deque<V> a(rv) (move construction) | O[1] if 'a' and 'rv' use the | // | deque<V> a(rv, al) | same allocator; O[n] otherwise| // |-----------------------------------------+-------------------------------| // | deque<V> a(k) | O[k] | // | deque<V> a(k, al) | | // |-----------------------------------------+-------------------------------| // | deque<V> a(k, vt) | O[k] | // | deque<V> a(k, vt, al) | | // |-----------------------------------------+-------------------------------| // | deque<V> a(i1, i2) | O[distance(i1, i2)] | // | deque<V> a(i1, i2, al) | | // |-----------------------------------------+-------------------------------| // | deque<V> a(il) | O[lil] | // | deque<V> a(il, al) | | // |-----------------------------------------+-------------------------------| // | a.~deque<V>() (destruction) | O[n] | // |-----------------------------------------+-------------------------------| // | a.assign(k, vt) | O[k] | // |-----------------------------------------+-------------------------------| // | a.assign(i1, i2) | O[distance(i1, i2)] | // |-----------------------------------------+-------------------------------| // | a.assign(il) | O[lil] | // |-----------------------------------------+-------------------------------| // | get_allocator() | O[1] | // |-----------------------------------------+-------------------------------| // | a.begin(), a.end() | O[1] | // | a.cbegin(), a.cend() | | // | a.rbegin(), a.rend() | | // | a.crbegin(), a.crend() | | // |-----------------------------------------+-------------------------------| // | a.size() | O[1] | // |-----------------------------------------+-------------------------------| // | a.max_size() | O[1] | // |-----------------------------------------+-------------------------------| // | a.resize(k) | O[k] | // | a.resize(k, vt) | | // |-----------------------------------------+-------------------------------| // | a.empty() | O[1] | // |-----------------------------------------+-------------------------------| // | a.reserve(k) | O[k] | // |-----------------------------------------+-------------------------------| // | a.shrink_to_fit() | O[n] | // |-----------------------------------------+-------------------------------| // | a[i] | O[1] | // |-----------------------------------------+-------------------------------| // | a.at(i) | O[1] | // |-----------------------------------------+-------------------------------| // | a.front() | O[1] | // |-----------------------------------------+-------------------------------| // | a.back() | O[1] | // |-----------------------------------------+-------------------------------| // | a.push_back(vt) | O[1] | // | a.push_front(vt) | | // |-----------------------------------------+-------------------------------| // | a.push_back(rvt) | O[1] | // | a.push_front(rvt) | | // |-----------------------------------------+-------------------------------| // | a.pop_back() | O[1] | // | a.pop_front() | | // |-----------------------------------------+-------------------------------| // | a.emplace_back(args) | O[1] | // | a.emplace_front(args) | | // |-----------------------------------------+-------------------------------| // | a.emplace(p1, args) | O[1 + minHalf(p1)] | // |-----------------------------------------+-------------------------------| // | a.insert(p1, vt) | O[1 + minHalf(p1)] | // |-----------------------------------------+-------------------------------| // | a.insert(p1, rvt) | O[1 + minHalf(p1)] | // |-----------------------------------------+-------------------------------| // | a.insert(p1, k, vt) | O[k + minHalf(p1)] | // |-----------------------------------------+-------------------------------| // | a.insert(p1, i1, i2) | O[distance(i1, i2) | // | | + minHalf(p1)] | // |-----------------------------------------+-------------------------------| // | a.insert(p1, il) | O[lil + minHalf(p1)] | // |-----------------------------------------+-------------------------------| // | a.erase(p1) | O[1 + minHalf(p1)] | // |-----------------------------------------+-------------------------------| // | a.erase(p1, p2) | O[distance(p1, p2) | // | | + min(distance(a.begin, p1), | // | | distance(p2, a.end())] | // |-----------------------------------------+-------------------------------| // | a.swap(b), swap(a, b) | O[1] if 'a' and 'b' use the | // | | same allocator; O[n + m] | // | | otherwise | // |-----------------------------------------+-------------------------------| // | a.clear() | O[n] | // |-----------------------------------------+-------------------------------| // | a = b; (copy assignment) | O[n] | // |-----------------------------------------+-------------------------------| // | a = rv; (move assignment) | O[1] if 'a' and 'rv' use the | // | | same allocator; O[n] otherwise| // |-----------------------------------------+-------------------------------| // | a = il; | O[lil] | // |-----------------------------------------+-------------------------------| // | a == b, a != b | O[n] | // |-----------------------------------------+-------------------------------| // | a < b, a <= b, a > b, a >= b | O[n] | // |-----------------------------------------+-------------------------------| //.. // ///Exceptional Behavior ///-------------------- // Since this component is below the BSL STL, we centralize all the exceptional // behavior into a 'bslstl::StdExceptUtil' class, which has a dual purpose: // //: o Remove the dependency of this header on the '<exception>' header, so that //: this implementation can offer an exception handler with the native //: exceptions, and so that all the C-strings may be defined in a single //: library ('bsl') and not in all the translation units including this //: header. //: //: o Allow installation of exception handlers at a higher level to throw BSL //: STL exceptions (which differ from the native exceptions) and thus //: establish a full standard compliance for this component when used as //: 'bsl::deque' in the BSL STL. // ///Usage ///----- // In this section we show intended usage of this component. // ///Example 1: Using a 'deque' to Implement a Laundry Queue ///- - - - - - - - - - - - - - - - - - - - - - - - - - - - // Suppose we want to define a class to maintain a process queue of names of // customers who are dropping off their laundry at a drop-off laundry service. // We can accomplish this by defining a new class characterizing a // laundry-process queue that uses 'bsl::deque' in its implementation. // // The process queue provides two methods, 'push' and 'expeditedPush', for // inserting names of customers onto the queue. When calling the 'push' // method, the customer's name will be inserted at the back of the queue -- his // laundry will be done after the laundry of customers previously on the queue. // The 'expeditedPush' method is reserved for customers who have bribed the // merchant for expedited service. When calling the 'expeditedPush' method, // the customer's name will be inserted onto the front of the queue -- his // laundry will be done before customers previously on the queue. // // When the workers are ready to do some laundry, they call the 'next' method // of the queue, which returns the name of the customer whose laundry is to be // done next. For brevity of the usage example, we do not show how customers // are track while or after their laundry is being done. // // In addition, the laundry queue also provides the 'find' method, which // returns a 'bool' to indicate whether a given customer is still in the queue. // // First, we declare a class 'LaundryQueue' based on a deque, to store names of // customers at a drop-off laundry: //.. // class LaundryQueue { // // This 'class' keeps track of customers enqueued to have their laundry // // done by a laundromat. // // // DATA // bsl::deque<bsl::string> d_queue; // // public: // // CREATORS // LaundryQueue(bslma::Allocator *basicAllocator = 0); // // Create a 'LaundryQueue' object using the specified // // 'basicAllocator'. If 'basicAllocator' is not provided, use the // // default allocator. // // // MANIPULATORS // void push(const bsl::string& customerName); // // Add the specified 'customerName' to the back of the laundry // // queue. // // void expeditedPush(const bsl::string& customerName); // // Add the specified 'customerName' to the laundry queue at the // // front. // // bsl::string next(); // // Return the name from the front of the queue, removing it from // // the queue. If the queue is empty, return '(* empty *)' which is // // not a valid name for a customer. // // // ACCESSORS // bool find(const bsl::string& customerName); // // Return 'true' if 'customerName' is in the queue, and 'false' // // otherwise. // }; //.. // Then, we define the implementation of the methods of 'LaundryQueue' //.. // // CREATORS // LaundryQueue::LaundryQueue(bslma::Allocator *basicAllocator) // : d_queue(basicAllocator) // { // // Note that the allocator is propagated to the underlying 'deque', // // which will use the default allocator is '0 == basicAllocator'. // } // // // MANIPULATORS // void LaundryQueue::push(const bsl::string& customerName) // { // d_queue.push_back(customerName); // note constant time // } // // void LaundryQueue::expeditedPush(const bsl::string& customerName) // { // d_queue.push_front(customerName); // note constant time // } // // bsl::string LaundryQueue::next() // { // if (d_queue.empty()) { // return "(* empty *)"; // } // // bsl::string ret = d_queue.front(); // note constant time // // d_queue.pop_front(); // note constant time // // return ret; // } // // // ACCESSORS // bool LaundryQueue::find(const bsl::string& customerName) // { // // Note 'd_queue.empty() || d_queue[0] == d_queue.front()' // // for (size_t i = 0; i < d_queue.size(); ++i) { // if (customerName == d_queue[i]) { // note '[]' is constant time // return true; // } // } // // return false; // } //.. #include <bslscm_version.h> #include <bslstl_algorithm.h> #include <bslstl_iterator.h> #include <bslstl_iteratorutil.h> #include <bslstl_randomaccessiterator.h> #include <bslstl_stdexceptutil.h> #include <bslalg_containerbase.h> #include <bslalg_dequeimputil.h> #include <bslalg_dequeiterator.h> #include <bslalg_dequeprimitives.h> #include <bslalg_rangecompare.h> #include <bslalg_swaputil.h> #include <bslalg_typetraithasstliterators.h> #include <bslma_allocatortraits.h> #include <bslma_destructionutil.h> #include <bslma_isstdallocator.h> #include <bslma_stdallocator.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_assert.h> #include <bslmf_isconvertible.h> #include <bslmf_issame.h> #include <bslmf_matchanytype.h> #include <bslmf_matcharithmetictype.h> #include <bslmf_movableref.h> #include <bslmf_nil.h> #include <bslmf_typeidentity.h> #include <bslmf_util.h> // 'forward(V)' #include <bsls_assert.h> #include <bsls_compilerfeatures.h> #include <bsls_keyword.h> #include <bsls_performancehint.h> #include <bsls_util.h> // 'forward<T>(V)' #include <cstring> #if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) #include <initializer_list> #endif #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <bsls_nativestd.h> #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <stdexcept> #endif #if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // Include version that can be compiled with C++03 // Generated on Thu Oct 21 10:11:37 2021 // Command line: sim_cpp11_features.pl bslstl_deque.h # define COMPILING_BSLSTL_DEQUE_H # include <bslstl_deque_cpp03.h> # undef COMPILING_BSLSTL_DEQUE_H #else namespace bsl { template <class VALUE_TYPE, class ALLOCATOR> class Deque_BlockCreator; template <class VALUE_TYPE, class ALLOCATOR> class Deque_BlockProctor; template <class VALUE_TYPE, class ALLOCATOR> class Deque_ClearGuard; template <class VALUE_TYPE, class ALLOCATOR> class Deque_Guard; // ================================ // struct Deque_BlockLengthCalcUtil // ================================ template <class VALUE_TYPE> struct Deque_BlockLengthCalcUtil { // This 'struct' provides a namespace for the calculation of block length // (the number of elements per block within a 'deque'). This ensures that // each block in the deque can hold at least 16 elements. // TYPES enum { DEFAULT_BLOCK_SIZE = 200, // number of bytes per block BLOCK_LENGTH = (16 * sizeof(VALUE_TYPE) >= DEFAULT_BLOCK_SIZE) ? 16 : (DEFAULT_BLOCK_SIZE / sizeof(VALUE_TYPE)) // number of elements per block }; }; // ================= // struct Deque_Util // ================= struct Deque_Util { // This 'struct' provides a namespace to implement the 'swap' member // function of 'deque<VALUE_TYPE, ALLOCATOR>'. This function can be // implemented irrespective of the 'VALUE_TYPE' or 'ALLOCATOR' template // parameters, which is why we implement it in this non-parameterized, // non-inlined utility. // CLASS METHODS static void move(void *dst, void *src); // Assign the value of the specified 'dst' deque to that of the // specified 'src' deque, and reset the 'src' deque to a raw state. static void swap(void *a, void *b); // Exchange the value of the specified 'a' deque with that of the // specified 'b' deque. }; // ================ // class Deque_Base // ================ template <class VALUE_TYPE> class Deque_Base { // This class describes the basic layout for a deque class. It is // important that this class has the same layout as the deque class // implementation. It is parameterized by 'VALUE_TYPE' only and implements // the portion of 'bsl::deque' that does not need to know about its // (template parameter) type 'ALLOCATOR' (in order to generate shorter // debug strings). Note that this class must have the same layout as // 'Deque_Imp' (see implementation file). // PRIVATE TYPES enum { BLOCK_LENGTH = Deque_BlockLengthCalcUtil<VALUE_TYPE>::BLOCK_LENGTH }; typedef BloombergLP::bslalg::DequeImpUtil<VALUE_TYPE, BLOCK_LENGTH> Imp; typedef typename Imp::Block Block; typedef typename Imp::BlockPtr BlockPtr; typedef BloombergLP::bslalg::DequeIterator<VALUE_TYPE, BLOCK_LENGTH> IteratorImp; typedef BloombergLP:: bslstl::RandomAccessIterator<VALUE_TYPE, IteratorImp> Iterator; typedef BloombergLP:: bslstl::RandomAccessIterator<const VALUE_TYPE, IteratorImp> ConstIterator; public: // PUBLIC TYPES typedef VALUE_TYPE& reference; typedef const VALUE_TYPE& const_reference; typedef Iterator iterator; typedef ConstIterator const_iterator; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef VALUE_TYPE value_type; // For consistent behavior on all compilers, we must 'bsl::'-qualify // 'reverse_iterator'. (For most compilers, 'reverse_iterator' is in // namespace 'std', and NOT in namespace 'bsl'. Hence, we need to // actively look into a different namespace to find the iterator. However, // on Solaris we explicitly provide a 'reverse_iterator' implementation, IN // namespace 'bsl', to replace their broken one. See 'bslstl_iterator.h'.) typedef bsl::reverse_iterator<Iterator> reverse_iterator; typedef bsl::reverse_iterator<ConstIterator> const_reverse_iterator; protected: // PROTECTED DATA BlockPtr *d_blocks_p; // array of pointer to blocks (owned) std::size_t d_blocksLength; // length of 'd_blocks_p' array IteratorImp d_start; // iterator to first element IteratorImp d_finish; // iterator to one past last element public: // MANIPULATORS // *** iterators *** iterator begin() BSLS_KEYWORD_NOEXCEPT; // Return an iterator providing modifiable access to the first element // in this deque, and the past-the-end iterator if this deque is empty. iterator end() BSLS_KEYWORD_NOEXCEPT; // Return the past-the-end (forward) iterator providing modifiable // access to this deque. reverse_iterator rbegin() BSLS_KEYWORD_NOEXCEPT; // Return a reverse iterator providing modifiable access to the last // element in this deque, and the past-the-end reverse iterator if this // deque is empty. reverse_iterator rend() BSLS_KEYWORD_NOEXCEPT; // Return the past-the-end reverse iterator providing modifiable access // to this deque. // *** element access *** reference operator[](size_type position); // Return a reference providing modifiable access to the element at the // specified 'position' in this deque. The behavior is undefined // unless 'position < size()'. reference at(size_type position); // Return a reference providing modifiable access to the element at the // specified 'position' in this deque. Throw a 'std::out_of_range' // exception if 'position >= size()'. reference front(); // Return a reference providing modifiable access to the first element // in this deque. The behavior is undefined unless this deque is not // empty. reference back(); // Return a reference providing modifiable access to the last element // in this deque. The behavior is undefined unless this deque is not // empty. // ACCESSORS // *** iterators *** const_iterator begin() const BSLS_KEYWORD_NOEXCEPT; const_iterator cbegin() const BSLS_KEYWORD_NOEXCEPT; // Return an iterator providing non-modifiable access to the first // element in this deque, and the past-the-end iterator if this deque // is empty. const_iterator end() const BSLS_KEYWORD_NOEXCEPT; const_iterator cend() const BSLS_KEYWORD_NOEXCEPT; // Return the past-the-end (forward) iterator providing non-modifiable // access to this deque. const_reverse_iterator rbegin() const BSLS_KEYWORD_NOEXCEPT; const_reverse_iterator crbegin() const BSLS_KEYWORD_NOEXCEPT; // Return a reverse iterator providing non-modifiable access to the // last element in this deque, and the past-the-end reverse iterator if // this deque is empty. const_reverse_iterator rend() const BSLS_KEYWORD_NOEXCEPT; const_reverse_iterator crend() const BSLS_KEYWORD_NOEXCEPT; // Return the past-the-end reverse iterator providing non-modifiable // access to this deque. // *** capacity *** size_type size() const BSLS_KEYWORD_NOEXCEPT; // Return the number of elements contained by this deque. size_type capacity() const BSLS_KEYWORD_NOEXCEPT; // Return the sum of the current size of this deque plus the minimum // number of 'push_front' or 'push_back' operations needed to // invalidate iterators in this deque. Note that this method is not // part of the C++ standard. bool empty() const BSLS_KEYWORD_NOEXCEPT; // Return 'true' if this deque contains no elements, and 'false' // otherwise. // *** element access *** const_reference operator[](size_type position) const; // Return a reference providing non-modifiable access to the element at // the specified 'position' in this deque. The behavior is undefined // unless 'position < size()'. const_reference at(size_type position) const; // Return a reference providing non-modifiable access to the element at // the specified 'position' in this deque. Throw a 'std::out_of_range' // exception if 'position >= size()'. const_reference front() const; // Return a reference providing non-modifiable access to the first // element in this deque. The behavior is undefined unless this deque // is not empty. const_reference back() const; // Return a reference providing non-modifiable access to the last // element in this deque. The behavior is undefined unless this deque // is not empty. }; // =========== // class deque // =========== template <class VALUE_TYPE, class ALLOCATOR = allocator<VALUE_TYPE> > class deque : public Deque_Base<VALUE_TYPE> , private BloombergLP::bslalg::ContainerBase<ALLOCATOR> { // This class template provides an STL-compliant 'deque' that conforms to // the 'bslma::Allocator' model. For the requirements of a deque class, // consult the C++11 standard. In particular, this implementation offers // the general rules that: //: 1 A call to any method that would result in a deque having a size //: greater than the value returned by 'max_size' triggers a call to //: 'bslstl::StdExceptUtil::throwLengthError'. //: //: 2 A call to an 'at' method that attempts to access a position //: outside of the valid range of a deque triggers a call to //: 'bslstl::StdExceptUtil::throwOutOfRange'. // // Note that portions of the standard methods are implemented in // 'Deque_Base', which is parameterized on only 'VALUE_TYPE' in order to // generate smaller debug strings. // // This class: //: o supports a complete set of *value-semantic* operations //: o except for 'BDEX' serialization //: o is *exception-neutral* //: o is *alias-safe* //: o is 'const' *thread-safe* // For terminology see {'bsldoc_glossary'}. // // In addition, the following members offer a full guarantee of rollback: // if an exception is thrown during the invocation of 'insert', // 'push_front', or 'push_back' on a pre-existing object, the object is // left in a valid state and its value is unchanged. // PRIVATE TYPES enum { BLOCK_LENGTH = Deque_BlockLengthCalcUtil<VALUE_TYPE>::BLOCK_LENGTH }; typedef Deque_Base<VALUE_TYPE> Base; typedef BloombergLP::bslalg::ContainerBase<ALLOCATOR> ContainerBase; typedef BloombergLP::bslalg::DequeImpUtil<VALUE_TYPE, BLOCK_LENGTH> Imp; typedef typename Imp::Block Block; typedef typename Imp::BlockPtr BlockPtr; typedef BloombergLP::bslalg::DequeIterator<VALUE_TYPE, BLOCK_LENGTH> IteratorImp; typedef BloombergLP:: bslstl::RandomAccessIterator<VALUE_TYPE, IteratorImp> Iterator; typedef BloombergLP:: bslstl::RandomAccessIterator<const VALUE_TYPE, IteratorImp> ConstIterator; typedef Deque_BlockCreator<VALUE_TYPE, ALLOCATOR> BlockCreator; typedef Deque_BlockProctor<VALUE_TYPE, ALLOCATOR> BlockProctor; typedef Deque_ClearGuard<VALUE_TYPE, ALLOCATOR> ClearGuard; typedef Deque_Guard<VALUE_TYPE, ALLOCATOR> Guard; typedef BloombergLP::bslalg::DequePrimitives<VALUE_TYPE, BLOCK_LENGTH> DequePrimitives; typedef bsl::allocator_traits<ALLOCATOR> AllocatorTraits; typedef BloombergLP::bslmf::MovableRefUtil MoveUtil; // This typedef is a convenient alias for the utility associated with // movable references. enum RawInit { k_RAW_INIT = 0 }; // Special type (and value) used to create a "raw" deque, which has a // block length of 0, and null start and finish pointers. public: // PUBLIC TYPES typedef VALUE_TYPE& reference; typedef const VALUE_TYPE& const_reference; typedef Iterator iterator; typedef ConstIterator const_iterator; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef VALUE_TYPE value_type; typedef ALLOCATOR allocator_type; typedef typename AllocatorTraits::pointer pointer; typedef typename AllocatorTraits::const_pointer const_pointer; // As above, we must 'bsl::'-qualify 'reverse_iterator'. typedef bsl::reverse_iterator<Iterator> reverse_iterator; typedef bsl::reverse_iterator<ConstIterator> const_reverse_iterator; private: // STATIC ASSERTIONS BSLMF_ASSERT((is_same<reference, typename Base::reference>::value)); BSLMF_ASSERT((is_same<const_reference, typename Base::const_reference>::value)); // These need not necessarily be true as per the C++ standard, but are // safe assumptions for this implementation and allow us to implement // the element access within the 'Base' type (that is parameterized by // 'VALUE_TYPE' only). // PRIVATE CREATORS deque(RawInit, const allocator_type& allocator); // Create a "raw" deque (i.e., a deque that obeys the raw deque // invariants and is destructible) that uses the specified 'allocator' // to supply memory. The following holds for a raw deque: // '0 == d_blocks_p', '0 == d_blocksLength', and 'd_start' and // 'd_finish' are singular iterators (i.e., have null internal // pointers). Note that the constructed deque contains no allocated // storage. Also note that the purpose of a raw deque is to provide an // exception-safe repository for intermediate calculations. // PRIVATE MANIPULATORS template <class INPUT_ITERATOR> size_type privateAppend(INPUT_ITERATOR first, INPUT_ITERATOR last, std::input_iterator_tag); template <class INPUT_ITERATOR> size_type privateAppend(INPUT_ITERATOR first, INPUT_ITERATOR last, std::random_access_iterator_tag); // Append the elements in the range specified by '[first .. last)' to // this deque, and return the number of elements appended. The third // argument is used for overload resolution. The behavior is undefined // unless 'first' and 'last' refer to a sequence of valid values where // 'first' is at a position at or before 'last'. void privateAppendDefaultInsertable(size_type numElements); // Append the specified 'numElements' value-inititalized objects to // this deque. void privateAppendRaw(size_type numElements, const VALUE_TYPE& value); // Append the specified 'numElements' copies of the specified 'value' // to this deque. void privateInit(size_type numElements); // Initialize 'd_start' and 'd_finish' for eventual insertion of the // specified 'numElements' elements. After this method returns, this // object is fully constructed with memory allocated for 'numElements', // with all member variables obeying the class invariants, and with // size 0. The behavior is undefined unless this object is in a "raw" // state. Note that this method must not be called while constructing // this object (although a constructor may call it for a temporary // object). template <class INTEGER_TYPE> void privateInsertDispatch( const_iterator position, INTEGER_TYPE numElements, INTEGER_TYPE value, BloombergLP::bslmf::MatchArithmeticType, BloombergLP::bslmf::Nil); // Insert the specified 'numElements' copies of the specified 'value' // into this deque at the specified 'position'. This overload matches // 'privateInsert' when the second and third arguments are of the same // type which happens to be an integral type. The fourth and fifth // arguments are used for overload resolution only. template <class INPUT_ITERATOR> void privateInsertDispatch(const_iterator position, INPUT_ITERATOR first, INPUT_ITERATOR last, BloombergLP::bslmf::MatchAnyType, BloombergLP::bslmf::MatchAnyType); // Insert the elements in the range specified by '[first .. last)' into // this deque at the specified 'position'. The third and fourth // arguments are used for overload resolution only, so that this // function is not called if 'first' and 'last' are of integral type. // The behavior is undefined unless 'first' and 'last' refer to a // sequence of valid values where 'first' is at a position at or before // 'last'. template <class INPUT_ITERATOR> void privateInsert(const_iterator position, INPUT_ITERATOR first, INPUT_ITERATOR last, std::input_iterator_tag); // Specialized insertion for input iterators. template <class INPUT_ITERATOR> void privateInsert(const_iterator position, INPUT_ITERATOR first, INPUT_ITERATOR last, std::random_access_iterator_tag); // Specialized insertion for forward, bidirectional, and random-access // iterators. void privateJoinPrepend(deque *other); // Join '*this' and the specified 'other' deque into one. After the // join, '*this' contains the concatenated sequence, in order, of // '*other' and '*this' elements, and 'other is made a raw deque. void privateJoinAppend(deque *other); // Join '*this' and the specified 'other' deque into one. After the // join, '*this' contains the concatenated sequence, in order, of // '*this' and '*other' elements, and 'other is made a raw deque. template <class INPUT_ITERATOR> size_type privatePrepend(INPUT_ITERATOR first, INPUT_ITERATOR last, std::input_iterator_tag); template <class INPUT_ITERATOR> size_type privatePrepend(INPUT_ITERATOR first, INPUT_ITERATOR last, std::bidirectional_iterator_tag); template <class INPUT_ITERATOR> size_type privatePrepend(INPUT_ITERATOR first, INPUT_ITERATOR last, std::random_access_iterator_tag); // Prepend the elements in the range specified by '[first .. last)' to // this deque, and return the number of elements prepended. The third // argument is used for overload resolution only. The behavior is // undefined unless 'first' and 'last' refer to a sequence of valid // values where 'first' is at a position at or before 'last'. void privatePrependRaw(size_type numElements, const VALUE_TYPE& value); // Prepend the specified 'numElements' copies of the specified 'value' // to this deque. void privateSplit(deque *other, IteratorImp pos); // Split this deque in two such that after the split, '*this' contains // elements formerly in the range specified by '[d_start .. pos)' and // the specified 'other' deque contains elements formerly in the range // '[pos .. d_finish)'. The behavior is undefined unless 'other' is a // raw deque, i.e., the 'RawInit' constructor was used to create // 'other'. // FRIENDS template <class VALUE_TYPE2, class ALLOCATOR2> friend class Deque_BlockCreator; template <class VALUE_TYPE2, class ALLOCATOR2> friend class Deque_BlockProctor; template <class VALUE_TYPE2, class ALLOCATOR2> friend class Deque_Guard; public: // CREATORS // *** construct/copy/destroy *** deque(); explicit deque(const ALLOCATOR& basicAllocator); // Create an empty deque. Optionally specify a 'basicAllocator' used // to supply memory. If 'basicAllocator' is not supplied, a // default-constructed object of the (template parameter) type // 'ALLOCATOR' is used. If the type 'ALLOCATOR' is 'bsl::allocator' // (the default), then 'basicAllocator', if supplied, shall be // convertible to 'bslma::Allocator *'. If the type 'ALLOCATOR' is // 'bsl::allocator' and 'basicAllocator' is not supplied, the currently // installed default allocator is used. explicit deque(size_type numElements, const ALLOCATOR& basicAllocator = ALLOCATOR()); // Create a deque of the specified 'numElements' size whose every // element is value-initialized. Optionally specify a 'basicAllocator' // used to supply memory. If 'basicAllocator' is not supplied, a // default-constructed object of the (template parameter) type // 'ALLOCATOR' is used. If the type 'ALLOCATOR' is 'bsl::allocator' // (the default), then 'basicAllocator', if supplied, shall be // convertible to 'bslma::Allocator *'. If the type 'ALLOCATOR' is // 'bsl::allocator' and 'basicAllocator' is not supplied, the currently // installed default allocator is used. Throw 'bsl::length_error' if // 'numElements > max_size()'. This method requires that the (template // parameter) 'VALUE_TYPE' be 'default-insertable' into this deque (see // {Requirements on 'VALUE_TYPE'}). deque(size_type numElements, const VALUE_TYPE& value, const ALLOCATOR& basicAllocator = ALLOCATOR()); // Create a deque of the specified 'numElements' size whose every // element has the specified 'value'. Optionally specify a // 'basicAllocator' used to supply memory. If 'basicAllocator' is not // supplied, a default-constructed object of the (template parameter) // type 'ALLOCATOR' is used. If the type 'ALLOCATOR' is // 'bsl::allocator' (the default), then 'basicAllocator', if supplied, // shall be convertible to 'bslma::Allocator *'. If the type // 'ALLOCATOR' is 'bsl::allocator' and 'basicAllocator' is not // supplied, the currently installed default allocator is used. Throw // 'bsl::length_error' if 'numElements > max_size()'. This method // requires that the (template parameter) 'VALUE_TYPE' be // 'copy-insertable' into this deque (see {Requirements on // 'VALUE_TYPE'}). template <class INPUT_ITERATOR> deque(INPUT_ITERATOR first, INPUT_ITERATOR last, const ALLOCATOR& basicAllocator = ALLOCATOR()); // Create a deque initially containing copies of the values in the // range starting at the specified 'first' and ending immediately // before the specified 'last' iterators of the (template parameter) // type 'INPUT_ITERATOR'. Optionally specify a 'basicAllocator' used // to supply memory. If 'basicAllocator' is not supplied, a // default-constructed object of the (template parameter) type // 'ALLOCATOR' is used. If the type 'ALLOCATOR' is 'bsl::allocator' // (the default), then 'basicAllocator', if supplied, shall be // convertible to 'bslma::Allocator *'. If the type 'ALLOCATOR' is // 'bsl::allocator' and 'basicAllocator' is not supplied, the currently // installed default allocator is used. Throw 'bsl::length_error' if // the number of elements in '[first .. last)' exceeds the size // returned by 'max_size'. The (template parameter) type // 'INPUT_ITERATOR' shall meet the requirements of an input iterator // defined in the C++11 standard [input.iterators] providing access to // values of a type convertible to 'value_type', and 'value_type' must // be 'emplace-constructible' from '*i' into this deque, where 'i' is a // dereferenceable iterator in the range '[first .. last)' (see // {Requirements on 'VALUE_TYPE'}). The behavior is undefined unless // 'first' and 'last' refer to a sequence of valid values where 'first' // is at a position at or before 'last'. deque(const deque& original); // Create a deque that has the same value as the specified 'original' // object. Use the allocator returned by // 'bsl::allocator_traits<ALLOCATOR>:: // select_on_container_copy_construction(original.get_allocator())' to // supply memory. If the (template parameter) type 'ALLOCATOR' is // 'bsl::allocator' (the default), the currently installed default // allocator is used. This method requires that the (template // parameter) 'VALUE_TYPE' be 'copy-insertable' into this deque (see // {Requirements on 'VALUE_TYPE'}). deque(const deque& original, const typename type_identity<ALLOCATOR>::type& basicAllocator); // Create a deque that has the same value as the specified 'original' // object and that uses the specified 'basicAllocator' to supply // memory. This method requires that the (template parameter) // 'VALUE_TYPE' be 'copy-insertable' into this deque (see // {Requirements on 'VALUE_TYPE'}). Note that a 'bslma::Allocator *' // can be supplied for 'basicAllocator' if the (template parameter) // type 'ALLOCATOR' is 'bsl::allocator' (the default). deque(BloombergLP::bslmf::MovableRef<deque> original); // IMPLICIT // Create a deque having the same value as the specified 'original' // object by moving (in constant time) the contents of 'original' to // the new deque. The allocator associated with 'original' is // propagated for use in the newly-created deque. 'original' is left // in a valid but unspecified state. deque(BloombergLP::bslmf::MovableRef<deque> original, const typename type_identity<ALLOCATOR>::type& basicAllocator); // Create a deque having the same value as the specified 'original' // object that uses the specified 'basicAllocator' to supply memory. // The contents of 'original' are moved (in constant time) to the new // deque if 'basicAllocator == original.get_allocator()', and are move- // inserted (in linear time) using 'basicAllocator' otherwise. // 'original' is left in a valid but unspecified state. This method // requires that the (template parameter) 'VALUE_TYPE' be // 'move-insertable' into this deque (see {Requirements on // 'VALUE_TYPE'}). Note that a 'bslma::Allocator *' can be supplied // for 'basicAllocator' if the (template parameter) 'ALLOCATOR' is // 'bsl::allocator' (the default). #if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) deque(std::initializer_list<value_type> values, const ALLOCATOR& basicAllocator = ALLOCATOR()); // Create a deque and append each 'value_type' object in the specified // 'values' initializer list. Optionally specify a 'basicAllocator' // used to supply memory. If 'basicAllocator' is not supplied, a // default-constructed object of the (template parameter) type // 'ALLOCATOR' is used. If the type 'ALLOCATOR' is 'bsl::allocator' // (the default), then 'basicAllocator', if supplied, shall be // convertible to 'bslma::Allocator *'. If the type 'ALLOCATOR' is // 'bsl::allocator' and 'basicAllocator' is not supplied, the currently // installed default allocator is used. This method requires that the // (template parameter) 'VALUE_TYPE' be 'copy-insertable' into this // deque (see {Requirements on 'VALUE_TYPE'}). #endif ~deque(); // Destroy this object. // MANIPULATORS deque& operator=(const deque& rhs); // Assign to this object the value of the specified 'rhs' object, // propagate to this object the allocator of 'rhs' if the 'ALLOCATOR' // type has trait 'propagate_on_container_copy_assignment', and return // a reference providing modifiable access to this object. If an // exception is thrown, '*this' is left in a valid but unspecified // state. This method requires that the (template parameter) // 'VALUE_TYPE' be 'copy-assignable' and 'copy-insertable' into this // deque (see {Requirements on 'VALUE_TYPE'}). deque& operator=(BloombergLP::bslmf::MovableRef<deque> rhs) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION( AllocatorTraits::is_always_equal::value); // Assign to this object the value of the specified 'rhs' object, // propagate to this object the allocator of 'rhs' if the 'ALLOCATOR' // type has trait 'propagate_on_container_move_assignment', and return // a reference providing modifiable access to this object. The // contents of 'rhs' are moved (in constant time) to this deque if // 'get_allocator() == rhs.get_allocator()' (after accounting for the // aforementioned trait); otherwise, all elements in this deque are // either destroyed or move-assigned to and each additional element in // 'rhs' is move-inserted into this deque. 'rhs' is left in a valid // but unspecified state, and if an exception is thrown, '*this' is // left in a valid but unspecified state. This method requires that // the (template parameter) 'VALUE_TYPE' be 'move-assignable' and // 'move-insertable' into this deque (see {Requirements on // 'VALUE_TYPE'}). #if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) deque& operator=(std::initializer_list<value_type> values); // Assign to this object the value resulting from first clearing this // deque and then appending each 'value_type' object in the specified // 'values' initializer list; return a reference providing modifiable // access to this object. This method requires that the (template // parameter) 'VALUE_TYPE' be 'copy-insertable' into this deque (see // {Requirements on 'VALUE_TYPE'}). #endif template <class INPUT_ITERATOR> void assign(INPUT_ITERATOR first, INPUT_ITERATOR last); // Assign to this deque the values in the range starting at the // specified 'first' and ending immediately before the specified 'last' // iterators of the (template parameter) type 'INPUT_ITERATOR'. The // (template parameter) type 'INPUT_ITERATOR' shall meet the // requirements of an input iterator defined in the C++11 standard // [input.iterators] providing access to values of a type convertible // to 'value_type', and 'value_type' must be 'copy-assignable' and // 'emplace-constructible' from '*i' into this deque, where 'i' is a // dereferenceable iterator in the range '[first .. last)' (see // {Requirements on 'VALUE_TYPE'}). The behavior is undefined unless // 'first' and 'last' refer to a sequence of valid values where 'first' // is at a position at or before 'last'. void assign(size_type numElements, const VALUE_TYPE& value); // Assign to this object the value resulting from first clearing this // deque and then appending the specified 'numElements' having the // specified 'value'. This method requires that the (template // parameter) 'VALUE_TYPE' be 'copy-assignable' and 'copy-insertable' // into this deque (see {Requirements on 'VALUE_TYPE'}). #if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) void assign(std::initializer_list<value_type> values); // Assign to this object the value resulting from first clearing this // deque and then appending each 'value_type' object in the specified // 'values' initializer list. This method requires that the (template // parameter) 'VALUE_TYPE' be 'copy-assignable' and 'copy-insertable' // into this deque (see {Requirements on 'VALUE_TYPE'}). #endif // *** capacity *** void reserve(size_type numElements); // Change the capacity of this deque such that, after this method // returns, iterators remain valid provided that no more than the // specified 'numElements' objects are pushed to the front or back of // the deque after this call. If it is already possible to push // 'numElements' objects to either end of this deque without // invalidating iterators, this method has no effect. Note that // inserting elements into the deque may still incur memory allocation. // Also note that this method, if it has any effect, will invalidate // iterators initialized prior to the call. Also note that this method // is not part of the C++ standard. void resize(size_type newSize); void resize(size_type newSize, const VALUE_TYPE& value); // Change the size of this deque to the specified 'newSize'. Erase // 'size() - newSize' elements at the back if 'newSize < size()'. // Append 'newSize - size()' elements at the back having the optionally // specified 'value' if 'newSize > size()'; if 'value' is not // specified, value-initialized objects of the (template parameter) // 'VALUE_TYPE' are emplaced. This method has no effect if // 'newSize == size()'. Throw 'bsl::length_error' if // 'newSize > max_size()'. void shrink_to_fit(); // Minimize the memory used by this deque to the extent possible // without moving any contained elements. If an exception is thrown, // the value of this object is unchanged. Note that this method has no // effect on the memory used by individual elements of the (template // parameter) 'VALUE_TYPE'. // *** modifiers *** void push_front(const VALUE_TYPE& value); // Prepend to the front of this deque a copy of the specified 'value'. // This method offers full guarantee of rollback in case an exception // is thrown. This method requires that the (template parameter) // 'VALUE_TYPE' be 'copy-constructible' (see {Requirements on // 'VALUE_TYPE'}). void push_front(BloombergLP::bslmf::MovableRef<value_type> value); // Prepend to the front of this deque the specified move-insertable // 'value'. 'value' is left in a valid but unspecified state. If an // exception is thrown (other than by the move constructor of a // non-copy-insertable 'value_type'), this method has no effect. This // method requires that the (template parameter) 'VALUE_TYPE' be // 'move-insertable' into this deque (see {Requirements on // 'VALUE_TYPE'}). void push_back(const VALUE_TYPE& value); // Append to the back of this deque a copy of the specified 'value'. // This method offers full guarantee of rollback in case an exception // is thrown. This method requires that the (template parameter) // 'VALUE_TYPE' be 'copy-constructible' (see {Requirements on // 'VALUE_TYPE'}). void push_back(BloombergLP::bslmf::MovableRef<value_type> value); // Append to the back of this deque the specified move-insertable // 'value'. 'value' is left in a valid but unspecified state. If an // exception is thrown (other than by the move constructor of a // non-copy-insertable 'value_type'), this method has no effect. This // method requires that the (template parameter) 'VALUE_TYPE' be // 'move-insertable' into this deque (see {Requirements on // 'VALUE_TYPE'}). #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES template <class... Args> reference emplace_front(Args&&... arguments); // Prepend to the front of this deque a newly created 'value_type' // object, constructed by forwarding 'get_allocator()' (if required) // and the specified (variable number of) 'arguments' to the // corresponding constructor of 'value_type'. Return a reference // providing modifiable access to the inserted element. If an // exception is thrown (other than by the move constructor of a // non-copy-insertable 'value_type'), this method has no effect. This // method requires that the (template parameter) 'VALUE_TYPE' be // 'move-insertable' into this deque and 'emplace-constructible' from // 'arguments' (see // {Requirements on 'VALUE_TYPE'}). template <class... Args> reference emplace_back(Args&&... arguments); // Append to the back of this deque a newly created 'value_type' // object, constructed by forwarding 'get_allocator()' (if required) // and the specified (variable number of) 'arguments' to the // corresponding constructor of 'value_type'. Return a reference // providing modifiable access to the inserted element. If an // exception is thrown (other than by the move constructor of a // non-copy-insertable 'value_type'), this method has no effect. This // method requires that the (template parameter) 'VALUE_TYPE' be // 'move-insertable' into this deque and 'emplace-constructible' from // 'arguments' (see // {Requirements on 'VALUE_TYPE'}). #endif #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES template <class... Args> iterator emplace(const_iterator position, Args&&... arguments); // Insert at the specified 'position' in this deque a newly created // 'value_type' object, constructed by forwarding 'get_allocator()' (if // required) and the specified (variable number of) 'arguments' to the // corresponding constructor of 'value_type', and return an iterator // providing modifiable access to the newly created and inserted // element. If an exception is thrown (other than by the copy // constructor, move constructor, assignment operator, or move // assignment operator of 'value_type'), this method has no effect. // This method requires that the (template parameter) 'VALUE_TYPE' be // 'move-insertable' into this deque and 'emplace-constructible' from // 'arguments' (see {Requirements on 'VALUE_TYPE'}). The behavior is // undefined unless 'position' is an iterator in the range // '[cbegin() .. cend()]' (both endpoints included). #endif void pop_front(); // Erase the first element from this deque. The behavior is undefined // if this deque is empty. void pop_back(); // Erase the last element from this deque. The behavior is undefined // if this deque is empty. iterator insert(const_iterator position, const VALUE_TYPE& value); // Insert at the specified 'position' in this deque a copy of the // specified 'value', and return an iterator providing modifiable // access to the newly inserted element. This method offers full // guarantee of rollback in case an exception is thrown other than by // the 'VALUE_TYPE' copy constructor or assignment operator. This // method requires that the (template parameter) 'VALUE_TYPE' be // 'copy-insertable' into this deque (see {Requirements on // 'VALUE_TYPE'}). The behavior is undefined unless 'position' is an // iterator in the range '[cbegin() .. cend()] (both endpoints // included)'. iterator insert(const_iterator position, BloombergLP::bslmf::MovableRef<value_type> value); // Insert at the specified 'position' in this deque the specified // move-insertable 'value', and return an iterator providing modifiable // access to the newly inserted element. 'value' is left in a valid // but unspecified state. If an exception is thrown (other than by the // copy constructor, move constructor, assignment operator, or move // assignment operator of 'value_type'), this method has no effect. // This method requires that the (template parameter) 'VALUE_TYPE' be // 'move-insertable' into this deque (see {Requirements on // 'VALUE_TYPE'}). The behavior is undefined unless 'position' is an // iterator in the range '[cbegin() .. cend()]' (both endpoints // included). iterator insert(const_iterator position, size_type numElements, const VALUE_TYPE& value); // Insert at the specified 'position' in this deque the specified // 'numElements' copies of the specified 'value', and return an // iterator providing modifiable access to the first element in the // newly inserted sequence of elements. This method offers full // guarantee of rollback in case an exception is thrown other than by // the 'VALUE_TYPE' copy constructor or assignment operator. This // method requires that the (template parameter) 'VALUE_TYPE' be // 'copy-insertable' into this deque (see {Requirements on // 'VALUE_TYPE'}). The behavior is undefined unless 'position' is an // iterator in the range '[cbegin() .. cend()]' (both endpoints // included). template <class INPUT_ITERATOR> iterator insert(const_iterator position, INPUT_ITERATOR first, INPUT_ITERATOR last); // Insert at the specified 'position' in this deque the values in the // range starting at the specified 'first' and ending immediately // before the specified 'last' iterators of the (template parameter) // type 'INPUT_ITERATOR', and return an iterator providing modifiable // access to the first element in the newly inserted sequence of // elements. This method offers full guarantee of rollback in case an // exception is thrown other than by the 'VALUE_TYPE' copy constructor // or assignment operator. The (template parameter) type // 'INPUT_ITERATOR' shall meet the requirements of an input iterator // defined in the C++11 standard [input.iterators] providing access to // values of a type convertible to 'value_type', and 'value_type' must // be 'emplace-constructible' from '*i' into this deque, where 'i' is a // dereferenceable iterator in the range '[first .. last)' (see // {Requirements on 'VALUE_TYPE'}). The behavior is undefined unless // 'position' is an iterator in the range '[cbegin() .. cend()]' (both // endpoints included), and 'first' and 'last' refer to a sequence of // valid values where 'first' is at a position at or before 'last'. #if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) iterator insert(const_iterator position, std::initializer_list<value_type> values); // Insert at the specified 'position' in this deque the value of each // 'value_type' object in the specified 'values' initializer list, and // return an iterator providing modifiable access to the first element // in the newly inserted sequence of elements. This method offers full // guarantee of rollback in case an exception is thrown other than by // the 'VALUE_TYPE' copy constructor or assignment operator. This // method requires that the (template parameter) 'VALUE_TYPE' be // 'copy-insertable' into this deque (see {Requirements on // 'VALUE_TYPE'}). The behavior is undefined unless 'position' is an // iterator in the range '[cbegin() .. cend()]' (both endpoints // included). #endif iterator erase(const_iterator position); // Remove from this deque the element at the specified 'position', and // return an iterator providing modifiable access to the element // immediately following the removed element, or the position returned // by the method 'end' if the removed element was the last in the // sequence. The behavior is undefined unless 'position' is an // iterator in the range '[cbegin() .. cend())'. iterator erase(const_iterator first, const_iterator last); // Remove from this deque the sequence of elements starting at the // specified 'first' position and ending before the specified 'last' // position, and return an iterator providing modifiable access to the // element immediately following the last removed element, or the // position returned by the method 'end' if the removed elements were // last in the sequence. The behavior is undefined unless 'first' is // an iterator in the range '[cbegin() .. cend()]' (both endpoints // included) and 'last' is an iterator in the range // '[first .. cend()]' (both endpoints included). void swap(deque<VALUE_TYPE, ALLOCATOR>& other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION( AllocatorTraits::is_always_equal::value); // Exchange the value of this object with that of the specified 'other' // object; also exchange the allocator of this object with that of // 'other' if the (template parameter) type 'ALLOCATOR' has the // 'propagate_on_container_swap' trait, and do not modify either // allocator otherwise. This method provides the no-throw // exception-safety guarantee. This operation has 'O[1]' complexity if // either this object was created with the same allocator as 'other' or // 'ALLOCATOR' has the 'propagate_on_container_swap' trait; otherwise, // it has 'O[n + m]' complexity, where 'n' and 'm' are the number of // elements in this object and 'other', respectively. Note that this // method's support for swapping objects created with different // allocators when 'ALLOCATOR' does not have the // 'propagate_on_container_swap' trait is a departure from the // C++ Standard. void clear() BSLS_KEYWORD_NOEXCEPT; // Remove all elements from this deque making its size 0. Note that // although this deque is empty after this method returns, it preserves // the same capacity it had before the method was called. // ACCESSORS // *** construct/copy/destroy *** allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT; // Return the allocator used by this deque to supply memory. size_type max_size() const BSLS_KEYWORD_NOEXCEPT; // Return the maximum possible size of this deque. Note that this is a // theoretical maximum (such as the maximum value that can be held by // 'size_type'). Also note that any request to create or enlarge a // deque to a size greater than 'max_size()' is guaranteed to raise a // 'bsl::length_error' exception. }; #ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD // CLASS TEMPLATE DEDUCTION GUIDES template < class SIZE_TYPE, class VALUE, class ALLOC, class DEFAULT_ALLOCATOR = bsl::allocator<VALUE>, class = bsl::enable_if_t< bsl::is_convertible_v< SIZE_TYPE, typename bsl::allocator_traits<DEFAULT_ALLOCATOR>::size_type>>, class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>> > deque(SIZE_TYPE, VALUE, ALLOC *) -> deque<VALUE>; // Deduce the template parameter 'VALUE' from the corresponding parameter // supplied to the constructor of 'deque'. This deduction guide does not // participate unless the supplied allocator is convertible to // 'bsl::allocator<VALUE>'. template < class INPUT_ITERATOR, class VALUE = typename BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR> > deque(INPUT_ITERATOR, INPUT_ITERATOR) -> deque<VALUE>; // Deduce the template parameter 'VALUE' from the 'value_type' of the // iterators supplied to the constructor of 'deque'. template< class INPUT_ITERATOR, class ALLOCATOR, class VALUE = typename BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR>, class = bsl::enable_if_t<bsl::IsStdAllocator_v<ALLOCATOR>>> deque(INPUT_ITERATOR, INPUT_ITERATOR, ALLOCATOR) -> deque<VALUE, ALLOCATOR>; // Deduce the template parameter 'VALUE' from the 'value_type' of the // iterators supplied to the constructor of 'deque'. This deduction guide // does not participate unless the supplied allocator meets the // requirements of a standard allocator. template< class INPUT_ITERATOR, class ALLOC, class VALUE = typename BloombergLP::bslstl::IteratorUtil::IterVal_t<INPUT_ITERATOR>, class DEFAULT_ALLOCATOR = bsl::allocator<VALUE>, class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>> > deque(INPUT_ITERATOR, INPUT_ITERATOR, ALLOC *) -> deque<VALUE>; // Deduce the template parameter 'VALUE' from the 'value_type' of the // iterators supplied to the constructor of 'deque'. This deduction guide // does not participate unless the supplied allocator is convertible to // 'bsl::allocator<VALUE>'. template< class VALUE, class ALLOC, class DEFAULT_ALLOCATOR = bsl::allocator<VALUE>, class = bsl::enable_if_t<bsl::is_convertible_v<ALLOC *, DEFAULT_ALLOCATOR>> > deque(std::initializer_list<VALUE>, ALLOC *) -> deque<VALUE>; // Deduce the template parameter 'VALUE' from the 'value_type' of the // initializer_list supplied to the constructor of 'deque'. This deduction // guide does not participate unless the supplied allocator is convertible // to 'bsl::allocator<VALUE>'. #endif // FREE OPERATORS template <class VALUE_TYPE, class ALLOCATOR> bool operator==(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs); // Return 'true' if the specified 'lhs' and 'rhs' objects have the same // value, and 'false' otherwise. Two 'deque' objects 'lhs' and 'rhs' have // the same value if they have the same number of elements, and each // element in the ordered sequence of elements of 'lhs' has the same value // as the corresponding element in the ordered sequence of elements of // 'rhs'. This method requires that the (template parameter) type // 'VALUE_TYPE' be 'equality-comparable' (see {Requirements on // 'VALUE_TYPE'}). template <class VALUE_TYPE, class ALLOCATOR> bool operator!=(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs); // Return 'true' if the specified 'lhs' and 'rhs' objects do not have the // same value, and 'false' otherwise. Two 'deque' objects 'lhs' and 'rhs' // do not have the same value if they do not have the same number of // elements, or some element in the ordered sequence of elements of 'lhs' // does not have the same value as the corresponding element in the ordered // sequence of elements of 'rhs'. This method requires that the (template // parameter) type 'VALUE_TYPE' be 'equality-comparable' (see {Requirements // on 'VALUE_TYPE'}). template <class VALUE_TYPE, class ALLOCATOR> bool operator<(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs); // Return 'true' if the value of the specified 'lhs' deque is // lexicographically less than that of the specified 'rhs' deque, and // 'false' otherwise. Given iterators 'i' and 'j' over the respective // sequences '[lhs.begin() .. lhs.end())' and '[rhs.begin() .. rhs.end())', // the value of deque 'lhs' is lexicographically less than that of deque // 'rhs' if 'true == *i < *j' for the first pair of corresponding iterator // positions where '*i < *j' and '*j < *i' are not both 'false'. If no // such corresponding iterator position exists, the value of 'lhs' is // lexicographically less than that of 'rhs' if 'lhs.size() < rhs.size()'. // This method requires that 'operator<', inducing a total order, be // defined for 'value_type'. template <class VALUE_TYPE, class ALLOCATOR> bool operator>(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs); // Return 'true' if the value of the specified 'lhs' deque is // lexicographically greater than that of the specified 'rhs' deque, and // 'false' otherwise. The value of deque 'lhs' is lexicographically // greater than that of deque 'rhs' if 'rhs' is lexicographically less than // 'lhs' (see 'operator<'). This method requires that 'operator<', // inducing a total order, be defined for 'value_type'. Note that this // operator returns 'rhs < lhs'. template <class VALUE_TYPE, class ALLOCATOR> bool operator<=(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs); // Return 'true' if the value of the specified 'lhs' deque is // lexicographically less than or equal to that of the specified 'rhs' // deque, and 'false' otherwise. The value of deque 'lhs' is // lexicographically less than or equal to that of deque 'rhs' if 'rhs' is // not lexicographically less than 'lhs' (see 'operator<'). This method // requires that 'operator<', inducing a total order, be defined for // 'value_type'. Note that this operator returns '!(rhs < lhs)'. template <class VALUE_TYPE, class ALLOCATOR> bool operator>=(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs); // Return 'true' if the value of the specified 'lhs' deque is // lexicographically greater than or equal to that of the specified 'rhs' // deque, and 'false' otherwise. The value of deque 'lhs' is // lexicographically greater than or equal to that of deque 'rhs' if 'lhs' // is not lexicographically less than 'rhs' (see 'operator<'). This method // requires that 'operator<', inducing a total order, be defined for // 'value_type'. Note that this operator returns '!(lhs < rhs)'. // FREE FUNCTIONS template <class VALUE_TYPE, class ALLOCATOR, class BDE_OTHER_TYPE> typename deque<VALUE_TYPE, ALLOCATOR>::size_type erase(deque<VALUE_TYPE, ALLOCATOR>& deq, const BDE_OTHER_TYPE& value); // Erase all the elements in the specified deque 'deq' that compare equal // to the specified 'value'. Return the number of elements erased. template <class VALUE_TYPE, class ALLOCATOR, class PREDICATE> typename deque<VALUE_TYPE, ALLOCATOR>::size_type erase_if(deque<VALUE_TYPE, ALLOCATOR>& deq, PREDICATE predicate); // Erase all the elements in the specified deque 'deq' that satisfy the // specified predicate 'predicate'. Return the number of elements erased. template <class VALUE_TYPE, class ALLOCATOR> void swap(deque<VALUE_TYPE, ALLOCATOR>& a, deque<VALUE_TYPE, ALLOCATOR>& b) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(BSLS_KEYWORD_NOEXCEPT_OPERATOR( a.swap(b))); // Exchange the value of the specified 'a' object with that of the // specified 'b' object; also exchange the allocator of 'a' with that of // 'b' if the (template parameter) type 'ALLOCATOR' has the // 'propagate_on_container_swap' trait, and do not modify either allocator // otherwise. This function provides the no-throw exception-safety // guarantee. This operation has 'O[1]' complexity if either 'a' was // created with the same allocator as 'b' or 'ALLOCATOR' has the // 'propagate_on_container_swap' trait; otherwise, it has 'O[n + m]' // complexity, where 'n' and 'm' are the number of elements in 'a' and 'b', // respectively. Note that this function's support for swapping objects // created with different allocators when 'ALLOCATOR' does not have the // 'propagate_on_container_swap' trait is a departure from the C++ // Standard. // ======================== // class Deque_BlockCreator // ======================== template <class VALUE_TYPE, class ALLOCATOR> class Deque_BlockCreator { // This class allocates blocks at the front or back of a deque and // tentatively adds them to the deque. It also keeps track of how many of // the newly allocated blocks have actually been used by the deque. The // destructor automatically frees any unused blocks (e.g., in case an // exception is thrown). // PRIVATE TYPES enum { BLOCK_LENGTH = Deque_BlockLengthCalcUtil<VALUE_TYPE>::BLOCK_LENGTH }; typedef BloombergLP::bslalg::DequeImpUtil<VALUE_TYPE, BLOCK_LENGTH> Imp; typedef typename Imp::Block Block; typedef typename Imp::BlockPtr BlockPtr; typedef std::size_t size_type; // DATA deque<VALUE_TYPE, ALLOCATOR> *d_deque_p; BlockPtr *d_boundary_p; private: // NOT IMPLEMENTED Deque_BlockCreator(const Deque_BlockCreator&); Deque_BlockCreator& operator=(const Deque_BlockCreator&); public: // CREATORS explicit Deque_BlockCreator(deque<VALUE_TYPE, ALLOCATOR> *deque); // Construct a block allocator for the specified 'deque'. ~Deque_BlockCreator(); // Free any blocks that have been allocated by this allocator but have // not yet been used by the deque. // MANIPULATORS void insertAtFront(size_type n); // Allocate the specified 'n' blocks at the front of the block array. // This method invalidates all iterators except 'd_deque_p->d_start' // and 'd_deque_p->d_finish'. void insertAtBack(size_type n); // Allocate the specified 'n' blocks at the back of the block array. // This method invalidates all iterators except 'd_deque_p->d_start' // and 'd_deque_p->d_finish'. BlockPtr *reserveBlockSlots(size_type numNewBlocks, bool atFront); // Make room for the specified 'numNewBlocks' pointers in the blocks // array. If the specified 'atFront' is 'true', then make room at the // front of the array, else make room at the back of the array. Return // a pointer to the insertion point, i.e., the point where new blocks // can be stored into the array, working backwards if 'atFront' is // 'true', or working forwards if 'atFront' is 'false'. This method // invalidates all iterators and updates 'd_deque_p->d_start' and // 'd_deque_p->d_finish'. void release(); // Relinquish control over any allocated blocks. The destructor will // do nothing following a call to this method. }; // ======================== // class Deque_BlockProctor // ======================== template <class VALUE_TYPE, class ALLOCATOR> class Deque_BlockProctor { // This class implements a proctor that, upon destruction and unless its // 'release' method has previously been invoked, deallocates empty blocks // at one end (i.e., front or back) of a proctored deque. The end at which // empty blocks are to be proctored is indicated by a flag supplied at // construction. See 'emplace' for a use case. // PRIVATE TYPES enum { BLOCK_LENGTH = Deque_BlockLengthCalcUtil<VALUE_TYPE>::BLOCK_LENGTH }; typedef BloombergLP::bslalg::DequeImpUtil<VALUE_TYPE, BLOCK_LENGTH> Imp; typedef typename Imp::BlockPtr BlockPtr; // DATA deque<VALUE_TYPE, ALLOCATOR> *d_deque_p; // proctored deque BlockPtr *d_boundary_p; // boundary of proctored // blocks bool d_atFront; // if 'true', proctor blocks // at the front of the deque; // otherwise, proctor blocks // at the block private: // NOT IMPLEMENTED Deque_BlockProctor(const Deque_BlockProctor&); Deque_BlockProctor& operator=(const Deque_BlockProctor&); public: // CREATORS Deque_BlockProctor(deque<VALUE_TYPE, ALLOCATOR> *deque, bool atFront); // Create a block proctor object to proctor blocks at one end (i.e., // front or back) of the specified 'deque' as indicated by the // specified 'atFront' flag. If 'atFront' is 'true', blocks at the // front of 'deque' are proctored; otherwise, blocks at the back of // 'deque' are proctored. ~Deque_BlockProctor(); // Destroy this block proctor, and deallocate empty blocks at the back // of the proctored deque as indicated by the 'atFront' flag supplied // at construction. If no deque is currently being managed, this // method has no effect. // MANIPULATORS void release(); // Release from management the deque currently managed by this proctor. // If no deque is currently being managed, this method has no effect. }; // ====================== // class Deque_ClearGuard // ====================== template <class VALUE_TYPE, class ALLOCATOR> class Deque_ClearGuard { // This class provides a proctor which, at destruction, calls 'clear' on // the deque supplied at construction, unless the guard has been released // prior. // PRIVATE TYPES typedef BloombergLP::bslalg::ContainerBase<ALLOCATOR> ContainerBase; // DATA deque<VALUE_TYPE, ALLOCATOR> *d_deque_p; // proctored object private: // NOT IMPLEMENTED Deque_ClearGuard(const Deque_ClearGuard&); Deque_ClearGuard& operator=(const Deque_ClearGuard&); public: // CREATORS explicit Deque_ClearGuard(deque<VALUE_TYPE, ALLOCATOR> *deque); // Create a clear guard object to proctor the specified 'deque'. ~Deque_ClearGuard(); // Destroy this guard, and call 'clear' on the deque supplied at // construction, unless 'release' has been called on this object. // MANIPULATORS void release(); // Release from management the deque proctored by this object. }; // ================= // class Deque_Guard // ================= template <class VALUE_TYPE, class ALLOCATOR> class Deque_Guard { // This class provides a proctor that maintains a count of the number of // elements constructed at the front or back of a deque, but not yet // committed to the deque's range of valid elements; if the count is // non-zero at destruction, the destructor destroys the elements in the // range '[d_deque_p->end() .. d_deque_p->end() + d_count)', or the range // '[d_deque_p->begin() - d_count .. d_deque_p->begin())', depending on // whether this proctor guards the back or front. This guard is used to // undo element constructors in the event of an exception. It is up to the // client code to increment the count whenever a new element is constructed // and to decrement the count whenever 'd_start' or 'd_finish' of the // guarded deque is moved to incorporate more elements. // PRIVATE TYPES enum { BLOCK_LENGTH = Deque_BlockLengthCalcUtil<VALUE_TYPE>::BLOCK_LENGTH }; typedef BloombergLP::bslalg::DequeIterator<VALUE_TYPE, BLOCK_LENGTH> IteratorImp; typedef BloombergLP::bslalg::DequePrimitives<VALUE_TYPE, BLOCK_LENGTH> DequePrimitives; // DATA deque<VALUE_TYPE, ALLOCATOR> *d_deque_p; std::size_t d_count; bool d_isTail; private: // NOT IMPLEMENTED Deque_Guard(const Deque_Guard&); Deque_Guard& operator=(const Deque_Guard&); public: // CREATORS Deque_Guard(deque<VALUE_TYPE, ALLOCATOR> *deque, bool isTail); // Initializes object to guard 0 items from the specified 'deque'. // This guards either the tail or the head, as determined by the // specified 'isTail' boolean. ~Deque_Guard(); // Call the (template parameter) 'VALUE_TYPE' destructor on objects in // the range '[d.end() .. d.end() + count())' if 'isTail' was specified // as 'true' during construction, or // '[d.start() - count() .. d.start()]' if 'isTail' was specified as // 'false' during construction, where 'd' is the deque used to // construct this guard. // MANIPULATORS std::size_t operator++(); // Increment the count of this guard, and return the new count. std::size_t operator--(); // Decrement the count of this guard, and return the new count. void release(); // Set the count of this guard to 0. Note that this guard's destructor // will do nothing if count is not incremented again after this call. // ACCESSORS std::size_t count() const BSLS_KEYWORD_NOEXCEPT; // Return the current count maintained by this guard. IteratorImp begin() const BSLS_KEYWORD_NOEXCEPT; // Return a pointer after the first item in the guarded range. IteratorImp end() const BSLS_KEYWORD_NOEXCEPT; // Return a pointer after the last item in the guarded range. }; // ============================================================================ // TEMPLATE AND INLINE FUNCTION DEFINITIONS // ============================================================================ // See IMPLEMENTATION NOTES in the .cpp before modifying anything below. // ---------------- // class Deque_Base // ---------------- // MANIPULATORS template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::iterator Deque_Base<VALUE_TYPE>::begin() BSLS_KEYWORD_NOEXCEPT { return d_start; } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::iterator Deque_Base<VALUE_TYPE>::end() BSLS_KEYWORD_NOEXCEPT { return d_finish; } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::reverse_iterator Deque_Base<VALUE_TYPE>::rbegin() BSLS_KEYWORD_NOEXCEPT { return reverse_iterator(end()); } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::reverse_iterator Deque_Base<VALUE_TYPE>::rend() BSLS_KEYWORD_NOEXCEPT { return reverse_iterator(begin()); } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::reference Deque_Base<VALUE_TYPE>::operator[](size_type position) { BSLS_ASSERT_SAFE(position < size()); return *(begin() + position); } template <class VALUE_TYPE> typename Deque_Base<VALUE_TYPE>::reference Deque_Base<VALUE_TYPE>::at(size_type position) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(position >= size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwOutOfRange( "deque<...>::at(n): invalid position"); } return *(begin() + position); } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::reference Deque_Base<VALUE_TYPE>::front() { BSLS_ASSERT_SAFE(!empty()); return *d_start; } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::reference Deque_Base<VALUE_TYPE>::back() { BSLS_ASSERT_SAFE(!empty()); IteratorImp backIterator = d_finish; --backIterator; return *backIterator; } // ACCESSORS template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_iterator Deque_Base<VALUE_TYPE>::begin() const BSLS_KEYWORD_NOEXCEPT { return d_start; } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_iterator Deque_Base<VALUE_TYPE>::cbegin() const BSLS_KEYWORD_NOEXCEPT { return d_start; } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_iterator Deque_Base<VALUE_TYPE>::end() const BSLS_KEYWORD_NOEXCEPT { return d_finish; } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_iterator Deque_Base<VALUE_TYPE>::cend() const BSLS_KEYWORD_NOEXCEPT { return d_finish; } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_reverse_iterator Deque_Base<VALUE_TYPE>::rbegin() const BSLS_KEYWORD_NOEXCEPT { return const_reverse_iterator(end()); } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_reverse_iterator Deque_Base<VALUE_TYPE>::crbegin() const BSLS_KEYWORD_NOEXCEPT { return const_reverse_iterator(end()); } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_reverse_iterator Deque_Base<VALUE_TYPE>::rend() const BSLS_KEYWORD_NOEXCEPT { return const_reverse_iterator(begin()); } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_reverse_iterator Deque_Base<VALUE_TYPE>::crend() const BSLS_KEYWORD_NOEXCEPT { return const_reverse_iterator(begin()); } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::size_type Deque_Base<VALUE_TYPE>::size() const BSLS_KEYWORD_NOEXCEPT { return d_finish - d_start; } template <class VALUE_TYPE> typename Deque_Base<VALUE_TYPE>::size_type Deque_Base<VALUE_TYPE>::capacity() const BSLS_KEYWORD_NOEXCEPT { // 'ContainerBase::allocateN', which creates the 'd_blocks_p' array, does // not, in its contract, guarantee to initialize the array to 0. Since we // read these values, we have to make sure they're initialized to avoid // purify 'read before write' errors. Note that we initialize them to // null in which case they are not valid pointers, but we never dereference // them, and the pointer arithmetic we do on them will still work. if (d_start.blockPtr() > d_blocks_p) { d_blocks_p[0] = 0; } if (d_finish.blockPtr() < d_blocks_p + d_blocksLength - 1) { d_blocks_p[d_blocksLength - 1] = 0; } const IteratorImp first(d_blocks_p); // 'last' points to the empty slot at the end of the last block in // 'd_blocks_p', which might not actually be there. IteratorImp last(d_blocks_p + d_blocksLength - 1); last += BLOCK_LENGTH - 1; BSLS_ASSERT_SAFE(!(d_start < first)); // 'IteratorImp' has no '>=' BSLS_ASSERT_SAFE(!(last < d_finish)); const size_type frontCapacity = d_finish - first; const size_type backCapacity = last - d_start; // Return the min (we are below 'bsl_algorithm.h', so we have to do it by // hand). return frontCapacity < backCapacity ? frontCapacity : backCapacity; } template <class VALUE_TYPE> inline bool Deque_Base<VALUE_TYPE>::empty() const BSLS_KEYWORD_NOEXCEPT { return d_start == d_finish; } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_reference Deque_Base<VALUE_TYPE>::operator[](size_type position) const { BSLS_ASSERT_SAFE(position < size()); return *(begin() + position); } template <class VALUE_TYPE> typename Deque_Base<VALUE_TYPE>::const_reference Deque_Base<VALUE_TYPE>::at(size_type position) const { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(position >= size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwOutOfRange( "const deque<...>::at(n): invalid position"); } return *(begin() + position); } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_reference Deque_Base<VALUE_TYPE>::front() const { BSLS_ASSERT_SAFE(!empty()); return *d_start; } template <class VALUE_TYPE> inline typename Deque_Base<VALUE_TYPE>::const_reference Deque_Base<VALUE_TYPE>::back() const { BSLS_ASSERT_SAFE(!empty()); IteratorImp backIterator = d_finish; --backIterator; return *backIterator; } // ----------- // class deque // ----------- // PRIVATE CREATORS template <class VALUE_TYPE, class ALLOCATOR> inline deque<VALUE_TYPE, ALLOCATOR>::deque(RawInit, const ALLOCATOR& allocator) : Deque_Base<VALUE_TYPE>() , ContainerBase(allocator) { this->d_blocks_p = 0; } // PRIVATE MANIPULATORS template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> typename deque<VALUE_TYPE, ALLOCATOR>::size_type deque<VALUE_TYPE, ALLOCATOR>::privateAppend( INPUT_ITERATOR first, INPUT_ITERATOR last, std::random_access_iterator_tag) { BlockCreator newBlocks(this); Guard guard(this, true); const size_type numElements = bsl::distance(first, last); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( numElements > max_size() - this->size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::insert(pos,n,v): deque too big"); } for ( ; first != last; ++first) { IteratorImp insertPoint = guard.end(); // There must be room for the iterator to be incremented. Allocate new // block now if necessary. We cannot wait until after the new element // is constructed or else we won't be able to increment the guard right // away and there will be a window where an exception will cause a // resource leak. if (1 == insertPoint.remainingInBlock()) { newBlocks.insertAtBack(1); insertPoint = guard.end(); // 'insertAtBack(1)' invalidated // iterator } AllocatorTraits::construct(ContainerBase::allocator(), BSLS_UTIL_ADDRESSOF(*insertPoint), *first); ++guard; } this->d_finish += guard.count(); guard.release(); return numElements; } template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> typename deque<VALUE_TYPE, ALLOCATOR>::size_type deque<VALUE_TYPE, ALLOCATOR>::privateAppend(INPUT_ITERATOR first, INPUT_ITERATOR last, std::input_iterator_tag) { BlockCreator newBlocks(this); Guard guard(this, true); size_type numElements = 0; size_type maxNumElements = max_size() - this->size(); for ( ; first != last; ++first) { ++numElements; if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( numElements > maxNumElements)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::insert(pos,n,v): deque too big"); } IteratorImp insertPoint = guard.end(); // There must be room for the iterator to be incremented. Allocate new // block now if necessary. We cannot wait until after the new element // is constructed or else we won't be able to increment the guard right // away and there will be a window where an exception will cause a // resource leak. if (1 == insertPoint.remainingInBlock()) { newBlocks.insertAtBack(1); insertPoint = guard.end(); // 'insertAtBack(1)' invalidated // iterator } AllocatorTraits::construct(ContainerBase::allocator(), BSLS_UTIL_ADDRESSOF(*insertPoint), *first); ++guard; } this->d_finish += guard.count(); guard.release(); return numElements; } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::privateAppendDefaultInsertable( size_type numElements) { // Create new blocks at the back. In case an exception is thrown, any // unused blocks are returned to the allocator. size_type numNewBlocks = (this->d_finish.offsetInBlock() + numElements) / BLOCK_LENGTH; BlockCreator newBlocks(this); newBlocks.insertAtBack(numNewBlocks); DequePrimitives::valueInititalizeN(&this->d_finish, this->d_finish, numElements, ContainerBase::allocator()); } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::privateAppendRaw( size_type numElements, const VALUE_TYPE& value) { // Create new blocks at the back. In case an exception is thrown, any // unused blocks are returned to the allocator. size_type numNewBlocks = (this->d_finish.offsetInBlock() + numElements) / BLOCK_LENGTH; BlockCreator newBlocks(this); newBlocks.insertAtBack(numNewBlocks); DequePrimitives::uninitializedFillNBack(&this->d_finish, this->d_finish, numElements, value, ContainerBase::allocator()); } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::privateInit(size_type numElements) { size_type blocksLength = numElements / BLOCK_LENGTH + 1 + 2 * Imp::BLOCK_ARRAY_PADDING; // Allocate block pointer array. this->d_blocks_p = this->allocateN((BlockPtr *)0, blocksLength); this->d_blocksLength = blocksLength; // Allocate the first block and store its pointer into the array. Leave a // little room at the front and back of the array for growth. BlockPtr *firstBlockPtr = &this->d_blocks_p[Imp::BLOCK_ARRAY_PADDING]; *firstBlockPtr = this->allocateN((Block *)0, 1); // Calculate the offset into the first block such that 'n' elements will // leave equal space at the front of the first block and at the end of the // last block, remembering that the last element of the last block cannot // be used. Centering the elements reduces the chance that either // 'push_back' or 'push_front' will need to allocate a new block. In case // of an odd number of unused elements, slight preference is given to // 'push_back' over 'push_front'. const int offset = static_cast<int>( (BLOCK_LENGTH - 1 - numElements % BLOCK_LENGTH) / 2); // Initialize the begin and end iterators. this->d_start = this->d_finish = IteratorImp( firstBlockPtr, (*firstBlockPtr)->d_data + offset); } template <class VALUE_TYPE, class ALLOCATOR> template <class INTEGRAL_TYPE> inline void deque<VALUE_TYPE, ALLOCATOR>::privateInsertDispatch( const_iterator position, INTEGRAL_TYPE numElements, INTEGRAL_TYPE value, BloombergLP::bslmf::MatchArithmeticType, BloombergLP::bslmf::Nil) { insert(position, static_cast<size_type>(numElements), static_cast<VALUE_TYPE>(value)); } template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> void deque<VALUE_TYPE, ALLOCATOR>::privateInsertDispatch( const_iterator position, INPUT_ITERATOR first, INPUT_ITERATOR last, BloombergLP::bslmf::MatchAnyType, BloombergLP::bslmf::MatchAnyType) { typedef typename iterator_traits<INPUT_ITERATOR>::iterator_category Tag; if (first == last) { return; // RETURN } if (position == this->cbegin()) { privatePrepend(first, last, Tag()); return; // RETURN } if (position == this->cend()) { privateAppend(first, last, Tag()); return; // RETURN } privateInsert(position, first, last, Tag()); } template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> void deque<VALUE_TYPE, ALLOCATOR>::privateInsert( const_iterator position, INPUT_ITERATOR first, INPUT_ITERATOR last, std::input_iterator_tag tag) { BSLS_ASSERT(first != last); iterator pos(position.imp()); const size_type currentSize = this->size(); const size_type posIdx = pos - this->begin(); deque temp(k_RAW_INIT, this->get_allocator()); privateSplit(&temp, position.imp()); if (posIdx <= currentSize / 2) { Deque_Util::swap( static_cast<Base *>(this), static_cast<Base *>(&temp)); privatePrepend(first, last, tag); privateJoinPrepend(&temp); } else { privateAppend(first, last, tag); privateJoinAppend(&temp); } } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::privateSplit( deque<VALUE_TYPE, ALLOCATOR> *other, IteratorImp pos) { // BEFORE: //.. // this->d_start.valuePtr() -----------+ // V // this->d_start.blockPtr() --> H -> __AAA // I -> AAAAA // pos.blockPtr() -> J -> BBBxx <- pos.valuePtr() (at 1st x) // K -> yyyyy // this->d_finish.blockPtr() -> L -> y____ // ^ // +- this->d_finish.valuePtr() // // AFTER: // this->d_start.valuePtr() -----------+ // V // this->d_start.blockPtr() --> H -> __AAA // I -> AAAAA // this->d_finish.blockPtr() -> J -> BBB__ // ^ // +- this->d_finish.valuePtr() // // other->d_start.valuePtr() ------------+ // V // other->d_start.blockPtr() --> M -> ___xx // K -> yyyyy // other->d_finish.blockPtr() -> L -> y____ // ^ // +- other->d_finish.valuePtr() // // assert(! other.d_blocks_p); //.. if (pos.blockPtr() == this->d_finish.blockPtr()) { // Split point is in last block. Just copy portion after the split to // new block in 'other'. difference_type numAfter = this->d_finish.valuePtr() - pos.valuePtr(); other->privateInit(numAfter); BloombergLP::bslalg::ArrayPrimitives::destructiveMove( other->d_start.valuePtr(), pos.valuePtr(), this->d_finish.valuePtr(), ContainerBase::allocator()); other->d_finish += numAfter; this->d_finish = pos; return; // RETURN } if (pos.blockPtr() == this->d_start.blockPtr()) { // Split point is in first block. Copy portion before the split to new // block in 'other' and swap. difference_type numBefore = pos.valuePtr() - this->d_start.valuePtr(); other->privateInit(numBefore); BloombergLP::bslalg::ArrayPrimitives::destructiveMove( other->d_start.valuePtr(), this->d_start.valuePtr(), pos.valuePtr(), ContainerBase::allocator()); other->d_finish += numBefore; this->d_start = pos; Deque_Util::swap( static_cast<Base *>(this), static_cast<Base *>(other)); return; // RETURN } // Compute number of unsplit blocks to move. difference_type numMoveBlocks = this->d_finish.blockPtr() - pos.blockPtr(); size_type otherBlocksLength = numMoveBlocks + 1 + 2 * Imp::BLOCK_ARRAY_PADDING; other->d_blocks_p = this->allocateN((BlockPtr *)0, otherBlocksLength); other->d_blocksLength = otherBlocksLength; // Good time to allocate block for exception safety. Block *newBlock = this->allocateN((Block *)0, 1); // The following chunk of code will never throw an exception. Move unsplit // blocks from 'this' to 'other', then adjust the iterators. std::memcpy(other->d_blocks_p + 1 + Imp::BLOCK_ARRAY_PADDING, pos.blockPtr() + 1, sizeof(BlockPtr) * numMoveBlocks); other->d_start = IteratorImp(&other->d_blocks_p[ 1 + Imp::BLOCK_ARRAY_PADDING]); other->d_finish = IteratorImp(other->d_start.blockPtr() + numMoveBlocks - 1, this->d_finish.valuePtr()); BlockPtr *newBlockPtr = pos.blockPtr() + 1; *newBlockPtr = newBlock; this->d_finish = IteratorImp(newBlockPtr); // Current situation: //.. // this->d_start.valuePtr() -----------+ // V // this->d_start.blockPtr() --> H -> __AAA // I -> AAAAA // pos.blockPtr() -> J -> BBBxx <- pos.valuePtr() (1st x) // this->d_finish.blockPtr() -> M -> _____ // / ^ // newBlockPtr -+ +- this->d_finish.valuePtr() // // other->d_start.valuePtr() ---------+ // V // other->d_start.blockPtr() --> K -> yyyyy // other->d_finish.blockPtr() -> L -> y____ // ^ // +- other->d_finish.valuePtr() //.. // Now we split the block containing "BBBxx" into two blocks, with the "xx" // part going into '*newBlockPtr'. An exception can safely occur here // because the 'bslalg::ArrayPrimitives' functions are exception-neutral // and because all class invariants for both '*this' and 'other' hold going // in to this section. size_type splitOffset = pos.offsetInBlock(); if (splitOffset >= pos.remainingInBlock()) { // Move the tail part of the block into the new block. value_type *splitValuePtr = newBlock->d_data + splitOffset; BloombergLP::bslalg::ArrayPrimitives::destructiveMove( splitValuePtr, pos.valuePtr(), pos.blockEnd(), ContainerBase::allocator()); } else { // Move the head part of the block into the new block, then swap the // blocks within the 'd_blocks_p' array. BloombergLP::bslalg::ArrayPrimitives::destructiveMove( newBlock->d_data, pos.blockBegin(), pos.valuePtr(), ContainerBase::allocator()); *newBlockPtr = *pos.blockPtr(); *pos.blockPtr() = newBlock; } // Move block to 'other' and adjust the iterators. This will not throw. this->d_finish = IteratorImp(&newBlockPtr[-1], newBlockPtr[-1]->d_data + splitOffset); other->d_start.previousBlock(); *(other->d_start.blockPtr()) = *newBlockPtr; other->d_start = IteratorImp(other->d_start.blockPtr(), other->d_start.blockBegin() + splitOffset); } template <class VALUE_TYPE, class ALLOCATOR> inline void deque<VALUE_TYPE, ALLOCATOR>::privateJoinPrepend( deque<VALUE_TYPE, ALLOCATOR> *other) { privatePrepend(other->begin(), other->end(), std::random_access_iterator_tag()); // Make 'other' raw again, and free its resources. deque<VALUE_TYPE, ALLOCATOR> temp(k_RAW_INIT, other->allocator()); Deque_Util::move(static_cast<Base *>(&temp), static_cast<Base *>(other)); } template <class VALUE_TYPE, class ALLOCATOR> inline void deque<VALUE_TYPE, ALLOCATOR>::privateJoinAppend( deque<VALUE_TYPE, ALLOCATOR> *other) { privateAppend(other->begin(), other->end(), std::random_access_iterator_tag()); // Make 'other' raw again, and free its resources. deque<VALUE_TYPE, ALLOCATOR> temp(k_RAW_INIT, other->allocator()); Deque_Util::move(static_cast<Base *>(&temp), static_cast<Base *>(other)); } template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> void deque<VALUE_TYPE, ALLOCATOR>::privateInsert( const_iterator position, INPUT_ITERATOR first, INPUT_ITERATOR last, std::random_access_iterator_tag tag) { BSLS_ASSERT(first != last); if (position == this->cbegin()) { privatePrepend(first, last, tag); return; // RETURN } if (position == this->cend()) { privateAppend(first, last, tag); return; // RETURN } const size_type currentSize = this->size(); const size_type numElements = bsl::distance(first, last); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( numElements > max_size() - currentSize)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::insert(pos,n,v): deque too big"); } iterator pos(position.imp()); const size_type posIdx = position - this->cbegin(); if (posIdx <= currentSize / 2) { // Create new blocks at the front. In case an exception is thrown, any // unused blocks are returned to the allocator. size_type numNewBlocks = (this->d_start.remainingInBlock() + numElements - 1) / BLOCK_LENGTH; BlockCreator newBlocks(this); newBlocks.insertAtFront(numNewBlocks); DequePrimitives::insertAndMoveToFront(&this->d_start, this->d_start, this->d_start + posIdx, first, last, numElements, ContainerBase::allocator()); } else { // Create new blocks at front. In case an exception is thrown, any // unused blocks are returned to the allocator. size_type numNewBlocks = (this->d_finish.offsetInBlock() + numElements) / BLOCK_LENGTH; BlockCreator newBlocks(this); newBlocks.insertAtBack(numNewBlocks); DequePrimitives::insertAndMoveToBack(&this->d_finish, this->d_finish, this->d_start + posIdx, first, last, numElements, ContainerBase::allocator()); } } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::privatePrependRaw( size_type numElements, const VALUE_TYPE& value) { // Create new blocks at front. In case an exception is thrown, any unused // blocks are returned to the allocator. size_type numNewBlocks = (this->d_start.remainingInBlock() + numElements - 1) / BLOCK_LENGTH; BlockCreator newBlocks(this); newBlocks.insertAtFront(numNewBlocks); DequePrimitives::uninitializedFillNFront(&this->d_start, this->d_start, numElements, value, ContainerBase::allocator()); } template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> typename deque<VALUE_TYPE, ALLOCATOR>::size_type deque<VALUE_TYPE, ALLOCATOR>::privatePrepend(INPUT_ITERATOR first, INPUT_ITERATOR last, std::input_iterator_tag tag) { deque temp(k_RAW_INIT, this->get_allocator()); temp.privateInit(this->size() + 1); size_type numElements = temp.privateAppend(first, last, tag); // Check whether appending or prepending is more economical. if (numElements > this->size()) { Deque_Util::swap((Base *)this, (Base *)&temp); privateJoinAppend(&temp); } else { privateJoinPrepend(&temp); } return numElements; } template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> typename deque<VALUE_TYPE, ALLOCATOR>::size_type deque<VALUE_TYPE, ALLOCATOR>::privatePrepend( INPUT_ITERATOR first, INPUT_ITERATOR last, std::bidirectional_iterator_tag) { BlockCreator newBlocks(this); Guard guard(this, false); size_type numElements = 0; size_type maxNumElements = max_size() - this->size(); do { ++numElements; if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( numElements > maxNumElements)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::insert(pos,n,v): deque too big"); } IteratorImp insertPoint = guard.begin(); // There must be room for the iterator to be decremented. Allocate new // block now if necessary, with same caveat as above. if (insertPoint.valuePtr() == insertPoint.blockBegin()) { newBlocks.insertAtFront(1); insertPoint = guard.begin(); // 'insertAtFront' invalidates // 'insertPoint' } --insertPoint; AllocatorTraits::construct(ContainerBase::allocator(), BSLS_UTIL_ADDRESSOF(*insertPoint), *--last); ++guard; } while (first != last); this->d_start -= guard.count(); guard.release(); return numElements; } template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> typename deque<VALUE_TYPE, ALLOCATOR>::size_type deque<VALUE_TYPE, ALLOCATOR>::privatePrepend( INPUT_ITERATOR first, INPUT_ITERATOR last, std::random_access_iterator_tag) { const size_type numElements = bsl::distance(first, last); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( numElements > max_size() - this->size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::insert(pos,n,v): deque too big"); } BlockCreator newBlocks(this); Guard guard(this, false); do { IteratorImp insertPoint = guard.begin(); // There must be room for the iterator to be decremented. Allocate new // block now if necessary, with same caveat as above. if (insertPoint.valuePtr() == insertPoint.blockBegin()) { newBlocks.insertAtFront(1); insertPoint = guard.begin(); // 'insertAtFront' invalidates // 'insertPoint' } --insertPoint; AllocatorTraits::construct(ContainerBase::allocator(), BSLS_UTIL_ADDRESSOF(*insertPoint), *--last); ++guard; } while (first != last); this->d_start -= guard.count(); guard.release(); return numElements; } // CREATORS template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>::deque() : Deque_Base<VALUE_TYPE>() , ContainerBase(ALLOCATOR()) { deque temp(k_RAW_INIT, this->get_allocator()); temp.privateInit(0); Deque_Util::move(static_cast<Base *>(this), static_cast<Base *>(&temp)); } template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>::deque(const ALLOCATOR& basicAllocator) : Deque_Base<VALUE_TYPE>() , ContainerBase(basicAllocator) { deque temp(k_RAW_INIT, this->get_allocator()); temp.privateInit(0); Deque_Util::move(static_cast<Base *>(this), static_cast<Base *>(&temp)); } template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>::deque(size_type numElements, const ALLOCATOR& basicAllocator) : Deque_Base<VALUE_TYPE>() , ContainerBase(basicAllocator) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(numElements > max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::deque(n): deque too big"); } deque temp(k_RAW_INIT, this->get_allocator()); temp.privateInit(numElements); temp.privateAppendDefaultInsertable(numElements); Deque_Util::move(static_cast<Base *>(this), static_cast<Base *>(&temp)); } template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>::deque(size_type numElements, const VALUE_TYPE& value, const ALLOCATOR& basicAllocator) : Deque_Base<VALUE_TYPE>() , ContainerBase(basicAllocator) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(numElements > max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::deque(n,v): deque too big"); } deque temp(k_RAW_INIT, this->get_allocator()); temp.privateInit(numElements); temp.privateAppendRaw(numElements, value); Deque_Util::move(static_cast<Base *>(this), static_cast<Base *>(&temp)); } template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> deque<VALUE_TYPE, ALLOCATOR>::deque(INPUT_ITERATOR first, INPUT_ITERATOR last, const ALLOCATOR& basicAllocator) : Deque_Base<VALUE_TYPE>() , ContainerBase(basicAllocator) { deque temp(k_RAW_INIT, this->get_allocator()); temp.privateInit(0); temp.insert(temp.begin(), first, last); Deque_Util::move(static_cast<Base *>(this), static_cast<Base *>(&temp)); } template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>::deque( const deque<VALUE_TYPE, ALLOCATOR>& original) : Deque_Base<VALUE_TYPE>() , ContainerBase(AllocatorTraits::select_on_container_copy_construction( original.get_allocator())) { deque temp(k_RAW_INIT, this->get_allocator()); temp.privateInit(original.size()); temp.privateAppend(original.begin(), original.end(), std::random_access_iterator_tag()); Deque_Util::move(static_cast<Base *>(this), static_cast<Base *>(&temp)); } template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>::deque( const deque<VALUE_TYPE, ALLOCATOR>& original, const typename type_identity<ALLOCATOR>::type& basicAllocator) : Deque_Base<VALUE_TYPE>() , ContainerBase(basicAllocator) { deque temp(k_RAW_INIT, this->get_allocator()); temp.privateInit(original.size()); temp.privateAppend(original.begin(), original.end(), std::random_access_iterator_tag()); Deque_Util::move(static_cast<Base *>(this), static_cast<Base *>(&temp)); } template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>::deque( BloombergLP::bslmf::MovableRef<deque> original) : Deque_Base<VALUE_TYPE>() , ContainerBase(MoveUtil::access(original).get_allocator()) { deque temp(k_RAW_INIT, this->get_allocator()); temp.privateInit(0); Deque_Util::move(static_cast<Base *>(this), static_cast<Base *>(&temp)); deque& lvalue = original; Deque_Util::swap(static_cast<Base *>(this), static_cast<Base *>(&lvalue)); } template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>::deque( BloombergLP::bslmf::MovableRef<deque> original, const typename type_identity<ALLOCATOR>::type& basicAllocator) : Deque_Base<VALUE_TYPE>() , ContainerBase(basicAllocator) { deque temp(k_RAW_INIT, this->get_allocator()); temp.privateInit(0); deque& lvalue = original; if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY( get_allocator() == lvalue.get_allocator())) { Deque_Util::move(static_cast<Base *>(this), static_cast<Base *>(&temp)); Deque_Util::swap(static_cast<Base *>(this), static_cast<Base *>(&lvalue)); } else { const size_type size = lvalue.size(); temp.reserve(size); for (size_type pos = 0; pos < size; ++pos) { temp.push_back(MoveUtil::move(lvalue[pos])); } Deque_Util::move(static_cast<Base *>(this), static_cast<Base *>(&temp)); } } #if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) template <class VALUE_TYPE, class ALLOCATOR> inline deque<VALUE_TYPE, ALLOCATOR>::deque( std::initializer_list<value_type> values, const ALLOCATOR& basicAllocator) : deque(values.begin(), values.end(), basicAllocator) { } #endif template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>::~deque() { if (0 == this->d_blocks_p) { // Nothing to do when destroying raw deques. return; // RETURN } if (0 != this->d_start.blockPtr()) { // Destroy all elements and deallocate all but one block. clear(); // Deallocate the remaining (empty) block. this->deallocateN(*this->d_start.blockPtr(), 1); } // Deallocate the array of block pointers. this->deallocateN(this->d_blocks_p, this->d_blocksLength); } // MANIPULATORS template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>& deque<VALUE_TYPE, ALLOCATOR>::operator=( const deque<VALUE_TYPE, ALLOCATOR>& rhs) { if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(this != &rhs)) { if (AllocatorTraits::propagate_on_container_copy_assignment::value) { deque other(rhs, rhs.get_allocator()); Deque_Util::swap(static_cast<Base *>(this), static_cast<Base *>(&other)); BloombergLP::bslalg::SwapUtil::swap( &ContainerBase::allocator(), &other.ContainerBase::allocator()); } else { size_type origSize = this->size(); size_type rhsSize = rhs.size(); size_type minSize; if (origSize > rhsSize) { // Make shorter by deleting excess elements. minSize = rhsSize; erase(this->begin() + minSize, this->end()); } else { // Make longer by appending new elements. minSize = origSize; privateAppend(rhs.begin() + minSize, rhs.end(), std::random_access_iterator_tag()); } // Copy the smaller of the number of elements in 'rhs' and '*this'. IteratorImp from = rhs.d_start; IteratorImp to = this->d_start; for (size_type i = 0; i < minSize; ++i) { *to = *from; ++to; ++from; } } } return *this; } template <class VALUE_TYPE, class ALLOCATOR> deque<VALUE_TYPE, ALLOCATOR>& deque<VALUE_TYPE, ALLOCATOR>::operator=( BloombergLP::bslmf::MovableRef<deque> rhs) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION( AllocatorTraits::is_always_equal::value) { deque& lvalue = rhs; if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(this != &lvalue)) { if (get_allocator() == lvalue.get_allocator()) { Deque_Util::swap(static_cast<Base *>(this), static_cast<Base *>(&lvalue)); } else if ( AllocatorTraits::propagate_on_container_move_assignment::value) { deque other(MoveUtil::move(lvalue)); Deque_Util::swap(static_cast<Base *>(this), static_cast<Base *>(&other)); BloombergLP::bslalg::SwapUtil::swap( &ContainerBase::allocator(), &other.ContainerBase::allocator()); } else { deque other(MoveUtil::move(lvalue), get_allocator()); Deque_Util::swap(static_cast<Base *>(this), static_cast<Base *>(&other)); } } return *this; } #if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) template <class VALUE_TYPE, class ALLOCATOR> inline deque<VALUE_TYPE, ALLOCATOR>& deque<VALUE_TYPE, ALLOCATOR>::operator=( std::initializer_list<value_type> values) { assign(values.begin(), values.end()); return *this; } #endif template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> void deque<VALUE_TYPE, ALLOCATOR>::assign(INPUT_ITERATOR first, INPUT_ITERATOR last) { typedef typename iterator_traits<INPUT_ITERATOR>::iterator_category Tag; // If an exception is thrown, clear the deque to provide standard behavior, // which is: //.. // erase(begin(), end()); // insert(begin(), first, last); //.. ClearGuard guard(this); // Copy over existing elements. IteratorImp i; for (i = this->d_start; !(i == this->d_finish) && first != last; ++i, ++first) { *i = *first; } if (!(i == this->d_finish)) { // Erase elements past the last one copied. erase(i, this->end()); } else { // Still more elements to copy. Append them. privateAppend(first, last, Tag()); } guard.release(); } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::assign(size_type numElements, const VALUE_TYPE& value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(numElements > max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::assign(n,v): deque too big"); } // If an exception is thrown, clear the deque to provide standard behavior, // which is: //.. // erase(begin(), end()); // insert(begin(), first, last); //.. ClearGuard guard(this); size_type origSize = this->size(); size_type minSize; if (numElements < origSize) { minSize = numElements; erase(this->begin() + numElements, this->end()); } else { minSize = origSize; privateAppendRaw(numElements - origSize, value); } IteratorImp to = this->d_start; for (size_type i = 0; i < minSize; ++i) { *to = value; ++to; } guard.release(); } #if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) template <class VALUE_TYPE, class ALLOCATOR> inline void deque<VALUE_TYPE, ALLOCATOR>::assign( std::initializer_list<value_type> values) { assign(values.begin(), values.end()); } #endif template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::reserve(size_type numElements) { // Make sure 'numElements' isn't high enough to make the calculations of // 'num(Front|Back)Blocks' overflow. if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(numElements > max_size() - (BLOCK_LENGTH - 1))) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::reserve(n): deque too big"); } // 'ContainerBase::allocateN', which creates the 'd_blocks_p' array, does // not, in its contract, guarantee to initialize the array to 0. Since we // read these values, we have to make sure they're initialized to avoid // purify 'read before write' errors. Note that we initialize them to 0, // making them invalid pointers, but we never dereference them, and the // pointer arithmetic we do on them will still work. if (this->d_start.blockPtr() > this->d_blocks_p) { this->d_blocks_p[0] = 0; } if (this->d_finish.blockPtr() < this->d_blocks_p + this->d_blocksLength-1){ this->d_blocks_p[this->d_blocksLength - 1] = 0; } const IteratorImp first(this->d_blocks_p); IteratorImp last( this->d_blocks_p + this->d_blocksLength - 1); last += BLOCK_LENGTH - 1; const size_type frontRoom = this->d_start - first; const size_type backRoom = last - this->d_finish; size_type numFrontBlocks = numElements > frontRoom ? (numElements - frontRoom + BLOCK_LENGTH - 1) / BLOCK_LENGTH : 0; size_type numBackBlocks = numElements > backRoom ? (numElements - backRoom + BLOCK_LENGTH - 1) / BLOCK_LENGTH : 0; if (0 == numFrontBlocks && 0 == numBackBlocks) { return; // RETURN } // Make sure that if we throw, it's before we modify the deque. size_type existingSpace = last - first; if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(numFrontBlocks > (max_size() - existingSpace) / BLOCK_LENGTH || (existingSpace += numFrontBlocks * BLOCK_LENGTH, numBackBlocks > (max_size() - existingSpace) / BLOCK_LENGTH))) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::reserve(n): deque too big"); } // When 'numFrontBlocks' or 'numBackBlocks' are 0, the respective calls // will be no-ops. BlockCreator newBlocks(this); newBlocks.reserveBlockSlots(numFrontBlocks, true); newBlocks.reserveBlockSlots(numBackBlocks, false); } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::resize(size_type newSize) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(newSize > max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::resize(n): deque too big"); } size_type origSize = this->size(); if (newSize <= origSize) { // Note that we do not use 'erase' here as 'erase' requires elements be // copy-insertable, while the standard does not require elements be // copy-insertable for this 'resize' overload. IteratorImp oldEnd = this->d_finish; IteratorImp newEnd = this->d_start + newSize; DequePrimitives::destruct(newEnd, oldEnd, ContainerBase::allocator()); // Deallocate blocks no longer used for (; oldEnd.blockPtr() != newEnd.blockPtr(); oldEnd.previousBlock()) { this->deallocateN(*oldEnd.blockPtr(), 1); } this->d_finish = newEnd; } else { privateAppendDefaultInsertable(newSize - origSize); } } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::resize(size_type newSize, const VALUE_TYPE& value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(newSize > max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::resize(n,v): deque too big"); } size_type origSize = this->size(); if (newSize <= origSize) { erase(this->begin() + newSize, this->end()); } else { privateAppendRaw(newSize - origSize, value); } } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::shrink_to_fit() { // Minimize the length of 'd_blocks_p' without moving any elements. A more // complex algorithm is not justified. At most 'BLOCK_LENGTH' bytes are // wasted. const size_type newBlocksLength = this->d_finish.blockPtr() - this->d_start.blockPtr() + 1; if (newBlocksLength == this->d_blocksLength) { return; // RETURN } const size_type offsetStart = this->d_start.offsetInBlock(); const size_type offsetFinish = this->d_finish.offsetInBlock(); BlockPtr *newBlocks = this->allocateN((BlockPtr *)0, newBlocksLength); std::memmove(newBlocks, this->d_start.blockPtr(), newBlocksLength * sizeof(BlockPtr)); this->deallocateN(this->d_blocks_p, this->d_blocksLength); this->d_blocks_p = newBlocks; this->d_blocksLength = newBlocksLength; this->d_start.setBlock(newBlocks); this->d_start += offsetStart; this->d_finish.setBlock(newBlocks + newBlocksLength - 1); this->d_finish += offsetFinish; } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::push_front(const VALUE_TYPE& value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(this->size() >= max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::push_front(v): deque too big"); } if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( 0 == this->d_start.offsetInBlock())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BlockCreator newBlocks(this); newBlocks.insertAtFront(1); // The deque's value is not modified. AllocatorTraits::construct( ContainerBase::allocator(), (this->d_start - 1).valuePtr(), value); --this->d_start; } else { // Since the offset is non-zero, it is safe to directly decrement the // pointer. This is much quicker than calling 'operator--'. AllocatorTraits::construct( ContainerBase::allocator(), this->d_start.valuePtr() - 1, value); this->d_start.valuePtrDecrement(); } } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::push_front( BloombergLP::bslmf::MovableRef<value_type> value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(this->size() >= max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::push_front(v): deque too big"); } VALUE_TYPE& lvalue = value; if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( 0 == this->d_start.offsetInBlock())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BlockCreator newBlocks(this); newBlocks.insertAtFront(1); // The deque's value is not modified. AllocatorTraits::construct(ContainerBase::allocator(), (this->d_start - 1).valuePtr(), MoveUtil::move(lvalue)); --this->d_start; } else { // Since the offset is non-zero, it is safe to directly decrement the // pointer. This is much quicker than calling 'operator--'. AllocatorTraits::construct(ContainerBase::allocator(), this->d_start.valuePtr() - 1, MoveUtil::move(lvalue)); this->d_start.valuePtrDecrement(); } } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::push_back(const VALUE_TYPE& value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(this->size() >= max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::push_back(v): deque too big"); } if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY( 1 < this->d_finish.remainingInBlock())) { AllocatorTraits::construct( ContainerBase::allocator(), this->d_finish.valuePtr(), value); this->d_finish.valuePtrIncrement(); } else { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BlockCreator newBlocks(this); newBlocks.insertAtBack(1); // The deque's value is not modified. AllocatorTraits::construct( ContainerBase::allocator(), this->d_finish.valuePtr(), value); this->d_finish.nextBlock(); } } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::push_back( BloombergLP::bslmf::MovableRef<value_type> value) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(this->size() >= max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::push_back(v): deque too big"); } VALUE_TYPE& lvalue = value; if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY( 1 < this->d_finish.remainingInBlock())) { AllocatorTraits::construct(ContainerBase::allocator(), this->d_finish.valuePtr(), MoveUtil::move(lvalue)); this->d_finish.valuePtrIncrement(); } else { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BlockCreator newBlocks(this); newBlocks.insertAtBack(1); // The deque's value is not modified. AllocatorTraits::construct(ContainerBase::allocator(), this->d_finish.valuePtr(), MoveUtil::move(lvalue)); this->d_finish.nextBlock(); } } #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES template <class VALUE_TYPE, class ALLOCATOR> template <class... Args> typename deque<VALUE_TYPE, ALLOCATOR>::reference deque<VALUE_TYPE, ALLOCATOR>::emplace_front(Args&&...arguments) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(this->size() >= max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::emplace_front(args): deque too big"); } if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( 0 == this->d_start.offsetInBlock())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BlockCreator newBlocks(this); newBlocks.insertAtFront(1); // The deque's value is not modified. AllocatorTraits::construct( ContainerBase::allocator(), (this->d_start - 1).valuePtr(), BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...); --this->d_start; } else { // Since the offset is non-zero, it is safe to directly decrement the // pointer. This is much quicker than calling 'operator--'. AllocatorTraits::construct( ContainerBase::allocator(), this->d_start.valuePtr() - 1, BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...); this->d_start.valuePtrDecrement(); } return *(this->d_start); } template <class VALUE_TYPE, class ALLOCATOR> template <class... Args> typename deque<VALUE_TYPE, ALLOCATOR>::reference deque<VALUE_TYPE, ALLOCATOR>::emplace_back(Args&&...arguments) { if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(this->size() >= max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::emplace_back(args): deque too big"); } if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY( 1 < this->d_finish.remainingInBlock())) { AllocatorTraits::construct( ContainerBase::allocator(), this->d_finish.valuePtr(), BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...); this->d_finish.valuePtrIncrement(); } else { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BlockCreator newBlocks(this); newBlocks.insertAtBack(1); // The deque's value is not modified. AllocatorTraits::construct( ContainerBase::allocator(), this->d_finish.valuePtr(), BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...); this->d_finish.nextBlock(); } return *(this->d_finish - 1); } #endif #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES template <class VALUE_TYPE, class ALLOCATOR> template <class... Args> typename deque<VALUE_TYPE, ALLOCATOR>::iterator deque<VALUE_TYPE, ALLOCATOR>::emplace(const_iterator position, Args&&... arguments) { BSLS_ASSERT(position >= this->cbegin()); BSLS_ASSERT(position <= this->cend()); if (position == this->cbegin()) { emplace_front(BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...); return this->begin(); // RETURN } if (position == this->cend()) { emplace_back(BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...); return iterator(this->d_finish - 1); // RETURN } // The test is placed here because 'emplace_front' and 'emplace_back' do // the same check. const size_type currentSize = this->size(); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(currentSize >= max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::emplace(args): deque too big"); } iterator pos(position.imp()); const size_type posIdx = position - this->cbegin(); if (posIdx <= currentSize / 2) { BlockCreator newBlocks(this); if (this->d_start.remainingInBlock() == BLOCK_LENGTH) { newBlocks.insertAtFront(1); } BlockProctor proctor(this, true); DequePrimitives::emplaceAndMoveToFront( &this->d_start, this->d_start, this->d_start + posIdx, ContainerBase::allocator(), BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...); proctor.release(); } else { BlockCreator newBlocks(this); if (this->d_finish.offsetInBlock() == BLOCK_LENGTH - 1) { newBlocks.insertAtBack(1); } BlockProctor proctor(this, false); DequePrimitives::emplaceAndMoveToBack( &this->d_finish, this->d_finish, this->d_start + posIdx, ContainerBase::allocator(), BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...); proctor.release(); } return this->begin() + posIdx; } #endif template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::pop_front() { BSLS_ASSERT(!this->empty()); BloombergLP::bslma::DestructionUtil::destroy(this->d_start.valuePtr()); if (1 == this->d_start.remainingInBlock()) { this->deallocateN(*this->d_start.blockPtr(), 1); this->d_start.nextBlock(); return; // RETURN } this->d_start.valuePtrIncrement(); } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::pop_back() { BSLS_ASSERT(!this->empty()); if (0 == this->d_finish.offsetInBlock()) { --this->d_finish; BloombergLP::bslma::DestructionUtil::destroy( this->d_finish.valuePtr()); this->deallocateN(this->d_finish.blockPtr()[1], 1); return; // RETURN } this->d_finish.valuePtrDecrement(); BloombergLP::bslma::DestructionUtil::destroy(this->d_finish.valuePtr()); } template <class VALUE_TYPE, class ALLOCATOR> typename deque<VALUE_TYPE, ALLOCATOR>::iterator deque<VALUE_TYPE, ALLOCATOR>::insert(const_iterator position, const VALUE_TYPE& value) { BSLS_ASSERT(position >= this->cbegin()); BSLS_ASSERT(position <= this->cend()); if (position == this->cbegin()) { push_front(value); return this->begin(); // RETURN } if (position == this->cend()) { push_back(value); return iterator(this->d_finish - 1); // RETURN } // The test is placed here because 'push_front' and 'push_back' do the same // check. const size_type currentSize = this->size(); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(currentSize >= max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::insert(pos,n,v): deque too big"); } iterator pos(position.imp()); const size_type posIdx = position - this->cbegin(); if (posIdx <= currentSize / 2) { BlockCreator newBlocks(this); if (this->d_start.remainingInBlock() == BLOCK_LENGTH) { newBlocks.insertAtFront(1); } DequePrimitives::insertAndMoveToFront(&this->d_start, this->d_start, this->d_start + posIdx, 1, value, ContainerBase::allocator()); } else { BlockCreator newBlocks(this); if (this->d_finish.offsetInBlock() == BLOCK_LENGTH - 1) { newBlocks.insertAtBack(1); } DequePrimitives::insertAndMoveToBack(&this->d_finish, this->d_finish, this->d_start + posIdx, 1, value, ContainerBase::allocator()); } return this->begin() + posIdx; } template <class VALUE_TYPE, class ALLOCATOR> typename deque<VALUE_TYPE, ALLOCATOR>::iterator deque<VALUE_TYPE, ALLOCATOR>::insert( const_iterator position, BloombergLP::bslmf::MovableRef<VALUE_TYPE> value) { BSLS_ASSERT(position >= this->cbegin()); BSLS_ASSERT(position <= this->cend()); VALUE_TYPE& lvalue = value; if (position == this->cbegin()) { push_front(MoveUtil::move(lvalue)); return this->begin(); // RETURN } if (position == this->cend()) { push_back(MoveUtil::move(lvalue)); return iterator(this->d_finish - 1); // RETURN } // The test is placed here because 'push_front' and 'push_back' do the same // check. const size_type currentSize = this->size(); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(currentSize >= max_size())) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::insert(pos,n,v): deque too big"); } iterator pos(position.imp()); const size_type posIdx = position - this->cbegin(); if (posIdx <= currentSize / 2) { BlockCreator newBlocks(this); if (this->d_start.remainingInBlock() == BLOCK_LENGTH) { newBlocks.insertAtFront(1); } DequePrimitives::moveInsertAndMoveToFront(&this->d_start, this->d_start, this->d_start + posIdx, MoveUtil::move(lvalue), ContainerBase::allocator()); } else { BlockCreator newBlocks(this); if (this->d_finish.offsetInBlock() == BLOCK_LENGTH - 1) { newBlocks.insertAtBack(1); } DequePrimitives::moveInsertAndMoveToBack(&this->d_finish, this->d_finish, this->d_start + posIdx, MoveUtil::move(lvalue), ContainerBase::allocator()); } return this->begin() + posIdx; } template <class VALUE_TYPE, class ALLOCATOR> typename deque<VALUE_TYPE, ALLOCATOR>::iterator deque<VALUE_TYPE, ALLOCATOR>::insert(const_iterator position, size_type numElements, const VALUE_TYPE& value) { BSLS_ASSERT(position >= this->cbegin()); BSLS_ASSERT(position <= this->cend()); const size_type posIdx = position - this->cbegin(); if (0 == numElements) { return this->begin() + posIdx; // RETURN } const size_type currentSize = this->size(); if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( numElements > max_size() - currentSize)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; BloombergLP::bslstl::StdExceptUtil::throwLengthError( "deque<...>::insert(pos,n,v): deque too big"); } if (position == this->cbegin()) { privatePrependRaw(numElements, value); return this->begin(); // RETURN } if (position == this->cend()) { privateAppendRaw(numElements, value); return this->begin() + posIdx; // RETURN } if (posIdx <= currentSize / 2) { // Create new blocks at front. In case an exception is thrown, any // unused blocks are returned to the allocator. size_type numNewBlocks = (this->d_start.remainingInBlock() + numElements - 1) / BLOCK_LENGTH; BlockCreator newBlocks(this); newBlocks.insertAtFront(numNewBlocks); DequePrimitives::insertAndMoveToFront(&this->d_start, this->d_start, this->d_start + posIdx, numElements, value, ContainerBase::allocator()); } else { // Create new blocks at back. In case an exception is thrown, any // unused blocks are returned to the allocator. size_type numNewBlocks = (this->d_finish.offsetInBlock() + numElements) / BLOCK_LENGTH; BlockCreator newBlocks(this); newBlocks.insertAtBack(numNewBlocks); DequePrimitives::insertAndMoveToBack(&this->d_finish, this->d_finish, this->d_start + posIdx, numElements, value, ContainerBase::allocator()); } return this->begin() + posIdx; } template <class VALUE_TYPE, class ALLOCATOR> template <class INPUT_ITERATOR> inline typename deque<VALUE_TYPE, ALLOCATOR>::iterator deque<VALUE_TYPE, ALLOCATOR>::insert(const_iterator position, INPUT_ITERATOR first, INPUT_ITERATOR last) { BSLS_ASSERT_SAFE(position >= this->cbegin()); BSLS_ASSERT_SAFE(position <= this->cend()); const size_type posIdx = position - this->cbegin(); privateInsertDispatch(position, first, last, first, BloombergLP::bslmf::Nil()); return this->begin() + posIdx; } #if defined(BSLS_COMPILERFEATURES_SUPPORT_GENERALIZED_INITIALIZERS) template <class VALUE_TYPE, class ALLOCATOR> inline typename deque<VALUE_TYPE, ALLOCATOR>::iterator deque<VALUE_TYPE, ALLOCATOR>::insert( const_iterator position, std::initializer_list<value_type> values) { BSLS_ASSERT_SAFE(position >= this->cbegin()); BSLS_ASSERT_SAFE(position <= this->cend()); return insert(position, values.begin(), values.end()); } #endif template <class VALUE_TYPE, class ALLOCATOR> typename deque<VALUE_TYPE, ALLOCATOR>::iterator deque<VALUE_TYPE, ALLOCATOR>::erase(const_iterator position) { BSLS_ASSERT(position >= this->cbegin()); BSLS_ASSERT(position < this->cend()); if (position == const_iterator(this->d_start)) { pop_front(); return this->begin(); // RETURN } if (position + 1 == const_iterator(this->d_finish)) { pop_back(); return this->end(); // RETURN } return erase(position, position + 1); } template <class VALUE_TYPE, class ALLOCATOR> typename deque<VALUE_TYPE, ALLOCATOR>::iterator deque<VALUE_TYPE, ALLOCATOR>::erase(const_iterator first, const_iterator last) { BSLS_ASSERT(first >= this->cbegin()); BSLS_ASSERT(first <= this->cend()); BSLS_ASSERT(first <= last); BSLS_ASSERT(last <= this->cend()); iterator first_imp = this->begin() + (first - this->cbegin()); iterator last_imp = this->begin() + (last - this->cbegin()); iterator oldStart = this->begin(); iterator oldFinish = this->end(); iterator result = iterator(DequePrimitives::erase( &this->d_start, &this->d_finish, this->d_start, first_imp.imp(), last_imp.imp(), this->d_finish, ContainerBase::allocator())); // Deallocate blocks no longer used. for ( ; oldStart.imp().blockPtr() != this->d_start.blockPtr(); oldStart.imp().nextBlock()) { this->deallocateN(oldStart.imp().blockPtr()[0], 1); } for ( ; oldFinish.imp().blockPtr() != this->d_finish.blockPtr(); oldFinish.imp().previousBlock()) { this->deallocateN(oldFinish.imp().blockPtr()[0], 1); } return result; } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::swap(deque<VALUE_TYPE, ALLOCATOR>& other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION( AllocatorTraits::is_always_equal::value) { if (AllocatorTraits::propagate_on_container_swap::value) { Deque_Util::swap(static_cast<Base *>(this), static_cast<Base *>(&other)); BloombergLP::bslalg::SwapUtil::swap(&ContainerBase::allocator(), &other.ContainerBase::allocator()); } else { if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY( this->get_allocator() == other.get_allocator())) { Deque_Util::swap(static_cast<Base *>(this), static_cast<Base *>(&other)); } else { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; deque toOtherCopy(MoveUtil::move(*this), other.get_allocator()); deque toThisCopy( MoveUtil::move(other), this->get_allocator()); Deque_Util::swap(static_cast<Base *>(&toThisCopy), static_cast<Base *>(this)); Deque_Util::swap(static_cast<Base *>(&toOtherCopy), static_cast<Base *>(&other)); } } } template <class VALUE_TYPE, class ALLOCATOR> void deque<VALUE_TYPE, ALLOCATOR>::clear() BSLS_KEYWORD_NOEXCEPT { DequePrimitives::destruct(this->d_start, this->d_finish, ContainerBase::allocator()); // Deallocate all blocks except 'finishBlock'. BlockPtr *startBlock = this->d_start.blockPtr(); BlockPtr *finishBlock = this->d_finish.blockPtr(); for ( ; startBlock != finishBlock; ++startBlock) { this->deallocateN(*startBlock, 1); } // Reposition in the middle. size_type blockOffset = this->d_blocksLength / 2; int offset = BLOCK_LENGTH / 2; BlockPtr *blockPtr = this->d_blocks_p + blockOffset; *blockPtr = *finishBlock; this->d_start = this->d_finish = IteratorImp(blockPtr, (*blockPtr)->d_data + offset); } // ACCESSORS template <class VALUE_TYPE, class ALLOCATOR> inline typename deque<VALUE_TYPE, ALLOCATOR>::allocator_type deque<VALUE_TYPE, ALLOCATOR>::get_allocator() const BSLS_KEYWORD_NOEXCEPT { return ContainerBase::allocator(); } template <class VALUE_TYPE, class ALLOCATOR> inline typename deque<VALUE_TYPE, ALLOCATOR>::size_type deque<VALUE_TYPE, ALLOCATOR>::max_size() const BSLS_KEYWORD_NOEXCEPT { return AllocatorTraits::max_size(this->get_allocator()); } // FREE OPERATORS template <class VALUE_TYPE, class ALLOCATOR> bool operator==(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs) { if (lhs.size() != rhs.size()) { return false; // RETURN } enum { BLOCK_LENGTH = Deque_BlockLengthCalcUtil<VALUE_TYPE>::BLOCK_LENGTH }; typedef BloombergLP::bslalg::DequeIterator<VALUE_TYPE, BLOCK_LENGTH> Iterator; Iterator lhsBegin = lhs.begin().imp(); Iterator lhsEnd = lhs.end().imp(); Iterator rhsBegin = rhs.begin().imp(); for (; !(lhsBegin == lhsEnd); ++lhsBegin, ++rhsBegin) { if (!(*lhsBegin == *rhsBegin)) { return false; // RETURN } } return true; } template <class VALUE_TYPE, class ALLOCATOR> inline bool operator!=(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs) { return !(lhs == rhs); } template <class VALUE_TYPE, class ALLOCATOR> inline bool operator<(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs) { return 0 > BloombergLP::bslalg::RangeCompare::lexicographical(lhs.begin(), lhs.end(), lhs.size(), rhs.begin(), rhs.end(), rhs.size()); } template <class VALUE_TYPE, class ALLOCATOR> inline bool operator>(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs) { return rhs < lhs; } template <class VALUE_TYPE, class ALLOCATOR> inline bool operator<=(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs) { return !(rhs < lhs); } template <class VALUE_TYPE, class ALLOCATOR> inline bool operator>=(const deque<VALUE_TYPE, ALLOCATOR>& lhs, const deque<VALUE_TYPE, ALLOCATOR>& rhs) { return !(lhs < rhs); } // FREE FUNCTIONS template <class VALUE_TYPE, class ALLOCATOR, class BDE_OTHER_TYPE> inline typename deque<VALUE_TYPE, ALLOCATOR>::size_type erase(deque<VALUE_TYPE, ALLOCATOR>& deq, const BDE_OTHER_TYPE& value) { typename deque<VALUE_TYPE, ALLOCATOR>::size_type oldSize = deq.size(); deq.erase(bsl::remove(deq.begin(), deq.end(), value), deq.end()); return oldSize - deq.size(); } template <class VALUE_TYPE, class ALLOCATOR, class PREDICATE> inline typename deque<VALUE_TYPE, ALLOCATOR>::size_type erase_if(deque<VALUE_TYPE, ALLOCATOR>& deq, PREDICATE predicate) { typename deque<VALUE_TYPE, ALLOCATOR>::size_type oldSize = deq.size(); deq.erase(bsl::remove_if(deq.begin(), deq.end(), predicate), deq.end()); return oldSize - deq.size(); } template <class VALUE_TYPE, class ALLOCATOR> inline void swap(deque<VALUE_TYPE, ALLOCATOR>& a, deque<VALUE_TYPE, ALLOCATOR>& b) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(BSLS_KEYWORD_NOEXCEPT_OPERATOR( a.swap(b))) { a.swap(b); } // ------------------------ // class Deque_BlockCreator // ------------------------ // CREATORS template <class VALUE_TYPE, class ALLOCATOR> inline Deque_BlockCreator<VALUE_TYPE, ALLOCATOR>::Deque_BlockCreator( deque<VALUE_TYPE, ALLOCATOR> *deque) : d_deque_p(deque) , d_boundary_p(0) { } template <class VALUE_TYPE, class ALLOCATOR> Deque_BlockCreator<VALUE_TYPE, ALLOCATOR>::~Deque_BlockCreator() { if (0 != d_boundary_p) { BlockPtr *delFirst, *delLast; if (d_boundary_p <= d_deque_p->d_start.blockPtr()) { delFirst = d_boundary_p; delLast = d_deque_p->d_start.blockPtr(); } else { delFirst = d_deque_p->d_finish.blockPtr() + 1; delLast = d_boundary_p; } for (; delFirst != delLast; ++delFirst) { // Deallocate the block that '*delFirst' points to. d_deque_p->deallocateN(*delFirst, 1); } } } // MANIPULATORS template <class VALUE_TYPE, class ALLOCATOR> void Deque_BlockCreator<VALUE_TYPE, ALLOCATOR>::insertAtFront(size_type n) { d_boundary_p = reserveBlockSlots(n, true); for ( ; n > 0; --n) { d_boundary_p[-1] = d_deque_p->allocateN((Block *)0, 1); --d_boundary_p; } } template <class VALUE_TYPE, class ALLOCATOR> void Deque_BlockCreator<VALUE_TYPE, ALLOCATOR>::insertAtBack(size_type n) { d_boundary_p = reserveBlockSlots(n, false); for ( ; n > 0; --n) { *d_boundary_p = d_deque_p->allocateN((Block *)0, 1); ++d_boundary_p; } } template <class VALUE_TYPE, class ALLOCATOR> typename Deque_BlockCreator<VALUE_TYPE, ALLOCATOR>::BlockPtr * Deque_BlockCreator<VALUE_TYPE, ALLOCATOR>::reserveBlockSlots( size_type numNewBlocks, bool atFront) { BlockPtr *blocks = d_deque_p->d_blocks_p; size_type blocksLength = d_deque_p->d_blocksLength; BlockPtr *firstSlot = d_deque_p->d_start.blockPtr(); BlockPtr *lastSlot = d_deque_p->d_finish.blockPtr() + 1; if (atFront) { if (d_boundary_p) { firstSlot = d_boundary_p; } if (size_type(firstSlot - blocks) >= numNewBlocks) { // Enough room to insert at the front. return firstSlot; // RETURN } } else { if (d_boundary_p) { lastSlot = d_boundary_p; } if (size_type(blocks + blocksLength - lastSlot) >= numNewBlocks) { // Enough room to insert at the back. return lastSlot; // RETURN } } BlockPtr *newBlocks = blocks; size_type newBlocksLength = blocksLength; size_type numUsedBlocks = lastSlot - firstSlot; size_type blockOffsetStart = d_deque_p->d_start.blockPtr() - firstSlot; size_type numCommittedBlocks = (d_deque_p->d_finish.blockPtr() - d_deque_p->d_start.blockPtr() + 1); size_type newNumUsedBlocks = numUsedBlocks + numNewBlocks; if (newNumUsedBlocks > blocksLength) { const size_type newThreshold = newNumUsedBlocks + 2 * Imp::BLOCK_ARRAY_PADDING; while (newThreshold > newBlocksLength) { // Insufficient room. Allocate new blocks array with geometric // growth. Note that this should never overflow because there are // at least 16 elements in each block, thus the requested block // array pointer will never be close to 'max_size() / 2'. newBlocksLength *= 2; } newBlocks = d_deque_p->allocateN((BlockPtr *)0, newBlocksLength); } // Center block pointers within new blocks array. BlockPtr *newFirstSlot = newBlocks + (newBlocksLength - newNumUsedBlocks) / 2; if (atFront) { newFirstSlot += numNewBlocks; } // Calculate offset for start and finish. Need to do this before moving // around blocks. const size_type offsetStart = d_deque_p->d_start.offsetInBlock(); const size_type offsetFinish = d_deque_p->d_finish.offsetInBlock(); // Move old block pointers into new position. std::memmove(newFirstSlot, firstSlot, numUsedBlocks * sizeof(BlockPtr)); if (newBlocks != blocks) { // Deallocate old blocks array and install the new one. if (blocks) { d_deque_p->deallocateN(blocks, d_deque_p->d_blocksLength); } d_deque_p->d_blocks_p = newBlocks; d_deque_p->d_blocksLength = newBlocksLength; } // Adjust start and finish iterators. d_deque_p->d_start.setBlock(newFirstSlot + blockOffsetStart); d_deque_p->d_start += offsetStart; d_deque_p->d_finish.setBlock(newFirstSlot + blockOffsetStart + numCommittedBlocks - 1); d_deque_p->d_finish += offsetFinish; BlockPtr *ret = newFirstSlot; if (!atFront) { ret += numUsedBlocks; } return ret; } template <class VALUE_TYPE, class ALLOCATOR> inline void Deque_BlockCreator<VALUE_TYPE, ALLOCATOR>::release() { d_boundary_p = 0; } // ------------------------ // class Deque_BlockProctor // ------------------------ // CREATORS template <class VALUE_TYPE, class ALLOCATOR> Deque_BlockProctor<VALUE_TYPE, ALLOCATOR>::Deque_BlockProctor( deque<VALUE_TYPE, ALLOCATOR> *deque, bool atFront) : d_deque_p(deque) , d_boundary_p(atFront ? d_deque_p->d_start.blockPtr() : d_deque_p->d_finish.blockPtr()) , d_atFront(atFront) { } template <class VALUE_TYPE, class ALLOCATOR> Deque_BlockProctor<VALUE_TYPE, ALLOCATOR>::~Deque_BlockProctor() { if (0 != d_deque_p) { BlockPtr *delFirst, *delLast; if (d_atFront && d_boundary_p < d_deque_p->d_start.blockPtr()) { // Blocks at the front of the deque have been emptied since this // proctor was created. delFirst = d_boundary_p; delLast = d_deque_p->d_start.blockPtr(); } else if (!d_atFront && d_boundary_p > d_deque_p->d_finish.blockPtr()) { // Blocks at the back of the deque have been emptied since this // proctor was created. delFirst = d_deque_p->d_finish.blockPtr() + 1; delLast = d_boundary_p + 1; } else { return; // RETURN } for (; delFirst != delLast; ++delFirst) { // Deallocate the block that '*delFirst' points to. d_deque_p->deallocateN(*delFirst, 1); } } } // MANIPULATORS template <class VALUE_TYPE, class ALLOCATOR> inline void Deque_BlockProctor<VALUE_TYPE, ALLOCATOR>::release() { d_deque_p = 0; } // ---------------------- // class Deque_ClearGuard // ---------------------- // CREATORS template <class VALUE_TYPE, class ALLOCATOR> inline Deque_ClearGuard<VALUE_TYPE, ALLOCATOR>::Deque_ClearGuard( deque<VALUE_TYPE, ALLOCATOR> *deque) : d_deque_p(deque) { } template <class VALUE_TYPE, class ALLOCATOR> inline Deque_ClearGuard<VALUE_TYPE, ALLOCATOR>::~Deque_ClearGuard() { if (d_deque_p) { d_deque_p->clear(); } } // MANIPULATORS template <class VALUE_TYPE, class ALLOCATOR> inline void Deque_ClearGuard<VALUE_TYPE, ALLOCATOR>::release() { d_deque_p = 0; } // ----------------- // class Deque_Guard // ----------------- // CREATORS template <class VALUE_TYPE, class ALLOCATOR> inline Deque_Guard<VALUE_TYPE, ALLOCATOR>::Deque_Guard( deque<VALUE_TYPE, ALLOCATOR> *deque, bool isTail) : d_deque_p(deque) , d_count(0) , d_isTail(isTail) { } template <class VALUE_TYPE, class ALLOCATOR> Deque_Guard<VALUE_TYPE, ALLOCATOR>::~Deque_Guard() { if (0 == d_count) { return; // RETURN } IteratorImp begin, end; if (d_isTail) { begin = d_deque_p->d_finish; end = begin + d_count; } else { end = d_deque_p->d_start; begin = end - d_count; } DequePrimitives::destruct(begin, end, d_deque_p->allocator()); } // MANIPULATORS template <class VALUE_TYPE, class ALLOCATOR> inline std::size_t Deque_Guard<VALUE_TYPE, ALLOCATOR>::operator++() { return ++d_count; } template <class VALUE_TYPE, class ALLOCATOR> inline std::size_t Deque_Guard<VALUE_TYPE, ALLOCATOR>::operator--() { return --d_count; } template <class VALUE_TYPE, class ALLOCATOR> inline void Deque_Guard<VALUE_TYPE, ALLOCATOR>::release() { d_count = 0; } // ACCESSORS template <class VALUE_TYPE, class ALLOCATOR> inline std::size_t Deque_Guard<VALUE_TYPE, ALLOCATOR>::count() const BSLS_KEYWORD_NOEXCEPT { return d_count; } template <class VALUE_TYPE, class ALLOCATOR> inline typename Deque_Guard<VALUE_TYPE, ALLOCATOR>::IteratorImp Deque_Guard<VALUE_TYPE, ALLOCATOR>::begin() const BSLS_KEYWORD_NOEXCEPT { return d_deque_p->d_start - d_count; } template <class VALUE_TYPE, class ALLOCATOR> inline typename Deque_Guard<VALUE_TYPE, ALLOCATOR>::IteratorImp Deque_Guard<VALUE_TYPE, ALLOCATOR>::end() const BSLS_KEYWORD_NOEXCEPT { return d_deque_p->d_finish + d_count; } } // close namespace bsl // ============================================================================ // TYPE TRAITS // ============================================================================ // Type traits for STL *sequence* containers: //: o A sequence container defines STL iterators. //: o A sequence container is bitwise-movable if its allocator is //: bitwise-movable. //: o A sequence container uses 'bslma' allocators if the (template parameter) //: type 'ALLOCATOR' is convertible from 'bslma::Allocator *'. namespace BloombergLP { namespace bslalg { template <class VALUE_TYPE, class ALLOCATOR> struct HasStlIterators<bsl::deque<VALUE_TYPE, ALLOCATOR> > : bsl::true_type { }; } // close namespace bslalg namespace bslmf { template <class VALUE_TYPE, class ALLOCATOR> struct IsBitwiseMoveable<bsl::deque<VALUE_TYPE, ALLOCATOR> > : IsBitwiseMoveable<ALLOCATOR> { }; } // close namespace bslmf namespace bslma { template <class VALUE_TYPE, class ALLOCATOR> struct UsesBslmaAllocator<bsl::deque<VALUE_TYPE, ALLOCATOR> > : bsl::is_convertible<Allocator *, ALLOCATOR> { }; } // close namespace bslma } // close enterprise namespace #endif // End C++11 code #endif // ---------------------------------------------------------------------------- // Copyright 2013 Bloomberg Finance L.P. // // Licensed 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. // ----------------------------- END-OF-FILE ----------------------------------