// bslalg_arrayprimitives.h -*-C++-*- #ifndef INCLUDED_BSLALG_ARRAYPRIMITIVES #define INCLUDED_BSLALG_ARRAYPRIMITIVES #include <bsls_ident.h> BSLS_IDENT("$Id$ $CSID$") //@PURPOSE: Provide primitive algorithms that operate on arrays. // //@CLASSES: // bslalg::ArrayPrimitives: namespace for array algorithms // //@SEE_ALSO: bslalg_dequeprimitives, bslma_constructionutil // //@DESCRIPTION: This component provides utilities to initialize, move, and // otherwise perform various primitive manipulations on arrays with a uniform // interface, but selecting a different implementation according to the various // traits possessed by the underlying type. Such primitives are exceptionally // useful for implementing generic components such as containers. // // Several algorithms are provided, with the following short synopsis // describing the observable behavior and mentioning the relevant traits. See // the full function-level contract for detailed description, including // exception-safety guarantees. In the description below, 'ADP' stands for // 'bslalg::ArrayDestructionPrimitives'. Note that some algorithms (e.g., // 'insert') are explained in terms of previous algorithms (e.g., // 'destructiveMove'). //.. // Algorithm Short description of observable behavior // ---------------------------- --------------------------------------------- // defaultConstruct Construct each element in the target range // by value-initialization, or 'std::memset' if // type has a trivial default constructor. // Note that this function *does* *not* perform // default-initialization, the colloquial // terminology "default construct" is maintained // for backwards compatibility. // // uninitializedFillN Copy construct from value for each element in // the target range, or 'std::memset' if value // is all 0s or 1s bits, and type is bit-wise // copyable // // copyConstruct Copy construct from each element in the // original range to the corresponding element // in the target range, or 'std::memcpy' if // value is null and type is bit-wise copyable // // destructiveMove Copy from each element in the original range // to the corresponding element in the target // and destroy objects in the original range, or // 'std::memcpy' if type is bit-wise moveable // // destructiveMoveAndInsert 'destructiveMove' from the original range to // target range, leaving a hole in the middle, // followed by 'defaultConstruct', // 'uninitializedFillN' or 'copyConstruct' to // fill hole with the appropriate values // // destructiveMoveAndMoveInsert 'destructiveMove' from the original range to // the target range, leaving a hole in the // middle, followed by 'destructiveMove' // from second range to fill hole // // insert 'std::memmove' or 'copyConstruct' by some // positive offset to create a hole, followed by // 'uninitializedFillN', 'copyConstruct', or // copy assignment to fill hole with the // appropriate values // // emplace 'std::memmove' or 'copyConstruct' by some // positive offset to create a hole, followed by // in-place construction, 'copyConstruct', or // copy assignment to fill hole with the // appropriate values // // moveInsert 'destructiveMove' by some positive offset to // create a hole, followed by 'destructiveMove' // to fill hole with the appropriate values // // erase 'ADP::destroy' elements in target range until // specified position, followed by // 'destructiveMove' by some negative offset // from the end of the range to fill hole with // the remaining values // // rotate 'destructiveMove' to move elements into a // shifting hole along parallel cyclic // permutations, or 'std::memmove' for small // rotations if type is bit-wise moveable //.. // The traits under consideration by this component are: //.. // Trait English description // -------------------------------------------- ----------------------------- // bsl::is_trivially_default_constructible "TYPE has the trivial default // constructor trait", or // "TYPE has a trivial default // constructor" // // bsl::is_trivially_copyable "TYPE has the bit-wise // copyable trait", or // "TYPE is bit-wise copyable" // // bslmf::IsBitwiseMoveable "TYPE has the bit-wise // moveable trait", or // "TYPE is bit-wise moveable" //.. // ///Aliasing ///-------- // There are some aliasing concerns in this component, due to the presence of // the reference 'const TARGET_TYPE& value' argument, which may belong to a // range that will be modified during the course of the operation. All such // aliasing concerns are taken care of properly. Other aliasing concerns due // to the copying or a range '[first, last)' are *not* taken care of, since // their intended use is for range assignments and insertions in standard // containers, for which the standard explicitly says that 'first' and 'last' // shall not be iterators into the container. // ///Usage ///----- // In this section we show intended use of this component. // ///Example 1: Defining a Vector-Like Type /// - - - - - - - - - - - - - - - - - - - // Suppose we want to define a STL-vector-like type. One requirement is that // an object of this vector should forward its allocator to its contained // elements when appropriate. Another requirement is that the vector should // take advantage of the optimizations available for certain traits of the // contained element type. For example, if the contained element type has the // 'bslmf::IsBitwiseMoveable' trait, moving an element in a vector can be done // using 'memcpy' instead of copy construction. // // We can utilize the class methods provided by 'bslalg::ArrayPrimitives' to // satisfy the above requirements. Unlike 'bslma::ConstructionUtil', which // operates on a single element, 'bslalg::ArrayPrimitives' operates on arrays, // which will further help simplify our implementation. // // First, we create an elided definition of the class template 'MyVector': //.. // template <class TYPE, class ALLOC> // class MyVector { // // This class implements a vector of elements of the (template // // parameter) 'TYPE', which must be copy constructible. Note that for // // the brevity of the usage example, this class does not provide any // // Exception-Safety guarantee. // // // DATA // TYPE *d_array_p; // pointer to the allocated array // int d_capacity; // capacity of the allocated array // int d_size; // number of objects // ALLOC d_allocator; // allocator pointer (held, not owned) // // public: // // TYPE TRAITS // BSLMF_NESTED_TRAIT_DECLARATION( // MyVector, // BloombergLP::bslmf::IsBitwiseMoveable); // // // CREATORS // explicit MyVector(bslma::Allocator *basicAllocator = 0) // // Construct a 'MyVector' object having a size of 0 and and a // // capacity of 0. Optionally specify a 'basicAllocator' used to // // supply memory. If 'basicAllocator' is 0, the currently // // installed default allocator is used. // : d_array_p(0) // , d_capacity(0) // , d_size(0) // , d_allocator_p(bslma::Default::allocator(basicAllocator)) // { // } // // MyVector(const MyVector& original, // bslma::Allocator *basicAllocator = 0); // // Create a 'MyVector' object having the same value as the // // specified 'original' object. Optionally specify a // // 'basicAllocator' used to supply memory. If 'basicAllocator' is // // 0, the currently installed default allocator is used. // // // ... // // // MANIPULATORS // void reserve(int minCapacity); // // Change the capacity of this vector to at least the specified // // 'minCapacity' if it is greater than the vector's current // // capacity. // // void insert(int dstIndex, int numElements, const TYPE& value); // // Insert, into this vector, the specified 'numElements' of the // // specified 'value' at the specified 'dstIndex'. The behavior is // // undefined unless '0 <= dstIndex <= size()'. // // // ACCESSORS // const TYPE& operator[](int position) const // // Return a reference providing non-modifiable access to the // // element at the specified 'position' in this vector. // { // return d_array_p[position]; // } // // int size() const // // Return the size of this vector. // { // return d_size; // } // }; //.. // Then, we implement the copy constructor of 'MyVector': //.. // template <class TYPE> // MyVector<TYPE>::MyVector(const MyVector<TYPE>& original, // bslma::Allocator *basicAllocator) // : d_array_p(0) // , d_capacity(0) // , d_size(0) // , d_allocator_p(bslma::Default::allocator(basicAllocator)) // { // reserve(original.d_size); //.. // Here, we call the 'bslalg::ArrayPrimitives::copyConstruct' class method to // copy each element from 'original.d_array_p' to 'd_array_p' (When // appropriate, this class method passes this vector's allocator to the copy // constructor of 'TYPE' or uses bit-wise copy.): //.. // bslalg::ArrayPrimitives::copyConstruct( // d_array_p, // original.d_array_p, // original.d_array_p + original.d_size, // d_allocator_p); // // d_size = original.d_size; // } //.. // Now, we implement the 'reserve' method of 'MyVector': //.. // template <class TYPE> // void MyVector<TYPE>::reserve(int minCapacity) // { // if (d_capacity >= minCapacity) return; // RETURN // // TYPE *newArrayPtr = static_cast<TYPE*>(d_allocator_p->allocate( // BloombergLP::bslma::Allocator::size_type(minCapacity * sizeof(TYPE)))); // // if (d_array_p) { //.. // Here, we call the 'bslalg::ArrayPrimitives::destructiveMove' class method to // copy each original element from 'd_array_p' to 'newArrayPtr' and then // destroy all the original elements (When appropriate, this class method // passes this vector's allocator to the copy constructor of 'TYPE' or uses // bit-wise copy.): //.. // bslalg::ArrayPrimitives::destructiveMove(newArrayPtr, // d_array_p, // d_array_p + d_size, // d_allocator_p); // d_allocator_p->deallocate(d_array_p); // } // // d_array_p = newArrayPtr; // d_capacity = minCapacity; // } //.. // Finally, we implement the 'insert' method of 'MyVector': //.. // template <class TYPE> // void // MyVector<TYPE>::insert(int dstIndex, int numElements, const TYPE& value) // { // int newSize = d_size + numElements; // // if (newSize > d_capacity) { // int newCapacity = d_capacity == 0 ? 2 : d_capacity * 2; // reserve(newCapacity); // } //.. // Here, we call the 'bslalg::ArrayPrimitives::insert' class method to first // move each element after 'dstIndex' by 'numElements' and then copy construct // 'numElements' of 'value' at 'dstIndex'. (When appropriate, this class // method passes this vector's allocator to the copy constructor of 'TYPE' or // uses bit-wise copy.): //.. // bslalg::ArrayPrimitives::insert(d_array_p + dstIndex, // d_array_p + d_size, // value, // numElements, // d_allocator_p); // // d_size = newSize; // } //.. #include <bslscm_version.h> #include <bslalg_arraydestructionprimitives.h> #include <bslalg_autoarraydestructor.h> #include <bslalg_autoarraymovedestructor.h> #include <bslma_allocator.h> #include <bslma_allocatortraits.h> #include <bslma_constructionutil.h> #include <bslma_default.h> #include <bslma_destructorproctor.h> #include <bslma_stdallocator.h> #include <bslmf_assert.h> #include <bslmf_functionpointertraits.h> #include <bslmf_integralconstant.h> #include <bslmf_isbitwisemoveable.h> #include <bslmf_isconvertible.h> #include <bslmf_isenum.h> #include <bslmf_isfundamental.h> #include <bslmf_ismemberpointer.h> #include <bslmf_ispointer.h> #include <bslmf_issame.h> #include <bslmf_istriviallycopyable.h> #include <bslmf_istriviallydefaultconstructible.h> #include <bslmf_isvoid.h> #include <bslmf_matchanytype.h> #include <bslmf_metaint.h> #include <bslmf_removeconst.h> #include <bslmf_removecv.h> #include <bslmf_removepointer.h> #include <bslmf_util.h> // 'forward(V)' #include <bsls_alignmentutil.h> #include <bsls_assert.h> #include <bsls_compilerfeatures.h> #include <bsls_objectbuffer.h> #include <bsls_performancehint.h> #include <bsls_platform.h> #include <bsls_types.h> #include <bsls_util.h> // 'forward<T>(V)' #include <cstddef> // 'std::size_t' #include <cstring> // 'memset', 'memcpy', 'memmove' #include <cwchar> // 'wmemset' #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <bslalg_constructorproxy.h> #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 bslalg_arrayprimitives.h # define COMPILING_BSLALG_ARRAYPRIMITIVES_H # include <bslalg_arrayprimitives_cpp03.h> # undef COMPILING_BSLALG_ARRAYPRIMITIVES_H #else #if defined(BSLS_PLATFORM_CMP_IBM) // IBM needs specific workarounds. # define BSLALG_ARRAYPRIMITIVES_CANNOT_REMOVE_POINTER_FROM_FUNCTION_POINTER 1 // xlC has problem removing pointer from function pointer types. # define BSLALG_ARRAYPRIMITIVES_NON_ZERO_NULL_VALUE_FOR_MEMBER_POINTERS 1 // xlC representation for a null member pointer is not all zero bits. #endif namespace BloombergLP { namespace bslalg { struct ArrayPrimitives_Imp; // ====================== // struct ArrayPrimitives // ====================== struct ArrayPrimitives { // This 'struct' provides a namespace for a suite of independent utility // functions that operate on arrays of elements of parameterized type // 'TARGET_TYPE'. Depending on the traits of 'TARGET_TYPE', the default // and copy constructors, destructor, assignment operators, etcetera may // not be invoked, optimized away by no-op or bit-wise move or copy. public: // TYPES typedef ArrayPrimitives_Imp Imp; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; // CLASS METHODS template <class ALLOCATOR, class FWD_ITER> static void copyConstruct( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, ALLOCATOR allocator); template <class ALLOCATOR, class SOURCE_TYPE> static void copyConstruct( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, SOURCE_TYPE *fromBegin, SOURCE_TYPE *fromEnd, ALLOCATOR allocator); // Copy the elements of type 'allocator_traits<ALLOCATOR>::value_type' // in the range beginning at the specified 'fromBegin' location and // ending immediately before the specified 'fromEnd' location into the // uninitialized array beginning at the specified 'toBegin' location, // using the specified 'allocator' to supply memory (if required). If // a constructor throws an exception during this operation, the output // array is left in an uninitialized state. The behavior is undefined // unless 'toBegin' refers to space sufficient to hold // 'fromEnd - fromBegin' elements. template <class TARGET_TYPE, class FWD_ITER> static void copyConstruct(TARGET_TYPE *toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, bslma::Allocator *allocator); template <class TARGET_TYPE, class SOURCE_TYPE> static void copyConstruct(TARGET_TYPE *toBegin, SOURCE_TYPE *fromBegin, SOURCE_TYPE *fromEnd, bslma::Allocator *allocator); // Copy into an uninitialized array of (the template parameter) // 'TARGET_TYPE' beginning at the specified 'toBegin' address, the // elements in the array of 'TARGET_TYPE' starting at the specified // 'fromBegin' address and ending immediately before the specified // 'fromEnd' address. If the (template parameter) 'ALLOCATOR' type is // derived from 'bslma::Allocator' and 'TARGET_TYPE' supports 'bslma' // allocators, then the specified 'allocator' is passed to each // invocation of the 'TARGET_TYPE' copy constructor. If a // 'TARGET_TYPE' constructor throws an exception during the operation, // then the destructor is called on any newly-constructed elements, // leaving the output array in an uninitialized state. template <class ALLOCATOR> static void moveConstruct( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, ALLOCATOR allocator); // Move the elements of type 'allocator_traits<ALLOCATOR>::value_type' // in the range beginning at the specified 'fromBegin' location and // ending immediately before the specified 'fromEnd' location into the // uninitialized array beginning at the specified 'toBegin' location, // using the specified 'allocator' to supply memory (if required). The // elements in the input array are left in a valid but unspecified // state. If a constructor throws an exception during this operation, // the output array is left in an uninitialized state. The behavior is // undefined unless 'toBegin' refers to space sufficient to hold // 'fromEnd - fromBegin' elements. template <class TARGET_TYPE> static void moveConstruct(TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, bslma::Allocator *allocator); // Move the elements of the (template parameter) 'TARGET_TYPE' starting // at the specified 'fromBegin' address and ending immediately before // the specified 'fromEnd' address into the uninitialized array of // 'TARGET_TYPE' beginning at the specified 'toBegin' address, using // the specified 'allocator' to supply memory (if required). The // elements in the input array are left in a valid but unspecified // state. If a constructor throws an exception during this operation, // the output array is left in an uninitialized state. The behavior is // undefined unless 'toBegin' refers to space sufficient to hold // 'fromEnd - fromBegin' elements. template <class ALLOCATOR> static void defaultConstruct( typename bsl::allocator_traits<ALLOCATOR>::pointer begin, size_type numElements, ALLOCATOR allocator); // Value-inititalize the specified 'numElements' objects of type // 'allocator_traits<ALLOCATOR>::value_type' into the uninitialized // array beginning at the specified 'begin' location, using the // specified 'allocator' to supply memory (if required). If a // constructor throws an exception during this operation, then the // destructor is called on any newly constructed elements, leaving the // output array in an uninitialized state. The behavior is undefined // unless the 'begin' refers to space sufficient to hold 'numElements'. template <class TARGET_TYPE> static void defaultConstruct(TARGET_TYPE *begin, size_type numElements, bslma::Allocator *allocator); // Construct each of the elements of an array of the specified // 'numElements' of the parameterized 'TARGET_TYPE' starting at the // specified 'begin' address by value-initialization. If the (template // parameter) 'ALLOCATOR' type is derived from 'bslma::Allocator' and // 'TARGET_TYPE' supports 'bslma' allocators, then the specified // 'allocator' is passed to each 'TARGET_TYPE' default constructor // call. The behavior is undefined unless the output array contains at // least 'numElements' uninitialized elements after 'begin'. If a // 'TARGET_TYPE' constructor throws an exception during this operation, // then the destructor is called on any newly-constructed elements, // leaving the output array in an uninitialized state. template <class ALLOCATOR> static void destructiveMove( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, ALLOCATOR allocator); // Move the elements of type 'allocator_traits<ALLOCATOR>::value_type' // in the range beginning at the specified 'fromBegin' location and // ending immediately before the specified 'fromEnd' location into the // uninitialized array beginning at the specified 'toBegin' location, // using the specified 'allocator' to supply memory (if required). On // return, the elements in the input range are invalid, i.e., their // destructors must not be called after this operation returns. If a // constructor throws an exception during this operation, the output // array is left in an uninitialized state. If a constructor other // than the move constructor of a non-copy-constructible type throws // an exception during this operation, the input array is unaffected; // otherwise, if the move constructor of a non-copy-constructible type // throws an exception during this operation, the input array is left // in a valid but unspecified state. The behavior is undefined unless // 'toBegin' refers to space sufficient to hold 'fromEnd - fromBegin' // elements. template <class TARGET_TYPE> static void destructiveMove(TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, bslma::Allocator *allocator); // Move the elements of the parameterized 'TARGET_TYPE' in the array // starting at the specified 'fromBegin' address and ending immediately // before the specified 'fromEnd' address into an uninitialized array // of 'TARGET_TYPE' beginning at the specified 'toBegin' address. On // return, the elements in the input range are invalid, i.e., their // destructors must not be called after this operation returns. If the // parameterized 'ALLOCATOR' type is derived from 'bslma::Allocator' // and 'TARGET_TYPE' supports 'bslma' allocators, then the specified // 'allocator' is used by the objects in their new location. If an // exception is thrown by a 'TARGET_TYPE' constructor during the // operation, then the output array is left in an uninitialized state // and the input elements remain in their original state. #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=10 template <class ALLOCATOR, class... ARGS> static void destructiveMoveAndEmplace( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer position, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, ALLOCATOR allocator, ARGS&&... arguments); // Move the elements of type 'allocator_traits<ALLOCATOR>::value_type' // in the specified range '[fromBegin .. fromEnd)' into the // uninitialized array beginning at the specified 'toBegin' location, // using the specified 'allocator' to supply memory (if required), // inserting at the specified 'position' (after translating from // 'fromBegin' to 'toBegin') a newly created object constructed by // forwarding 'allocator' (if required) and the specified (variable // number of) 'arguments' to the corresponding constructor of the // target type, ensuring that the specified 'fromEndPtr' points to the // first uninitialized element in '[fromBegin .. fromEnd)' as the // elements are moved from source to destination. On return, the // elements in the input range are invalid, i.e., their destructors // must not be called after this operation returns. If a constructor // throws an exception during this operation, the output array is left // in an uninitialized state. If an exception is thrown during the // in-place construction of the new object, the input array is // unaffected; otherwise, if a (copy or move) constructor throws an // exception during this operation, the input elements in the range // '[fromBegin .. *fromEndPtr)' are left in a valid but unspecified // state and the remaining portion of the input array is left in an // uninitialized state. The behavior is undefined unless // 'fromBegin <= position <= fromEnd' and 'toBegin' refers to space // sufficient to hold 'fromEnd - fromBegin + 1' elements. #endif template <class ALLOCATOR> static void destructiveMoveAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer position, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, size_type numElements, ALLOCATOR allocator); // Move the elements of type 'allocator_traits<ALLOCATOR>::value_type' // in the range beginning at the specified 'fromBegin' location and // ending immediately before the specified 'fromEnd' location into the // uninitialized array beginning at the specified 'toBegin' location // using the specified 'allocator' to supply memory (if required), // inserting at the specified 'position' (after translating from // 'fromBegin' to 'toBegin') the specified 'numElements' objects // initialized to default values, ensuring that the specified // 'fromEndPtr' points to the first uninitialized element in // '[fromBegin .. fromEnd)' as the elements are moved from source to // destination. On return, the elements in the input range are // invalid, i.e., their destructors must not be called after this // operation returns. If a constructor throws an exception during this // operation, the output array is left in an uninitialized state. If a // default constructor throws an exception, the input array is // unaffected; otherwise, if a (copy or move) constructor throws an // exception during this operation, the input elements in the range // '[fromBegin .. *fromEndPtr)' are left in a valid but unspecified // state and the remaining portion of the input array is left in an // uninitialized state. The behavior is undefined unless 'fromBegin <= // position <= fromEnd' and 'toBegin' refers to space sufficient to // hold 'fromEnd - fromBegin + 1' elements. template <class TARGET_TYPE> static void destructiveMoveAndInsert(TARGET_TYPE *toBegin, TARGET_TYPE **fromEndPtr, TARGET_TYPE *fromBegin, TARGET_TYPE *position, TARGET_TYPE *fromEnd, size_type numElements, bslma::Allocator *allocator); // Move the elements of the (template parameter) 'TARGET_TYPE' in the // starting at the specified 'fromBegin' address and ending immediately // before the specified 'fromEnd' address into the uninitialized array // beginning at the specified 'toBegin' location using the specified // 'allocator' to supply memory (if required), inserting at the // specified 'position' (after translating from 'fromBegin' to // 'toBegin') 'numElements' objects initialized to default values, // ensuring that the specified 'fromEndPtr' points to the first // uninitialized element in '[fromBegin .. fromEnd)' as the elements // are moved from source to destination. On return, the elements in // the input range are invalid, i.e., their destructors must not be // called after this operation returns. If a constructor throws an // exception during this operation, the output array is left in an // uninitialized state. If a default constructor throws an exception, // the input array is unaffected; otherwise, if a (copy or move) // constructor throws an exception during this operation, the input // elements in the range '[fromBegin .. *fromEndPtr)' are left in a // valid but unspecified state and the remaining portion of the input // array is left in an uninitialized state. The behavior is undefined // unless 'fromBegin <= position <= fromEnd' and 'toBegin' refers to // space sufficient to hold 'fromEnd - fromBegin + numElements' // elements. template <class ALLOCATOR> static void destructiveMoveAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer position, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, const typename bsl::allocator_traits<ALLOCATOR>::value_type& value, size_type numElements, ALLOCATOR allocator); // Move the elements of type 'allocator_traits<ALLOCATOR>::value_type' // in the range beginning at the specified 'fromBegin' location and // ending immediately before the specified 'fromEnd' location into the // uninitialized array beginning at the specified 'toBegin' location // using the specified 'allocator' to supply memory (if required), // inserting at the specified 'position' (after translating from // 'fromBegin' to 'toBegin') the specified 'numElements' copies of the // specified 'value', ensuring that the specified 'fromEndPtr' points // to the first uninitialized element in '[fromBegin .. fromEnd)' as // the elements are moved from source to destination. On return, the // elements in the input range are invalid, i.e., their destructors // must not be called after this operation returns. If a constructor // throws an exception during this operation, the output array is left // in an uninitialized state. If a (copy or move) constructor throws // an exception during this operation, the input elements in the range // '[fromBegin .. *fromEndPtr)' are left in a valid but unspecified // state and the remaining portion of the input array is left in an // uninitialized state. The behavior is undefined unless // 'fromBegin <= position <= fromEnd' and 'toBegin' refers to space // sufficient to hold 'fromEnd - fromBegin + numElements' elements. template <class TARGET_TYPE> static void destructiveMoveAndInsert(TARGET_TYPE *toBegin, TARGET_TYPE **fromEndPtr, TARGET_TYPE *fromBegin, TARGET_TYPE *position, TARGET_TYPE *fromEnd, const TARGET_TYPE& value, size_type numElements, bslma::Allocator *allocator); // Move the elements of the parameterized 'TARGET_TYPE' in the array // starting at the specified 'fromBegin' address and ending immediately // before the specified 'fromEnd' address into an uninitialized array // of 'TARGET_TYPE' at the specified 'toBegin' address, inserting at // the specified 'position' (after translating from 'fromBegin' to // 'toBegin') the specified 'numElements' copies of the specified // 'value'. Keep the pointer at the specified 'fromEndPtr' address // pointing to the first uninitialized element in '[ fromBegin, // fromEnd)' as the elements are moved from source to destination. The // behavior is undefined unless 'fromBegin <= position <= fromEnd' and // the destination array contains at least // '(fromEnd - fromBegin) + numElements' uninitialized elements. If a // copy constructor or assignment operator for 'TARGET_TYPE' throws an // exception, then any elements created in the output array are // destroyed and the elements in the range '[ fromBegin, *fromEndPtr )' // will have unspecified but valid values. template <class ALLOCATOR, class FWD_ITER> static void destructiveMoveAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer position, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, FWD_ITER first, FWD_ITER last, size_type numElements, ALLOCATOR allocator); // Move the elements of type 'allocator_traits<ALLOCATOR>::value_type' // in the range beginning at the specified 'fromBegin' location and // ending immediately before the specified 'fromEnd' location into the // uninitialized array beginning at the specified 'toBegin' location // using the specified 'allocator' to supply memory (if required), // inserting at the specified 'position' (after translating from // 'fromBegin' to 'toBegin') the specified 'numElements' copies of the // non-modifiable elements from the range starting at the specified // 'first' iterator of (template parameter) type 'FWD_ITER' and ending // immediately before the specified 'last' iterator, ensuring that the // specified 'fromEndPtr' points to the first uninitialized element in // '[fromBegin .. fromEnd)' as the elements are moved from source to // destination. On return, the elements in the input range are // invalid, i.e., their destructors must not be called after this // operation returns. If a constructor throws an exception during this // operation, the output array is left in an uninitialized state. If // a constructor other than the copy or move constructor throws an // exception during this operation, the input array is unaffected; // otherwise, if a copy or move constructor throws an exception during // this operation, the input elements in the range // '[fromBegin .. *fromEndPtr)' are left in a valid but unspecified // state and the remaining portion of the input array is left in an // uninitialized state. The behavior is undefined unless // 'fromBegin <= position <= fromEnd' and 'toBegin' refers to space // sufficient to hold 'fromEnd - fromBegin + numElements' elements. template <class TARGET_TYPE, class FWD_ITER> static void destructiveMoveAndInsert(TARGET_TYPE *toBegin, TARGET_TYPE **fromEndPtr, TARGET_TYPE *fromBegin, TARGET_TYPE *position, TARGET_TYPE *fromEnd, FWD_ITER first, FWD_ITER last, size_type numElements, bslma::Allocator *allocator); // Move the elements of the parameterized 'TARGET_TYPE' in the array // starting at the specified 'fromBegin' address and ending immediately // before the specified 'fromEnd' address into an uninitialized array // of 'TARGET_TYPE' at the specified 'toBegin' address, inserting at // the specified 'position' (after translating from 'fromBegin' to // 'toBegin') the specified 'numElements' copies of the non-modifiable // elements from the range starting at the specified 'first' iterator // of the parameterized 'FWD_ITER' type and ending immediately before // the specified 'last' iterator. Keep the pointer at the specified // 'fromEndPtr' to point to the first uninitialized element in // '[fromBegin, fromEnd)' as the elements are moved from source to // destination. The behavior is undefined unless // 'fromBegin <= position <= fromEnd', the destination array contains // at least '(fromEnd - fromBegin) + numElements' uninitialized // elements after 'toBegin', and 'numElements' is the distance from // 'first' to 'last'. If a copy constructor or assignment operator for // 'TARGET_TYPE' throws an exception, then any elements created in the // output array are destroyed and the elements in the range // '[ fromBegin, *fromEndPtr )' will have unspecified but valid values. template <class ALLOCATOR> static void destructiveMoveAndMoveInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer *lastPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer position, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, typename bsl::allocator_traits<ALLOCATOR>::pointer first, typename bsl::allocator_traits<ALLOCATOR>::pointer last, size_type numElements, ALLOCATOR allocator); // TBD: improve comment // Move, into an uninitialized array beginning at the specified // 'toBegin' pointer, elements of type given by the 'allocator_traits' // class template for (template parameter) 'ALLOCATOR', from elements // starting at the specified 'fromBegin' pointer and ending immediately // before the specified 'fromEnd' address, moving into the specified // 'position' (after translating from 'fromBegin' to 'toBegin') the // specified 'numElements' elements starting at the specified 'first' // pointer and ending immediately before the specified 'last' pointer. // Keep the pointer at the specified 'fromEndPtr' address pointing to // the first uninitialized element in '[ fromBegin, fromEnd)' as the // elements are moved from source to destination. The behavior is // undefined unless 'fromBegin <= position <= fromEnd' and the // destination array contains at least // '(fromEnd - fromBegin) + numElements' uninitialized elements. If a // constructor or assignment operator for the target type throws an // exception, then any elements created in the output array are // destroyed and the elements in the range '[ fromBegin, *fromEndPtr )' // will have valid but unspecified values. template <class TARGET_TYPE> static void destructiveMoveAndMoveInsert(TARGET_TYPE *toBegin, TARGET_TYPE **fromEndPtr, TARGET_TYPE **lastPtr, TARGET_TYPE *fromBegin, TARGET_TYPE *position, TARGET_TYPE *fromEnd, TARGET_TYPE *first, TARGET_TYPE *last, size_type numElements, bslma::Allocator *allocator); // Move the elements of (template parameter) 'TARGET_TYPE' in the array // starting at the specified 'fromBegin' address and ending immediately // before the specified 'fromEnd' address into an uninitialized array // of 'TARGET_TYPE' at the specified 'toBegin' address, moving into the // specified 'position' (after translating from 'fromBegin' to // 'toBegin') the specified 'numElements' of the 'TARGET_TYPE' from the // array starting at the specified 'first' address and ending // immediately before the specified 'last' address. Keep the pointer // at the specified 'fromEndPtr' address pointing to the first // uninitialized element in '[fromBegin, fromEnd)', and the pointer at // the specified 'lastPtr' address pointing to the end of the moved // range as the elements from the range '[ first, last)' are moved from // source to destination. The behavior is undefined unless // 'fromBegin <= position <= fromEnd', the destination array contains // at least '(fromEnd - fromBegin) + numElements' uninitialized // elements after 'toBegin', and 'numElements' is the distance from // 'first' to 'last'. If a copy constructor or assignment operator for // 'TARGET_TYPE' throws an exception, then any elements in // '[ *lastPtr, last )' as well as in '[ toBegin, ... )' are destroyed, // and the elements in the ranges '[ first, *lastPtr )' and // '[ fromBegin, *fromEndPtr )' will have unspecified but valid values. #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=10 template <class ALLOCATOR, class... ARGS> static void emplace( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, ALLOCATOR allocator, ARGS&&... arguments); // Insert a newly created 'allocator_traits<ALLOCATOR>::value_type' // object, constructed by forwarding the specified 'allocator' (if // required) and the specified (variable number of) 'arguments' to the // corresponding constructor of // 'allocator_traits<ALLOCATOR>::value_type', into the array at the // specified 'toBegin' location, shifting forward the elements from // 'toBegin' to the specified 'toEnd' location by one position. If an // exception is thrown during the in-place construction of the new // object, the elements in the range '[toBegin .. toEnd)' are // unaffected; otherwise, if a (copy or move) constructor or a (copy or // move) assignment operator throws an exception, then any elements // created after 'toEnd' are destroyed and the elements in the range // '[toBegin .. toEnd )' are left in a valid but unspecified state. // The behavior is undefined unless 'toBegin' refers to sufficient // space to hold at least 'toEnd - toBegin + 1' elements. template <class TARGET_TYPE, class... ARGS> static void emplace(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, bslma::Allocator *allocator, ARGS&&... args); // Insert a newly created object of the (template parameter) type // 'TARGET_TYPE', constructed by forwarding the specified 'allocator' // (if required) and the specified (variable number of) 'arguments' to // the corresponding constructor of 'TARGET_TYPE', into the array at // the specified 'toBegin' address, shifting the elements from // 'toBegin' to the specified 'toEnd' address up one position towards // larger addresses. If an exception is thrown during the in-place // construction of the new object, the elements in the range // '[toBegin .. toEnd)' are unaffected; otherwise, if a (copy or move) // constructor or a (copy or move) assignment operator throws an // exception, then any elements created after 'toEnd' are destroyed and // the elements in the range '[toBegin .. toEnd )' are left in a valid // but unspecified state. The behavior is undefined unless 'toBegin' // refers to sufficient space to hold at least 'toEnd - toBegin + 1' // elements. #endif #if defined(BSLS_PLATFORM_CMP_MSVC) && BSLS_PLATFORM_CMP_VERSION < 1900 template <class CLASS_TYPE, class MEMBER_TYPE, class... ARGS> static void emplace(MEMBER_TYPE CLASS_TYPE::* *toBegin, MEMBER_TYPE CLASS_TYPE::* *toEnd, bslma::Allocator *allocator) // Old Microsoft compilers need help value-initializing elements that // are pointer-to-member types. { emplace(toBegin, toEnd, allocator, nullptr); } #endif template <class ALLOCATOR> static void erase(typename bsl::allocator_traits<ALLOCATOR>::pointer first, typename bsl::allocator_traits<ALLOCATOR>::pointer middle, typename bsl::allocator_traits<ALLOCATOR>::pointer last, ALLOCATOR allocator); // TBD: improve comment // Destroy the elements of type given by the 'allocator_traits' class // template for (template parameter) 'ALLOCATOR' starting at the // specified 'first' 'first' pointer and ending immediately before the // specified 'middle' pointer, and move the elements in the array // starting at 'middle' and ending at the specified 'last' pointer down // to the 'first' pointer. If an assignment throws an exception during // this process, all of the elements in the range '[ first, last )' // will have unspecified but valid values, and no elements are // destroyed. The behavior is undefined unless // 'first <= middle <= last'. template <class TARGET_TYPE> static void erase(TARGET_TYPE *first, TARGET_TYPE *middle, TARGET_TYPE *last, bslma::Allocator *allocator = 0); // Destroy the elements of the parameterized 'TARGET_TYPE' in the array // starting at the specified 'first' address and ending immediately // before the specified 'middle' address, and move the elements in the // array starting at 'middle' and ending at the specified 'last' // address down to the 'first' address. If an assignment throws an // exception during this process, all of the elements in the range // '[ first, last )' will have unspecified but valid values, and no // elements are destroyed. The behavior is undefined unless // 'first <= middle <= last'. template <class ALLOCATOR> static void insert(typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, bslmf::MovableRef< typename bsl::allocator_traits<ALLOCATOR>::value_type> value, ALLOCATOR allocator); // Insert the specified 'value' into the array of // 'allocator_traits<ALLOCATOR>::value_type' objects at the specified // 'toBegin' location, shifting forward the elements from 'toBegin' to // the specified 'toEnd' location by one position. 'value' is left in // a valid but unspecified state. If a (copy or move) constructor or a // (copy or move) assignment operator throws an exception, then any // elements created after 'toEnd' are destroyed and the elements in the // range '[toBegin .. toEnd )' are left in a valid but unspecified // state. The behavior is undefined unless 'toBegin' refers to // sufficient space to hold at least 'toEnd - toBegin + 1' elements. template <class TARGET_TYPE> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, bslmf::MovableRef<TARGET_TYPE> value, bslma::Allocator *allocator); // Insert the specified 'value' into the array of the (template // parameter) type 'TARGET_TYPE' at the specified 'toBegin' address, // shifting the elements from 'toBegin' to the specified 'toEnd' // address by one position towards larger addresses. 'value' is left // in a valid but unspecified state. If a (copy or move) constructor // or a (copy or move) assignment operator throws an exception, then // any elements created after 'toEnd' are destroyed and the elements in // the range '[toBegin .. toEnd )' are left in a valid but unspecified // state. The behavior is undefined unless 'toBegin' refers to // sufficient space to hold at least 'toEnd - toBegin + 1' elements. template <class ALLOCATOR> static void insert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, const typename bsl::allocator_traits<ALLOCATOR>::value_type& value, size_type numElements, ALLOCATOR allocator); // Insert the specified 'numElements' copies of the specified 'value' // into the array of type 'allocator_traits<ALLOCATOR>::value_type' // starting at the specified 'toBegin' location, shifting forward the // elements from 'toBegin' to the specified 'toEnd' location by // 'numElements' positions. If a (copy or move) constructor or a (copy // or move) assignment operator throws an exception, any elements // created after 'toEnd' are destroyed and the elements in the range // '[toBegin .. toEnd)' are left in a valid but unspecified state. The // behavior is undefined unless 'toBegin' refers to space sufficient to // hold at least 'toEnd - toBegin + numElements' elements. template <class TARGET_TYPE> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, const TARGET_TYPE& value, size_type numElements, bslma::Allocator *allocator); // Insert the specified 'numElements' copies of the specified 'value' // into the array of (template parameter) 'TARGET_TYPE' starting at the // specified 'toBegin' address and ending immediately before the // specified 'toEnd' address, shifting the elements in the array by // 'numElements' positions towards larger addresses. The behavior is // undefined unless the destination array contains at least // 'numElements' uninitialized elements after 'toEnd'. If a copy // constructor or assignment operator for 'TARGET_TYPE' throws an // exception, then any elements created after 'toEnd' are destroyed and // the elements in the range '[ toBegin, toEnd )' will have // unspecified, but valid, values. template <class ALLOCATOR, class FWD_ITER> static void insert(typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, FWD_ITER fromBegin, FWD_ITER fromEnd, size_type numElements, ALLOCATOR allocator); template <class ALLOCATOR, class SOURCE_TYPE> static void insert(typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, SOURCE_TYPE *fromBegin, SOURCE_TYPE *fromEnd, size_type numElements, ALLOCATOR allocator); // TBD: improve comment // Insert the specified 'numElements' from the range starting at the // specified 'fromBegin' and ending immediately before the specified // 'fromEnd' iterators of (template parameter) 'FWD_ITER' type (or // template parameter 'SOURCE_TYPE *'), into the array of elements of // type given by the 'allocator_traits' class template for (template // parameter) 'ALLOCATOR', starting at the specified 'toBegin' address, // shifting forward the elements in the array by 'numElements' // positions. The behavior is undefined unless the destination array // contains 'numElements' uninitialized elements after 'toEnd', // 'numElements' is the distance between 'fromBegin' and 'fromEnd', // and the input array and the destination array do not overlap. If a // copy constructor or assignment operator throws an exception, then // any elements created after 'toEnd' are destroyed and the elements in // the range '[ toBegin, toEnd )' will have valid but unspecified // values. template <class TARGET_TYPE, class FWD_ITER> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, FWD_ITER fromBegin, FWD_ITER fromEnd, size_type numElements, bslma::Allocator *allocator); template <class TARGET_TYPE, class SOURCE_TYPE> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, SOURCE_TYPE *fromBegin, SOURCE_TYPE *fromEnd, size_type numElements, bslma::Allocator *allocator); // Insert, into the array at the specified 'toBegin' location, the // specified 'numElements' from the range starting at the specified // 'fromBegin' and ending immediately before the specified 'fromEnd' // iterators of the (template parameter) 'FWD_ITER' type (or the // (template parameter) 'SOURCE_TYPE *'), into the array of elements of // the parameterized 'TARGET_TYPE' starting at the specified 'toBegin' // address and ending immediately before the specified 'toEnd' address, // shifting the elements in the array by 'numElements' positions // towards larger addresses. The behavior is undefined unless the // destination array contains 'numElements' uninitialized elements // after 'toEnd', 'numElements' is the distance between 'fromBegin' and // 'fromEnd', and the input array and the destination array do not // overlap. If a copy constructor or assignment operator for // 'TARGET_TYPE' throws an exception, then any elements created after // 'toEnd' are destroyed and the elements in the range // '[ toBegin, toEnd )' will have unspecified, but valid, values. template <class ALLOCATOR> static void moveInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, size_type numElements, ALLOCATOR allocator); // TBD: improve comment // Move the elements of type given by the 'allocator_traits' class // template for (template parameter) 'ALLOCATOR' in the array starting // at the specified 'toBegin' location and ending immediately before // the specified 'toEnd' location by the specified 'numElements' // positions towards larger addresses, and fill the 'numElements' at // the 'toBegin' location by moving the elements from the array // starting at the specified 'fromBegin' and ending immediately before // the specified 'fromEnd' location. Keep the iterator at the // specified 'fromEndPtr' address pointing to the end of the range as // the elements from '[ fromBegin, fromEnd )' are moved from source to // destination. The behavior is undefined unless the destination array // contains 'numElements' uninitialized elements after 'toEnd', // 'numElements' is the distance from 'fromBegin' to 'fromEnd', and the // input and destination arrays do not overlap. If a copy constructor // or assignment operator for 'TARGET_TYPE' throws an exception, then // any elements created after 'toEnd' are destroyed, the elements in // the ranges '[ toBegin, toEnd)' and '[ fromBegin, *fromEndPtr )' will // have unspecified, but valid, values, and the elements in // '[ *fromEndPtr, fromEnd )' will be destroyed. template <class TARGET_TYPE> static void moveInsert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, TARGET_TYPE **fromEndPtr, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, size_type numElements, bslma::Allocator *allocator); // Move the elements of the (template parameter) 'TARGET_TYPE' in the // array starting at the specified 'toBegin' address and ending // immediately before the specified 'toEnd' address by the specified // 'numElements' positions towards larger addresses, and fill the // 'numElements' at the 'toBegin' address by moving the elements from // the array starting at the specified 'fromBegin' and ending // immediately before the specified 'fromEnd' address. Keep the // iterator at the specified 'fromEndPtr' address pointing to the end // of the range as the elements from '[ fromBegin, fromEnd )' are moved // from source to destination. The behavior is undefined unless the // destination array contains 'numElements' uninitialized elements // after 'toEnd', 'numElements' is the distance from 'fromBegin' to // 'fromEnd', and the input and destination arrays do not overlap. If // a copy constructor or assignment operator for 'TARGET_TYPE' throws // an exception, then any elements created after 'toEnd' are destroyed, // the elements in the ranges '[ toBegin, toEnd)' and // '[ fromBegin, *fromEndPtr )' will have unspecified, but valid, // values, and the elements in '[ *fromEndPtr, fromEnd )' will be // destroyed. template <class TARGET_TYPE> static void rotate(TARGET_TYPE *first, TARGET_TYPE *middle, TARGET_TYPE *last); // Move the elements of the parameterized 'TARGET_TYPE' in the array // starting at the specified 'first' address and ending immediately // before the specified 'middle' address to the array of the same // length ending at the specified 'last' address (and thus starting at // the 'last - (middle - first)' address), and move the elements // previously in the array starting at 'middle' and ending at 'last' // down to the 'first' address. If the assignment operator throws an // exception during this process, all of the elements in // '[ first, last )' will have unspecified, but valid, values. The // behavior is undefined unless 'first <= middle <= last'. template <class ALLOCATOR> static void uninitializedFillN( typename bsl::allocator_traits<ALLOCATOR>::pointer begin, size_type numElements, const typename bsl::allocator_traits<ALLOCATOR>::value_type& value, ALLOCATOR allocator); // TBD: improve comment // Construct copies of the specified 'value' of type given by the // 'allocator_traits' class template for (template parameter) // 'ALLOCATOR' into the uninitialized array containing the specified // 'numElements' starting at the specified 'begin' location. The // behavior is undefined unless the output array contains at least // 'numElements' uninitialized elements after 'begin'. If a // constructor throws an exception during the operation, then the // destructor is called on any newly-constructed elements, leaving the // output array in an uninitialized state. template <class TARGET_TYPE> static void uninitializedFillN(TARGET_TYPE *begin, size_type numElements, const TARGET_TYPE& value, bslma::Allocator *allocator); // Construct copies of the specified 'value' of the parameterized type // 'TARGET_TYPE' into the uninitialized array containing the specified // 'numElements' starting at the specified 'begin' address. If the // (template parameter) 'ALLOCATOR' type is derived from // 'bslma::Allocator' and 'TARGET_TYPE' supports 'bslma' allocators, // then the specified 'allocator' is passed to each invocation of the // 'TARGET_TYPE' copy constructor. The behavior is undefined unless // the output array contains at least 'numElements' uninitialized // elements after 'begin'. If a 'TARGET_TYPE' constructor throws an // exception during the operation, then the destructor is called on any // newly-constructed elements, leaving the output array in an // uninitialized state. Note that the argument order was chosen to // maintain compatibility with the existing 'bslalg'. }; // ========================== // struct ArrayPrimitives_Imp // ========================== struct ArrayPrimitives_Imp { // This 'struct' provides a namespace for a suite of independent utility // functions that operate on arrays of elements of a parameterized // 'TARGET_TYPE'. These utility functions are only for the purpose of // implementing those in the 'ArrayPrimitives' utility. For brevity, we do // not repeat the main contracts here, but instead refer to the // corresponding contract in the 'ArrayPrimitives' utility. private: // PRIVATE METHODS template <class TARGET_TYPE> static void assign(TARGET_TYPE *srcStart, TARGET_TYPE *srcEnd, TARGET_TYPE& value); // Copy-assign the specified 'value' to the range starting at the // specified 'srcStart' and ending immediately before the specified // 'srcEnd'. Note that the (template parameter) 'TARGET_TYPE' must be // copy-assignable. Also note that 'value' should not be an element in // the range '[srcStart, srcEnd)'. template <class TARGET_TYPE> static void reverseAssign(TARGET_TYPE *dest, TARGET_TYPE *srcStart, TARGET_TYPE *srcEnd); // Copy-assign the elements in reverse order from the range starting at // the specified 'srcStart' and ending immediately before the specified // 'srcEnd' to the range starting at the specified 'dest' and ending // immediately before 'dest + (srcEnd - srcStart)'. The behavior is // undefined unless each element is both range '[srcStart, srcEnd)' and // range '[dest, dest + (srcEnd - srcStart))' is valid. Note that the // (template parameter) 'TARGET_TYPE' must be copy-assignable. Also // note that this method is intended to support range assignment when // the two ranges may be overlapped, and 'srcStart <= dest'. public: // TYPES typedef ArrayPrimitives::size_type size_type; typedef ArrayPrimitives::difference_type difference_type; enum { // These constants are used in the overloads below, when the last // argument is of type 'bslmf::MetaInt<N> *', indicating that // 'TARGET_TYPE' has the traits for which the enumerator equal to 'N' // is named. e_IS_ITERATOR_TO_FUNCTION_POINTER = 6, e_IS_POINTER_TO_POINTER = 5, e_IS_FUNDAMENTAL_OR_POINTER = 4, e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS = 3, e_BITWISE_COPYABLE_TRAITS = 2, e_BITWISE_MOVEABLE_TRAITS = 1, e_NIL_TRAITS = 0 }; enum { // Number of bytes for which a stack-allocated buffer can be // comfortably obtained to optimize bitwise moves. k_INPLACE_BUFFER_SIZE = 16 * bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT }; // CLASS METHODS static void bitwiseFillN(char *begin, size_type numBytesInitialized, size_type numBytes); // Fill the specified 'numBytes' in the array starting at the specified // 'begin' address, as if by bit-wise copying the specified // 'numBytesInitialized' at every offset that is a multiple of // 'numBytesInitialized' within the output array. The behavior is // undefined unless 'numBytesInitialized <= numBytes'. Note that // 'numBytes' usually is, but does not have to be, a multiple of // 'numBytesInitialized'. static void uninitializedFillN( bool *begin, bool value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( char *begin, char value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( unsigned char *begin, unsigned char value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( signed char *begin, signed char value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( wchar_t *begin, wchar_t value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( short *begin, short value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( unsigned short *begin, unsigned short value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( int *begin, int value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( unsigned int *begin, unsigned int value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( long *begin, long value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( unsigned long *begin, unsigned long value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( bsls::Types::Int64 *begin, bsls::Types::Int64 value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( bsls::Types::Uint64 *begin, bsls::Types::Uint64 value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( float *begin, float value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( double *begin, double value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( long double *begin, long double value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( void **begin, void *value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( const void **begin, const void *value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( volatile void **begin, volatile void *value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); static void uninitializedFillN( const volatile void **begin, const volatile void *value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); template <class TARGET_TYPE> static void uninitializedFillN( TARGET_TYPE **begin, TARGET_TYPE *value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); template <class TARGET_TYPE> static void uninitializedFillN( const TARGET_TYPE **begin, const TARGET_TYPE *value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); template <class TARGET_TYPE> static void uninitializedFillN( volatile TARGET_TYPE **begin, volatile TARGET_TYPE *value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); template <class TARGET_TYPE> static void uninitializedFillN( const volatile TARGET_TYPE **begin, const volatile TARGET_TYPE *value, size_type numElements, void * = 0, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> * = 0); template <class TARGET_TYPE, class ALLOCATOR> static void uninitializedFillN( TARGET_TYPE *begin, const TARGET_TYPE& value, size_type numElements, ALLOCATOR *allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *); template <class TARGET_TYPE, class ALLOCATOR> static void uninitializedFillN(TARGET_TYPE *begin, const TARGET_TYPE& value, size_type numElements, ALLOCATOR *allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // Copy the specified 'value' of the parameterized 'TARGET_TYPE' into // every of the specified 'numElements' in the array starting at the // specified 'begin' address. Pass the specified 'allocator' to the // copy constructor if appropriate. Note that if 'TARGET_TYPE' is // bit-wise copyable or is not based on 'bslma::Allocator', 'allocator' // is ignored. The last argument is for removing overload ambiguities // and is not used. template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> static void copyConstruct(TARGET_TYPE *toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_IS_POINTER_TO_POINTER> *); template <class TARGET_TYPE, class ALLOCATOR> static void copyConstruct( TARGET_TYPE *toBegin, const TARGET_TYPE *fromBegin, const TARGET_TYPE *fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *); template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> static void copyConstruct(TARGET_TYPE *toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_IS_ITERATOR_TO_FUNCTION_POINTER> *); template <class FWD_ITER, class ALLOCATOR> static void copyConstruct(void **toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_IS_ITERATOR_TO_FUNCTION_POINTER> *); template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> static void copyConstruct(TARGET_TYPE *toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // These functions follow the 'copyConstruct' contract. If the // (template parameter) 'ALLOCATOR' type is based on 'bslma::Allocator' // and the 'TARGET_TYPE' constructors take an allocator argument, then // pass the specified 'allocator' to the copy constructor. The // behavior is undefined unless the output array has length at least // the distance from the specified 'fromBegin' to the specified // 'fromEnd'. Note that if 'FWD_ITER' is the 'TARGET_TYPE *' pointer // type and 'TARGET_TYPE' is bit-wise copyable, then this operation is // simply 'memcpy'. The last argument is for removing overload // ambiguities and is not used. template <class TARGET_TYPE, class ALLOCATOR> static void moveConstruct( TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *); template <class TARGET_TYPE, class ALLOCATOR> static void moveConstruct( TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // TBD: improve comment // Move-insert into an uninitialized array beginning at the specified // 'toBegin' pointer, elements of type given by the 'allocator_traits' // class template for (template parameter) 'ALLOCATOR' from elements // starting at the specified 'fromBegin' pointer and ending immediately // before the specified 'fromEnd' pointer. The elements in the range // '[fromBegin...fromEnd)' are left in a valid but unspecified state. // If a constructor throws an exception during the operation, then the // destructor is called on any newly-constructed elements, leaving the // output array in an uninitialized state. The behavior is undefined // unless 'toBegin' refers to space sufficient to hold // 'fromEnd - fromBegin' elements. template <class TARGET_TYPE, class ALLOCATOR> static void moveIfNoexcept( TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // TBD: improve comment // Either move- or copy-insert into an uninitialized array beginning at // the specified 'toBegin' pointer, elements of type given by the // 'allocator_traits' class template for (template parameter) // 'ALLOCATOR' from elements starting at the specified 'fromBegin' // pointer and ending immediately before the specified 'fromEnd' // pointer. The elements in the range '[fromBegin...fromEnd)' are left // in a valid but unspecified state. Use the move constructor if it is // guaranteed to not throw or if the target type does not define a copy // constructor; otherwise use the copy constructor. If a constructor // throws an exception during the operation, then the destructor is // called on any newly-constructed elements, leaving the output array // in an uninitialized state. The behavior is undefined unless // 'toBegin' refers to space sufficient to hold 'fromEnd - fromBegin' // elements. template <class TARGET_TYPE, class ALLOCATOR> static void defaultConstruct( TARGET_TYPE *begin, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS> *); template <class TARGET_TYPE, class ALLOCATOR> static void defaultConstruct( TARGET_TYPE *begin, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *); template <class TARGET_TYPE, class ALLOCATOR> static void defaultConstruct(TARGET_TYPE *begin, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // Use the default constructor of the (template parameter) // 'TARGET_TYPE' (or 'memset' to 0 if 'TARGET_TYPE' has a trivial // default constructor) on each element of the array starting at the // specified 'begin' address and ending immediately before the 'end' // address. Pass the specified 'allocator' to the default constructor // if appropriate. The last argument is for traits overloading // resolution only and its value is ignored. template <class TARGET_TYPE, class ALLOCATOR> static void destructiveMove( TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *); template <class TARGET_TYPE, class ALLOCATOR> static void destructiveMove(TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // These functions follow the 'destructiveMove' contract. Note that // both arrays cannot overlap (one contains only initialized elements // and the other only uninitialized elements), and that if // 'TARGET_TYPE' is bit-wise moveable, then this operation is simply // 'memcpy'. The last argument is for removing overload ambiguities // and is not used. #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES template <class TARGET_TYPE, class ALLOCATOR, class... ARGS> static void emplace(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *, ARGS&&... args); template <class TARGET_TYPE, class ALLOCATOR, class... ARGS> static void emplace(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *, ARGS&&... args); template <class TARGET_TYPE, class ALLOCATOR, class... ARGS> static void emplace(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *, ARGS&&... args); // TBD: document this #endif template <class TARGET_TYPE, class ALLOCATOR> static void erase(TARGET_TYPE *first, TARGET_TYPE *middle, TARGET_TYPE *last, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *); template <class TARGET_TYPE, class ALLOCATOR> static void erase(TARGET_TYPE *first, TARGET_TYPE *middle, TARGET_TYPE *last, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // These functions follow the 'erase' contract. Note that if (template // parameter) 'TARGET_TYPE' is bit-wise moveable, then this operation // can be implemented by first bit-wise moving the elements in // '[middle, last)' towards first, and destroying // '[ last - (middle - first), last)'; note that this cannot throw // exceptions. template <class TARGET_TYPE, class ALLOCATOR> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, const TARGET_TYPE& value, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *); template <class TARGET_TYPE, class ALLOCATOR> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, const TARGET_TYPE& value, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *); template <class TARGET_TYPE, class ALLOCATOR> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, const TARGET_TYPE& value, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // These functions follow the 'insert' contract. Note that if // 'TARGET_TYPE' is bit-wise copyable, then this operation is simply // 'memmove' followed by 'bitwiseFillN'. If 'TARGET_TYPE' is bit-wise // moveable, then this operation can still be optimized using 'memmove' // followed by repeated assignments, but a guard needs to be set up. // The last argument is for removing overload ambiguities and is not // used. template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, FWD_ITER fromBegin, FWD_ITER fromEnd, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_IS_POINTER_TO_POINTER> *); template <class TARGET_TYPE, class ALLOCATOR> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, const TARGET_TYPE *fromBegin, const TARGET_TYPE *fromEnd, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *); template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, FWD_ITER fromBegin, FWD_ITER fromEnd, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *); template <class FWD_ITER, class ALLOCATOR> static void insert(void **toBegin, void **toEnd, FWD_ITER fromBegin, FWD_ITER fromEnd, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_IS_ITERATOR_TO_FUNCTION_POINTER> *); template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> static void insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, FWD_ITER fromBegin, FWD_ITER fromEnd, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // These functions follow the 'insert' contract. Note that if // 'TARGET_TYPE' is bit-wise copyable and 'FWD_ITER' is convertible to // 'const TARGET_TYPE *', then this operation is simply 'memmove' // followed by 'memcpy'. If 'TARGET_TYPE' is bit-wise moveable and // 'FWD_ITER' is convertible to 'const TARGET_TYPE *', then this // operation can still be optimized using 'memmove' followed by // repeated copies. The last argument is for removing overload // ambiguities and is not used. template <class TARGET_TYPE, class ALLOCATOR> static void moveInsert( TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, TARGET_TYPE **lastPtr, TARGET_TYPE *first, TARGET_TYPE *last, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *); template <class TARGET_TYPE, class ALLOCATOR> static void moveInsert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, TARGET_TYPE **lastPtr, TARGET_TYPE *first, TARGET_TYPE *last, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // These functions follow the 'moveInsert' contract. Note that if // 'TARGET_TYPE' is at least bit-wise moveable, then this operation is // simply 'memmove' followed by 'memcpy'. template <class TARGET_TYPE> static void rotate(TARGET_TYPE *begin, TARGET_TYPE *middle, TARGET_TYPE *end, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *); template <class TARGET_TYPE> static void rotate(TARGET_TYPE *begin, TARGET_TYPE *middle, TARGET_TYPE *end, bslmf::MetaInt<e_NIL_TRAITS> *); // These functions follow the 'rotate' contract, but the first overload // is optimized when the parameterized 'TARGET_TYPE' is bit-wise // moveable. The last argument is for removing overload ambiguities // and is not used. Note that if 'TARGET_TYPE' is bit-wise moveable, // the 'rotate(char*, char*, char*)' can be used, enabling to take the // whole implementation out-of-line. template <class ALLOCATOR> static void shiftAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer begin, typename bsl::allocator_traits<ALLOCATOR>::pointer end, bslmf::MovableRef< typename bsl::allocator_traits<ALLOCATOR>::value_type> value, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *); template <class ALLOCATOR> static void shiftAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer begin, typename bsl::allocator_traits<ALLOCATOR>::pointer end, bslmf::MovableRef< typename bsl::allocator_traits<ALLOCATOR>::value_type> value, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *); template <class ALLOCATOR> static void shiftAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer begin, typename bsl::allocator_traits<ALLOCATOR>::pointer end, bslmf::MovableRef< typename bsl::allocator_traits<ALLOCATOR>::value_type> value, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *); // Shift the specified '[begin, end)' sequence one position right, then // insert the specified 'value' at the position pointed by 'begin'. // The specified 'allocator' is used for the element construction. The // behavior is undefined unless the specified '[begin, end)' sequence // contains at least one element. // 'bitwise' METHODS static void bitwiseRotate(char *begin, char *middle, char *end); // This function follows the 'rotate' contract, but by using bit-wise // moves on the underlying 'char' array. static void bitwiseRotateBackward(char *begin, char *middle, char *end); // Move the characters in the array starting at the specified 'first' // address and ending immediately before the specified 'middle' address // to the array of the same length ending at the specified 'last' // address (and thus starting at the 'last - (middle - first)' // address), and move the elements previously in the array starting at // 'middle' and ending at 'last' down to the 'first' address. The // behavior is undefined unless // 'middle - begin <= k_INPLACE_BUFFER_SIZE'. static void bitwiseRotateForward(char *begin, char *middle, char *end); // Move the characters in the array starting at the specified 'first' // address and ending immediately before the specified 'middle' address // to the array of the same length ending at the specified 'last' // address (and thus starting at the 'last - (middle - first)' // address), and move the elements previously in the array starting at // 'middle' and ending at 'last' down to the 'first' address. The // behavior is undefined unless // 'end - middle <= k_INPLACE_BUFFER_SIZE'. static void bitwiseSwapRanges(char *begin, char *middle, char *end); // Swap the characters in the array starting at the specified 'first' // address and ending immediately before the specified 'middle' address // with the array of the same length starting at the 'middle' address // and ending at the specified 'last' address. The behavior is // undefined unless 'middle - begin == end - middle'. template <class FORWARD_ITERATOR> static bool isInvalidRange(FORWARD_ITERATOR begin, FORWARD_ITERATOR end); template <class TARGET_TYPE> static bool isInvalidRange(TARGET_TYPE *begin, TARGET_TYPE *end); // Return 'true' if the specified 'begin' and the specified 'end' // provably do not form a valid semi-open range, '[begin, end)', and // 'false' otherwise. Note that 'begin == null == end' produces a // valid range, and any other use of the null pointer value will return // 'true'. Also note that this function is intended to support // testing, primarily through assertions, so will return 'false' unless // it can *prove* that the passed range is invalid. Currently, this // function can prove invalid ranges only for pointers, although should // also encompass generic random access iterators in a future update, // where iterator tag types are levelized below 'bslalg'. }; // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // IMPLEMENTATION NOTES: Specializations of 'uninitializedFillN' for most // fundamental types are not templates nor inline, and thus can be found in the // '.cpp' file. // ===================================== // struct ArrayPrimitives_CanBitwiseCopy // ===================================== template <class FROM_TYPE, class TO_TYPE> struct ArrayPrimitives_CanBitwiseCopy : bsl::integral_constant<bool, bsl::is_same< typename bsl::remove_const<FROM_TYPE>::type, typename bsl::remove_const<TO_TYPE >::type> ::value && bsl::is_trivially_copyable< typename bsl::remove_const<TO_TYPE >::type> ::value > { }; // ---------------------- // struct ArrayPrimitives // ---------------------- template <class ALLOCATOR> inline void ArrayPrimitives::uninitializedFillN( typename bsl::allocator_traits<ALLOCATOR>::pointer begin, size_type numElements, const typename bsl::allocator_traits<ALLOCATOR>::value_type& value, ALLOCATOR allocator) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; enum { // We provide specialized overloads of 'uninitializedFillN' for // fundamental and pointer types. However, function pointers can have // extern "C" linkage and SunPro doesn't match them properly with the // pointer template function overload in 'Imp', so we resort to the // general case for those. k_IS_FUNCTION_POINTER = bslmf::IsFunctionPointer<TargetType>::value, k_IS_FUNDAMENTAL = bsl::is_fundamental<TargetType>::value, k_IS_POINTER = bsl::is_pointer<TargetType>::value, k_IS_FUNDAMENTAL_OR_POINTER = k_IS_FUNDAMENTAL || (k_IS_POINTER && !k_IS_FUNCTION_POINTER), k_IS_BITWISECOPYABLE = bsl::is_trivially_copyable<TargetType>::value, k_VALUE = k_IS_FUNDAMENTAL_OR_POINTER ? Imp::e_IS_FUNDAMENTAL_OR_POINTER : k_IS_BITWISECOPYABLE ? Imp::e_BITWISE_COPYABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::uninitializedFillN(begin, value, numElements, &allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE> inline void ArrayPrimitives::uninitializedFillN(TARGET_TYPE *begin, size_type numElements, const TARGET_TYPE& value, bslma::Allocator *basicAllocator) { uninitializedFillN<bsl::allocator<TARGET_TYPE> >(begin, numElements, value, basicAllocator); } template <class ALLOCATOR, class FWD_ITER> void ArrayPrimitives::copyConstruct( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, ALLOCATOR allocator) { BSLS_ASSERT_SAFE(toBegin || fromBegin == fromEnd); BSLMF_ASSERT(!bsl::is_pointer<FWD_ITER>::value); typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; typedef typename FWD_ITER::value_type FwdTarget; // Overload resolution will handle the case where 'FWD_ITER' is a raw // pointer, so we need handle only user-defined iterators. As 'bslalg' // is levelized below 'bslstl' we cannot use 'iterator_traits', but // rely on the same property as 'iterator_traits' that this typedef // must be defined for any standard-conforming iterator, unless the // iterator explicitly specialized the 'std::iterator_traits' template. // In practice, iterators always prefer to provide the member typedef // than specialize the traits as it is a much simpler implementation, // so this assumption is good enough. // // Also note that as we know that 'FWD_ITER' is not a pointer, then we // cannot take advantage of bitwise copying as we do not have pointers // to pass to the 'memcpy' describing the whole range. It is not worth // the effort to try to bitwise copy one element at a time. typedef typename bsl::remove_pointer<TargetType>::type RemovePtrTarget; // We want to detect the special case of copying function pointers to // 'void *' or 'const void *' pointers. enum { k_ITER_TO_FUNC_PTRS = bslmf::IsFunctionPointer<FwdTarget>::value, k_TARGET_IS_VOID_PTR = bsl::is_pointer<TargetType>::value && bsl::is_void<RemovePtrTarget>::value, k_VALUE = k_ITER_TO_FUNC_PTRS && k_TARGET_IS_VOID_PTR ? Imp::e_IS_ITERATOR_TO_FUNCTION_POINTER : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::copyConstruct(toBegin, fromBegin, fromEnd, allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE, class FWD_ITER> inline void ArrayPrimitives::copyConstruct(TARGET_TYPE *toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, bslma::Allocator *basicAllocator) { copyConstruct<bsl::allocator<TARGET_TYPE> >(toBegin, fromBegin, fromEnd, basicAllocator); } template <class ALLOCATOR, class SOURCE_TYPE> inline void ArrayPrimitives::copyConstruct( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, SOURCE_TYPE *fromBegin, SOURCE_TYPE *fromEnd, ALLOCATOR allocator) { BSLS_ASSERT_SAFE(toBegin || fromBegin == fromEnd); typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; enum { k_ARE_PTRS_TO_PTRS = bsl::is_pointer<TargetType>::value && bsl::is_pointer<SOURCE_TYPE>::value, k_IS_BITWISECOPYABLE = ArrayPrimitives_CanBitwiseCopy<SOURCE_TYPE, TargetType>::value, k_VALUE = k_ARE_PTRS_TO_PTRS ? Imp::e_IS_POINTER_TO_POINTER : k_IS_BITWISECOPYABLE ? Imp::e_BITWISE_COPYABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::copyConstruct(toBegin, fromBegin, fromEnd, allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE, class SOURCE_TYPE> inline void ArrayPrimitives::copyConstruct(TARGET_TYPE *toBegin, SOURCE_TYPE *fromBegin, SOURCE_TYPE *fromEnd, bslma::Allocator *basicAllocator) { copyConstruct<bsl::allocator<TARGET_TYPE> >(toBegin, fromBegin, fromEnd, basicAllocator); } template <class ALLOCATOR> inline void ArrayPrimitives::defaultConstruct( typename bsl::allocator_traits<ALLOCATOR>::pointer begin, size_type numElements, ALLOCATOR allocator) { BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); BSLS_ASSERT_SAFE(begin || 0 == numElements); typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; enum { k_VALUE = bsl::is_fundamental<TargetType>::value || bsl::is_enum<TargetType>::value || bsl::is_pointer<TargetType>::value #if !defined(BSLALG_ARRAYPRIMITIVES_NON_ZERO_NULL_VALUE_FOR_MEMBER_POINTERS) || bsl::is_member_pointer<TargetType>::value #endif ? Imp::e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS : bsl::is_trivially_copyable<TargetType>::value && bsl::is_trivially_default_constructible<TargetType>::value ? Imp::e_BITWISE_COPYABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::defaultConstruct(begin, numElements, allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE> inline void ArrayPrimitives::defaultConstruct(TARGET_TYPE *begin, size_type numElements, bslma::Allocator *basicAllocator) { defaultConstruct<bsl::allocator<TARGET_TYPE> >(begin, numElements, basicAllocator); } template <class ALLOCATOR> inline void ArrayPrimitives::destructiveMove( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, ALLOCATOR allocator) { BSLS_ASSERT_SAFE(toBegin || fromBegin == fromEnd); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(fromBegin, fromEnd)); typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; enum { k_VALUE = bslmf::IsBitwiseMoveable<TargetType>::value ? Imp::e_BITWISE_MOVEABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::destructiveMove(toBegin, fromBegin, fromEnd, allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE> inline void ArrayPrimitives::destructiveMove(TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, bslma::Allocator *basicAllocator) { destructiveMove<bsl::allocator<TARGET_TYPE> >(toBegin, fromBegin, fromEnd, basicAllocator); } #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=10 template <class ALLOCATOR, class... ARGS> void ArrayPrimitives::destructiveMoveAndEmplace( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer position, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, ALLOCATOR allocator, ARGS&&... arguments) { // Key to the transformation diagrams: //.. // A...H original contents of '[fromBegin, fromEnd)' ("source") // v...v default-constructed values ("input") // ; ... contents of '[toBegin, toEnd)' ("destination") // ..:.. position of 'fromEndPtr' in the input // _____ uninitialized array elements // [...] part of array protected by an exception guard object //.. typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; *fromEndPtr = fromEnd; // Note: Construct new element. //.. // Transformation: ABCDEFGH: ; ___________[] // => ABCDEFGH: ; ____[v]____ //.. TargetType *toPositionBegin = toBegin + (position - fromBegin); bsl::allocator_traits<ALLOCATOR>::construct( allocator, toPositionBegin, BSLS_COMPILERFEATURES_FORWARD(ARGS,arguments)...); TargetType *toPositionEnd = toPositionBegin + 1; AutoArrayDestructor<TargetType, ALLOCATOR> guard(toPositionBegin, toPositionEnd, allocator); //.. // Transformation: ABCDEFGH: ; ____[v]____ // => ABCD:____ ; ____[vEFGH] //.. destructiveMove(toPositionEnd, position, fromEnd, allocator); *fromEndPtr = position; // shorten input range after partial destruction guard.moveEnd(fromEnd - position); // toEnd //.. // Transformation: ABCD:____ ; ____[vEFGH] // => :________ ; ABCDvEFGH[] //.. destructiveMove(toBegin, fromBegin, position, allocator); *fromEndPtr = fromBegin; // empty input range after final destruction guard.release(); } #endif template <class ALLOCATOR> void ArrayPrimitives::destructiveMoveAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer position, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, size_type numElements, ALLOCATOR allocator) { // Key to the transformation diagrams: //.. // A...H original contents of '[fromBegin, fromEnd)' ("source") // v...v default-constructed values ("input") // ; ... contents of '[toBegin, toEnd)' ("destination") // ..:.. position of 'fromEndPtr' in the input // _____ uninitialized array elements // [...] part of array protected by an exception guard object //.. typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; *fromEndPtr = fromEnd; // Note: Construct default values. //.. // Transformation: ABCDEFGH: ; _____________[] // => ABCDEFGH: ; ____[vvvvv]____ //.. TargetType *toPositionBegin = toBegin + (position - fromBegin); defaultConstruct(toPositionBegin, numElements, allocator); TargetType *toPositionEnd = toPositionBegin + numElements; AutoArrayDestructor<TargetType, ALLOCATOR> guard(toPositionBegin, toPositionEnd, allocator); //.. // Transformation: ABCDEFGH: ; ____[vvvvv]____ // => ABCD:____ ; ____[vvvvvEFGH] //.. destructiveMove(toPositionEnd, position, fromEnd, allocator); *fromEndPtr = position; // shorten input range after partial destruction guard.moveEnd(fromEnd - position); // toEnd //.. // Transformation: ABCD:____ ; ____[vvvvvEFGH] // => :________ ; ABCDvvvvvEFGH[] //.. destructiveMove(toBegin, fromBegin, position, allocator); *fromEndPtr = fromBegin; // empty input range after final destruction guard.release(); } template <class TARGET_TYPE> inline void ArrayPrimitives::destructiveMoveAndInsert( TARGET_TYPE *toBegin, TARGET_TYPE **fromEndPtr, TARGET_TYPE *fromBegin, TARGET_TYPE *position, TARGET_TYPE *fromEnd, size_type numElements, bslma::Allocator *basicAllocator) { destructiveMoveAndInsert<bsl::allocator<TARGET_TYPE> >(toBegin, fromEndPtr, fromBegin, position, fromEnd, numElements, basicAllocator); } template <class ALLOCATOR> void ArrayPrimitives::destructiveMoveAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer position, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, const typename bsl::allocator_traits<ALLOCATOR>::value_type& value, size_type numElements, ALLOCATOR allocator) { // Key to the transformation diagrams: //.. // A...H original contents of '[fromBegin, fromEnd)' ("source") // v...v copies of 'value' ("input") // ; ... contents of '[toBegin, toEnd)' ("destination") // ..:.. position of 'fromEndPtr' in the input // _____ uninitialized array elements // [...] part of array protected by an exception guard object //.. typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; *fromEndPtr = fromEnd; // Note: Construct copies of 'value' first in case 'value' is a reference // in the input range, which would be invalidated by any of the following // moves. // //.. // Transformation: ABCDEFGH: ; _____________[] // => ABCDEFGH: ; ____[vvvvv]____ //.. TargetType *toPositionBegin = toBegin + (position - fromBegin); uninitializedFillN(toPositionBegin, numElements, value, allocator); TargetType *toPositionEnd = toPositionBegin + numElements; AutoArrayDestructor<TargetType, ALLOCATOR> guard(toPositionBegin, toPositionEnd, allocator); //.. // Transformation: ABCDEFGH: ; ____[vvvvv]____ // => ABCD:____ ; ____[vvvvvEFGH] //.. destructiveMove(toPositionEnd, position, fromEnd, allocator); *fromEndPtr = position; // shorten input range after partial destruction guard.moveEnd(fromEnd - position); // toEnd //.. // Transformation: ABCD:____ ; ____[vvvvvEFGH] // => :________ ; ABCDvvvvvEFGH[] //.. destructiveMove(toBegin, fromBegin, position, allocator); *fromEndPtr = fromBegin; // empty input range after final destruction guard.release(); } template <class TARGET_TYPE> void ArrayPrimitives::destructiveMoveAndInsert( TARGET_TYPE *toBegin, TARGET_TYPE **fromEndPtr, TARGET_TYPE *fromBegin, TARGET_TYPE *position, TARGET_TYPE *fromEnd, const TARGET_TYPE& value, size_type numElements, bslma::Allocator *basicAllocator) { destructiveMoveAndInsert<bsl::allocator<TARGET_TYPE> >(toBegin, fromEndPtr, fromBegin, position, fromEnd, value, numElements, basicAllocator); } template <class ALLOCATOR, class FWD_ITER> void ArrayPrimitives::destructiveMoveAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer position, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, FWD_ITER first, FWD_ITER last, size_type numElements, ALLOCATOR allocator) { // Key to the transformation diagrams: //.. // A...H original contents of '[fromBegin, fromEnd)' ("source") // t...z original contents of '[first, last)' ("input") // ; ... contents of '[toBegin, toEnd)' ("destination") // ..:.. position of 'fromEndPtr' in the input // _____ uninitialized array elements // [...] part of array protected by an exception guard object //.. typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; *fromEndPtr = fromEnd; // Note: Construct copies of 'value' first in case 'value' is a reference // in the input range, which would be invalidated by any of the following // moves: //.. // Transformation: ABCDEFGH: ; _________[]____ // => ABCDEFGH: ; ____[tuvxy]____ //.. TargetType *toPositionBegin = toBegin + (position - fromBegin); copyConstruct(toPositionBegin, first, last, allocator); TargetType *toPositionEnd = toPositionBegin + numElements; AutoArrayDestructor<TargetType, ALLOCATOR> guard(toPositionBegin, toPositionEnd, allocator); //.. // Transformation: ABCDEFGH: ; ____[tuvxy]____ // => ABCD:____ ; ____[tuvxyEFGH] //.. destructiveMove(toPositionEnd, position, fromEnd, allocator); *fromEndPtr = position; // shorten input range after partial destruction guard.moveEnd(fromEnd - position); // toEnd //.. // Transformation: ABCD:____ ; ____[tuvxyEFGH] // => :________ ; ABCDtuvxyEFGH[] //.. destructiveMove(toBegin, fromBegin, position, allocator); *fromEndPtr = fromBegin; // empty input range after final destruction guard.release(); } template <class TARGET_TYPE, class FWD_ITER> inline void ArrayPrimitives::destructiveMoveAndInsert( TARGET_TYPE *toBegin, TARGET_TYPE **fromEndPtr, TARGET_TYPE *fromBegin, TARGET_TYPE *position, TARGET_TYPE *fromEnd, FWD_ITER first, FWD_ITER last, size_type numElements, bslma::Allocator *basicAllocator) { destructiveMoveAndInsert<bsl::allocator<TARGET_TYPE> >(toBegin, fromEndPtr, fromBegin, position, fromEnd, first, last, numElements, basicAllocator); } template <class ALLOCATOR> void ArrayPrimitives::destructiveMoveAndMoveInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer *lastPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer position, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, typename bsl::allocator_traits<ALLOCATOR>::pointer first, typename bsl::allocator_traits<ALLOCATOR>::pointer last, size_type numElements, ALLOCATOR allocator) { // Key to the transformation diagrams: //.. // A...H original contents of '[fromBegin, fromEnd)' ("source") // t...z original contents of '[first, last)' ("input") // ; ... contents of '[toBegin, toEnd)' ("destination") // ..:.. position of 'fromEndPtr' in the input // _____ uninitialized array elements // [...] part of array protected by an exception guard object //.. typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; *lastPtr = last; *fromEndPtr = fromEnd; //.. // Transformation: ABCDEFGH: ; _____________[] // => ABCD:____ ; _________[EFGH] //.. TargetType *toPositionBegin = toBegin + (position - fromBegin); TargetType *toPositionEnd = toPositionBegin + numElements; destructiveMove(toPositionEnd, position, fromEnd, allocator); *fromEndPtr = position; // shorten input range after partial destruction AutoArrayDestructor<TargetType, ALLOCATOR> guard(toPositionEnd, toPositionEnd + (fromEnd - position), allocator); //.. // Transformation: ABCD:____ ; _________[EFGH] // => ABCD:____ ; _____[tuvwEFGH] //.. destructiveMove(toPositionBegin, first, last, allocator); *lastPtr = first; guard.moveBegin(-static_cast<difference_type>(numElements)); //.. // Transformation: ABCD:____ ; ____[tuvwEFGH] // => :________ ; ABCDtuvwEFGH[] //.. destructiveMove(toBegin, fromBegin, position, allocator); *fromEndPtr = fromBegin; // empty input range after final destruction guard.release(); } template <class TARGET_TYPE> inline void ArrayPrimitives::destructiveMoveAndMoveInsert( TARGET_TYPE *toBegin, TARGET_TYPE **fromEndPtr, TARGET_TYPE **lastPtr, TARGET_TYPE *fromBegin, TARGET_TYPE *position, TARGET_TYPE *fromEnd, TARGET_TYPE *first, TARGET_TYPE *last, size_type numElements, bslma::Allocator *basicAllocator) { destructiveMoveAndMoveInsert<bsl::allocator<TARGET_TYPE> >(toBegin, fromEndPtr, lastPtr, fromBegin, position, fromEnd, first, last, numElements, basicAllocator); } #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES template <class ALLOCATOR, class... ARGS> inline void ArrayPrimitives::emplace( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, ALLOCATOR allocator, ARGS&&... args) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; enum { k_VALUE = bsl::is_trivially_copyable<TargetType>::value ? Imp::e_BITWISE_COPYABLE_TRAITS : bslmf::IsBitwiseMoveable<TargetType>::value ? Imp::e_BITWISE_MOVEABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::emplace( toBegin, toEnd, allocator, (bslmf::MetaInt<k_VALUE> *)0, BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...); } template <class TARGET_TYPE, class... ARGS> inline void ArrayPrimitives::emplace(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, bslma::Allocator *basicAllocator, ARGS&&... args) { emplace<bsl::allocator<TARGET_TYPE> >( toBegin, toEnd, basicAllocator, BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...); } #endif template <class ALLOCATOR> inline void ArrayPrimitives::erase( typename bsl::allocator_traits<ALLOCATOR>::pointer first, typename bsl::allocator_traits<ALLOCATOR>::pointer middle, typename bsl::allocator_traits<ALLOCATOR>::pointer last, ALLOCATOR allocator) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(first, middle)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(middle, last)); typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; if (first == middle) { // erasing empty range O(1) versus O(N): Do not // remove! return; // RETURN } enum { k_VALUE = bslmf::IsBitwiseMoveable<TargetType>::value ? Imp::e_BITWISE_MOVEABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::erase(first, middle, last, allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE> inline void ArrayPrimitives::erase(TARGET_TYPE *first, TARGET_TYPE *middle, TARGET_TYPE *last, bslma::Allocator *basicAllocator) { erase<bsl::allocator<TARGET_TYPE> >(first, middle, last, basicAllocator); } template <class ALLOCATOR> inline void ArrayPrimitives::insert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, bslmf::MovableRef< typename bsl::allocator_traits<ALLOCATOR>::value_type> value, ALLOCATOR allocator) { BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; if (toBegin != toEnd) { // Insert in the middle. Note that there is no strong exception // guarantee if copy constructor, move constructor, or assignment // operator throw. enum { k_VALUE = bsl::is_trivially_copyable<TargetType>::value ? Imp::e_BITWISE_COPYABLE_TRAITS : bslmf::IsBitwiseMoveable<TargetType>::value ? Imp::e_BITWISE_MOVEABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::shiftAndInsert(toBegin, toEnd, bslmf::MovableRefUtil::move(value), allocator, (bslmf::MetaInt<k_VALUE>*)0); } else { // toBegin == toEnd bsl::allocator_traits<ALLOCATOR>::construct( allocator, toBegin, bslmf::MovableRefUtil::move(value)); } } template <class TARGET_TYPE> inline void ArrayPrimitives::insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, bslmf::MovableRef<TARGET_TYPE> value, bslma::Allocator *basicAllocator) { insert<bsl::allocator<TARGET_TYPE> >(toBegin, toEnd, bslmf::MovableRefUtil::move(value), basicAllocator); } template <class ALLOCATOR> void ArrayPrimitives::insert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, const typename bsl::allocator_traits<ALLOCATOR>::value_type& value, size_type numElements, ALLOCATOR allocator) { BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; if (0 == numElements) { return; // RETURN } enum { k_VALUE = bsl::is_trivially_copyable<TargetType>::value ? Imp::e_BITWISE_COPYABLE_TRAITS : bslmf::IsBitwiseMoveable<TargetType>::value ? Imp::e_BITWISE_MOVEABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::insert(toBegin, toEnd, value, numElements, allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE> inline void ArrayPrimitives::insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, const TARGET_TYPE& value, size_type numElements, bslma::Allocator *basicAllocator) { insert<bsl::allocator<TARGET_TYPE> >(toBegin, toEnd, value, numElements, basicAllocator); } template <class ALLOCATOR, class FWD_ITER> void ArrayPrimitives::insert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, FWD_ITER fromBegin, FWD_ITER fromEnd, size_type numElements, ALLOCATOR allocator) { if (0 == numElements) { return; // RETURN } typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; BSLMF_ASSERT(!bsl::is_pointer<FWD_ITER>::value); typedef typename FWD_ITER::value_type FwdTarget; // Overload resolution will handle the case where 'FWD_ITER' is a raw // pointer, so we need handle only user-defined iterators. As 'bslalg' // is levelized below 'bslstl' we cannot use 'iterator_traits', but // rely on the same property as 'iterator_traits' that this typedef // must be defined for any standard-conforming iterator, unless the // iterator explicitly specialized the 'std::iterator_traits' template. // In practice, iterators always prefer to provide the member typedef // than specialize the traits as it is a much simpler implementation, // so this assumption is good enough. // // Also note that as we know that 'FWD_ITER' is not a pointer, then we // cannot take advantage of bitwise copying as we do not have pointers // to pass to the 'memcpy' describing the whole range. It is not worth // the effort to try to bitwise copy one element at a time. typedef typename bsl::remove_pointer<TargetType>::type RemovePtrTarget; // We want to detect the special case of copying function pointers to // 'void *' or 'const void *' pointers. enum { k_ITER_TO_FUNC_PTRS = bslmf::IsFunctionPointer<FwdTarget>::value, k_TARGET_IS_VOID_PTR = bsl::is_pointer<TargetType>::value && bsl::is_void<RemovePtrTarget>::value, k_VALUE = k_ITER_TO_FUNC_PTRS && k_TARGET_IS_VOID_PTR ? Imp::e_IS_ITERATOR_TO_FUNCTION_POINTER : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::insert(toBegin, toEnd, fromBegin, fromEnd, numElements, allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE, class FWD_ITER> inline void ArrayPrimitives::insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, FWD_ITER fromBegin, FWD_ITER fromEnd, size_type numElements, bslma::Allocator *basicAllocator) { insert<bsl::allocator<TARGET_TYPE> >(toBegin, toEnd, fromBegin, fromEnd, numElements, basicAllocator); } template <class ALLOCATOR, class SOURCE_TYPE> void ArrayPrimitives::insert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, SOURCE_TYPE *fromBegin, SOURCE_TYPE *fromEnd, size_type numElements, ALLOCATOR allocator) { if (0 == numElements) { return; // RETURN } typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; enum { k_ARE_PTRS_TO_PTRS = bsl::is_pointer<TargetType>::value && bsl::is_pointer<SOURCE_TYPE>::value, k_IS_BITWISEMOVEABLE = bslmf::IsBitwiseMoveable<TargetType>::value, k_IS_BITWISECOPYABLE = ArrayPrimitives_CanBitwiseCopy<SOURCE_TYPE, TargetType>::value, k_VALUE = k_ARE_PTRS_TO_PTRS ? Imp::e_IS_POINTER_TO_POINTER : k_IS_BITWISECOPYABLE ? Imp::e_BITWISE_COPYABLE_TRAITS : k_IS_BITWISEMOVEABLE ? Imp::e_BITWISE_MOVEABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::insert(toBegin, toEnd, fromBegin, fromEnd, numElements, allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE, class SOURCE_TYPE> inline void ArrayPrimitives::insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, SOURCE_TYPE *fromBegin, SOURCE_TYPE *fromEnd, size_type numElements, bslma::Allocator *basicAllocator) { insert<bsl::allocator<TARGET_TYPE> >(toBegin, toEnd, fromBegin, fromEnd, numElements, basicAllocator); } template <class ALLOCATOR> inline void ArrayPrimitives::moveConstruct( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, ALLOCATOR allocator) { BSLS_ASSERT_SAFE(toBegin || fromBegin == fromEnd); typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; enum { k_VALUE = bsl::is_trivially_copyable<TargetType>::value ? Imp::e_BITWISE_COPYABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::moveConstruct(toBegin, fromBegin, fromEnd, allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE> inline void ArrayPrimitives::moveConstruct(TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, bslma::Allocator *basicAllocator) { moveConstruct<bsl::allocator<TARGET_TYPE> >(toBegin, fromBegin, fromEnd, basicAllocator); } template <class ALLOCATOR> inline void ArrayPrimitives::moveInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer toBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer toEnd, typename bsl::allocator_traits<ALLOCATOR>::pointer *fromEndPtr, typename bsl::allocator_traits<ALLOCATOR>::pointer fromBegin, typename bsl::allocator_traits<ALLOCATOR>::pointer fromEnd, size_type numElements, ALLOCATOR allocator) { typedef typename bsl::allocator_traits<ALLOCATOR>::value_type TargetType; enum { k_VALUE = bslmf::IsBitwiseMoveable<TargetType>::value ? Imp::e_BITWISE_MOVEABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::moveInsert(toBegin, toEnd, fromEndPtr, fromBegin, fromEnd, numElements, allocator, (bslmf::MetaInt<k_VALUE>*)0); } template <class TARGET_TYPE> inline void ArrayPrimitives::moveInsert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, TARGET_TYPE **fromEndPtr, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, size_type numElements, bslma::Allocator *basicAllocator) { moveInsert<bsl::allocator<TARGET_TYPE> >(toBegin, toEnd, fromEndPtr, fromBegin, fromEnd, numElements, basicAllocator); } template <class TARGET_TYPE> inline void ArrayPrimitives::rotate(TARGET_TYPE *first, TARGET_TYPE *middle, TARGET_TYPE *last) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(first, middle)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(middle, last)); enum { k_VALUE = bslmf::IsBitwiseMoveable<TARGET_TYPE>::value ? Imp::e_BITWISE_MOVEABLE_TRAITS : Imp::e_NIL_TRAITS }; ArrayPrimitives_Imp::rotate(first, middle, last, (bslmf::MetaInt<k_VALUE>*)0); } // -------------------------- // struct ArrayPrimitives_Imp // -------------------------- // CLASS METHODS template <class TARGET_TYPE> inline void ArrayPrimitives_Imp::assign(TARGET_TYPE *srcStart, TARGET_TYPE *srcEnd, TARGET_TYPE& value) { for ( ; srcStart != srcEnd; ++srcStart) { *srcStart = value; } } template <class FORWARD_ITERATOR> inline bool ArrayPrimitives_Imp::isInvalidRange(FORWARD_ITERATOR, FORWARD_ITERATOR) { // Ideally would dispatch on random_access_iterator_tag to support // generalized random access iterators, but we are constrained by 'bsl' // levelization to not depend on 'bsl_iterator.h'. As the intent is to // detect invalid ranges in assertions, the conservative choice is to // return 'false' always. Note that this differs from the pointers case // below, which also disallows empty ranges. return false; } template <class TARGET_TYPE> inline bool ArrayPrimitives_Imp::isInvalidRange(TARGET_TYPE *begin, TARGET_TYPE *end) { return !begin != !end || begin > end; } template <class TARGET_TYPE> inline void ArrayPrimitives_Imp::reverseAssign(TARGET_TYPE *dest, TARGET_TYPE *srcStart, TARGET_TYPE *srcEnd) { TARGET_TYPE *destEnd = srcEnd - srcStart + dest; while (srcStart != srcEnd) { *--destEnd = *--srcEnd; } } // *** 'uninitializedFillN' overloads: *** inline void ArrayPrimitives_Imp::uninitializedFillN( bool *begin, bool value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); BSLMF_ASSERT(sizeof(bool) == 1); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numElements != 0)) { std::memset(reinterpret_cast<char *>(begin), // odd, why not 'void *'? static_cast<char>(value), numElements); } } inline void ArrayPrimitives_Imp::uninitializedFillN( char *begin, char value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numElements != 0)) { std::memset(begin, value, numElements); } } inline void ArrayPrimitives_Imp::uninitializedFillN( unsigned char *begin, unsigned char value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numElements != 0)) { std::memset(begin, value, numElements); } } inline void ArrayPrimitives_Imp::uninitializedFillN( signed char *begin, signed char value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numElements != 0)) { std::memset(begin, value, numElements); } } inline void ArrayPrimitives_Imp::uninitializedFillN( wchar_t *begin, wchar_t value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numElements != 0)) { std::wmemset(begin, value, numElements); } } inline void ArrayPrimitives_Imp::uninitializedFillN( unsigned short *begin, unsigned short value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); uninitializedFillN(reinterpret_cast<short *>(begin), static_cast<short>(value), numElements, (void *)0, (bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *)0); } inline void ArrayPrimitives_Imp::uninitializedFillN( unsigned int *begin, unsigned int value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); uninitializedFillN(reinterpret_cast<int *>(begin), static_cast<int>(value), numElements, (void *)0, (bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *)0); } inline void ArrayPrimitives_Imp::uninitializedFillN( long *begin, long value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); #if defined(BSLS_PLATFORM_CPU_64_BIT) && !defined(BSLS_PLATFORM_OS_WINDOWS) uninitializedFillN(reinterpret_cast<bsls::Types::Int64 *>(begin), static_cast<bsls::Types::Int64>(value), numElements); #else uninitializedFillN(reinterpret_cast<int *>(begin), static_cast<int>(value), numElements, (void *)0, (bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *)0); #endif } inline void ArrayPrimitives_Imp::uninitializedFillN( unsigned long *begin, unsigned long value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); #if defined(BSLS_PLATFORM_CPU_64_BIT) && !defined(BSLS_PLATFORM_OS_WINDOWS) uninitializedFillN(reinterpret_cast<bsls::Types::Int64 *>(begin), static_cast<bsls::Types::Int64>(value), numElements, (void *)0, (bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER>*)0); #else uninitializedFillN(reinterpret_cast<int *>(begin), static_cast<int>(value), numElements, (void *)0, (bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *)0); #endif } inline void ArrayPrimitives_Imp::uninitializedFillN( bsls::Types::Uint64 *begin, bsls::Types::Uint64 value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); uninitializedFillN(reinterpret_cast<bsls::Types::Int64 *>(begin), value, numElements, (void *)0, (bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *)0); } template <class TARGET_TYPE> inline void ArrayPrimitives_Imp::uninitializedFillN( TARGET_TYPE **begin, TARGET_TYPE *value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); // Note: 'const'-correctness is respected because the next overload picks // up the 'const TARGET_TYPE' and will be a better match. Note that we // cannot cast to 'const void **' (one would have to add 'const' at every // level, not just the innermost; i.e., 'const void *const *' would be // correct, 'const void **' is not [C++ Standard, 4.4 Qualification // conversions]). uninitializedFillN(reinterpret_cast<void **>(begin), static_cast<void *>(value), numElements, (void *)0, (bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *)0); } template <class TARGET_TYPE> inline void ArrayPrimitives_Imp::uninitializedFillN( const TARGET_TYPE **begin, const TARGET_TYPE *value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); // While it seems that this overload is subsumed by the previous template, // SunPro does not detect it. uninitializedFillN(reinterpret_cast<const void **>(begin), static_cast<const void *>(value), numElements, (void *)0, (bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *)0); } template <class TARGET_TYPE> inline void ArrayPrimitives_Imp::uninitializedFillN( volatile TARGET_TYPE **begin, volatile TARGET_TYPE *value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); // While it seems that this overload is subsumed by the previous template, // SunPro does not detect it. uninitializedFillN(reinterpret_cast<volatile void **>(begin), static_cast<volatile void *>(value), numElements, (void *)0, (bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *)0); } template <class TARGET_TYPE> inline void ArrayPrimitives_Imp::uninitializedFillN( const volatile TARGET_TYPE **begin, const volatile TARGET_TYPE *value, size_type numElements, void *, bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); // While it seems that this overload is subsumed by the previous template, // SunPro does not detect it. uninitializedFillN(reinterpret_cast<const volatile void **>(begin), static_cast<const volatile void *>(value), numElements, (void *)0, (bslmf::MetaInt<e_IS_FUNDAMENTAL_OR_POINTER> *)0); } template <class TARGET_TYPE, class ALLOCATOR> void ArrayPrimitives_Imp::uninitializedFillN( TARGET_TYPE *begin, const TARGET_TYPE& value, size_type numElements, ALLOCATOR *, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); if (0 == numElements) { return; // RETURN } const char *valueBuffer = reinterpret_cast<const char *>(BSLS_UTIL_ADDRESSOF(value)); std::memcpy((void *)begin, valueBuffer, sizeof(TARGET_TYPE)); bitwiseFillN(reinterpret_cast<char *>(begin), sizeof(TARGET_TYPE), sizeof(TARGET_TYPE) * numElements); } template <class TARGET_TYPE, class ALLOCATOR> void ArrayPrimitives_Imp::uninitializedFillN( TARGET_TYPE *begin, const TARGET_TYPE& value, size_type numElements, ALLOCATOR *allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); BSLS_ASSERT_SAFE(allocator); if (0 == numElements) { return; // RETURN } AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> guard(begin, begin, *allocator); TARGET_TYPE *end = begin + numElements; do { bsl::allocator_traits<ALLOCATOR>::construct(*allocator, begin, value); begin = guard.moveEnd(1); } while (begin != end); guard.release(); } // *** 'copyConstruct' overloads: *** template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> inline void ArrayPrimitives_Imp::copyConstruct( TARGET_TYPE *toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_IS_POINTER_TO_POINTER> *) { // We may be casting a function pointer to a 'void *' here, so this won't // work if we port to an architecture where the two are of different sizes. BSLMF_ASSERT(sizeof(void *) == sizeof(void (*)())); typedef typename bsl::remove_cv< typename bsl::remove_pointer<TARGET_TYPE>::type>::type NcPtrType; typedef typename bsl::remove_cv< typename bsl::remove_pointer< typename bsl::remove_pointer<FWD_ITER>::type>::type>::type NcIter; #if defined(BSLALG_ARRAYPRIMITIVES_CANNOT_REMOVE_POINTER_FROM_FUNCTION_POINTER) // fall back on traditional C-style casts. copyConstruct((void * *)toBegin, (void * const *)fromBegin, (void * const *)fromEnd, allocator, (bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *) 0); #else copyConstruct( reinterpret_cast<void * *>(const_cast<NcPtrType **>(toBegin)), reinterpret_cast<void * const *>(const_cast<NcIter * const *>(fromBegin)), reinterpret_cast<void * const *>(const_cast<NcIter * const *>(fromEnd)), allocator, (bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *)0); #endif } template <class FWD_ITER, class ALLOCATOR> void ArrayPrimitives_Imp::copyConstruct( void **toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, ALLOCATOR , bslmf::MetaInt<e_IS_ITERATOR_TO_FUNCTION_POINTER> *) { BSLMF_ASSERT(sizeof(void *) == sizeof(void (*)())); // We will be casting a function pointer to a 'void *', so this won't // work if we port to an architecture where the two are of different // sizes. BSLS_ASSERT_SAFE(toBegin || fromBegin == fromEnd); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(fromBegin, fromEnd)); while (fromBegin != fromEnd) { // 'fromBegin' iterates over pointers to functions, which must be // 'reinterpret_cast' to 'void *'. *toBegin = reinterpret_cast<void *>(*fromBegin); ++fromBegin; ++toBegin; } } template <class TARGET_TYPE, class ALLOCATOR> inline void ArrayPrimitives_Imp::copyConstruct( TARGET_TYPE *toBegin, const TARGET_TYPE *fromBegin, const TARGET_TYPE *fromEnd, ALLOCATOR , bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *) { BSLS_ASSERT_SAFE(toBegin); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(fromBegin, fromEnd)); const size_type numBytes = reinterpret_cast<const char*>(fromEnd) - reinterpret_cast<const char*>(fromBegin); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numBytes != 0)) { std::memcpy((void *)toBegin, fromBegin, numBytes); } } template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> void ArrayPrimitives_Imp::copyConstruct( TARGET_TYPE *toBegin, FWD_ITER fromBegin, FWD_ITER fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(toBegin || fromBegin == fromEnd); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(fromBegin, fromEnd)); AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> guard(toBegin, toBegin, allocator); while (fromBegin != fromEnd) { // Note: We are not sure the value type of 'FWD_ITER' is convertible to // 'TARGET_TYPE'. Use 'construct' instead. bsl::allocator_traits<ALLOCATOR>::construct(allocator, toBegin, *fromBegin); ++fromBegin; toBegin = guard.moveEnd(1); } guard.release(); } // *** 'moveConstruct' overloads: *** template <class TARGET_TYPE, class ALLOCATOR> inline void ArrayPrimitives_Imp::moveConstruct( TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, ALLOCATOR , bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *) { BSLS_ASSERT_SAFE(toBegin); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(fromBegin, fromEnd)); const size_type numBytes = reinterpret_cast<const char*>(fromEnd) - reinterpret_cast<const char*>(fromBegin); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numBytes != 0)) { std::memcpy((void *)toBegin, fromBegin, numBytes); } } template <class TARGET_TYPE, class ALLOCATOR> void ArrayPrimitives_Imp::moveConstruct( TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(toBegin || fromBegin == fromEnd); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(fromBegin, fromEnd)); AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> guard(toBegin, toBegin, allocator); while (fromBegin != fromEnd) { bsl::allocator_traits<ALLOCATOR>::construct( allocator, toBegin, bslmf::MovableRefUtil::move(*fromBegin)); ++fromBegin; toBegin = guard.moveEnd(1); } guard.release(); } template <class TARGET_TYPE, class ALLOCATOR> void ArrayPrimitives_Imp::moveIfNoexcept( TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(toBegin || fromBegin == fromEnd); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(fromBegin, fromEnd)); AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> guard(toBegin, toBegin, allocator); while (fromBegin != fromEnd) { bsl::allocator_traits<ALLOCATOR>::construct( allocator, toBegin, bslmf::MovableRefUtil::move_if_noexcept(*fromBegin)); ++fromBegin; toBegin = guard.moveEnd(1); } guard.release(); } // *** 'defaultConstruct' overloads: *** template <class TARGET_TYPE, class ALLOCATOR> inline void ArrayPrimitives_Imp::defaultConstruct( TARGET_TYPE *begin, size_type numElements, ALLOCATOR , bslmf::MetaInt<e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numElements != 0)) { std::memset(static_cast<void *>(begin), 0, sizeof(TARGET_TYPE) * numElements); } } template <class TARGET_TYPE, class ALLOCATOR> inline void ArrayPrimitives_Imp::defaultConstruct( TARGET_TYPE *begin, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); if (0 < numElements) { bsl::allocator_traits<ALLOCATOR>::construct(allocator, begin); bitwiseFillN(reinterpret_cast<char *>(begin), sizeof(TARGET_TYPE), numElements * sizeof(TARGET_TYPE)); } } template <class TARGET_TYPE, class ALLOCATOR> void ArrayPrimitives_Imp::defaultConstruct( TARGET_TYPE *begin, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(begin || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> guard(begin, begin, allocator); const TARGET_TYPE *end = begin + numElements; while (begin != end) { bsl::allocator_traits<ALLOCATOR>::construct(allocator, begin); begin = guard.moveEnd(1); } guard.release(); } // *** 'destructiveMove' overloads: *** template <class TARGET_TYPE, class ALLOCATOR> inline void ArrayPrimitives_Imp::destructiveMove( TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, ALLOCATOR , bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *) { BSLS_ASSERT_SAFE(toBegin || fromBegin == fromEnd); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(fromBegin, fromEnd)); const size_type numBytes = reinterpret_cast<const char*>(fromEnd) - reinterpret_cast<const char*>(fromBegin); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numBytes != 0)) { std::memcpy((void *)toBegin, fromBegin, numBytes); } } template <class TARGET_TYPE, class ALLOCATOR> inline void ArrayPrimitives_Imp::destructiveMove( TARGET_TYPE *toBegin, TARGET_TYPE *fromBegin, TARGET_TYPE *fromEnd, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(toBegin || fromBegin == fromEnd); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(fromBegin, fromEnd)); // 'TARGET_TYPE' certainly cannot be bit-wise copyable, so we can save the // compiler some work. moveIfNoexcept(toBegin, fromBegin, fromEnd, allocator, (bslmf::MetaInt<e_NIL_TRAITS>*)0); ArrayDestructionPrimitives::destroy(fromBegin, fromEnd, allocator); } // *** 'emplace' with 'args' overloads: *** #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES template <class TARGET_TYPE, class ALLOCATOR, class... ARGS> inline void ArrayPrimitives_Imp::emplace( TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *, ARGS&&... args) { // TBD: The implementation is exactly the same as 'BITWISE_MOVEABLE_TRAITS' // unless 'AutoArrayMoveDestructor' has a 'release' method so the guard can // be called off after one in-place construction. Then an optimization // using 'bitwiseFillN' is possible. ArrayPrimitives_Imp::emplace(toBegin, toEnd, allocator, (bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS>*)0, BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...); } template <class TARGET_TYPE, class ALLOCATOR, class... ARGS> void ArrayPrimitives_Imp::emplace( TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *, ARGS&&... args) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); // TBD: fix to reflect that its only a single item.... size_type numElements = 1; // Key to the transformation diagrams: //.. // A...G original contents of '[toBegin, toEnd)' ("tail") // v...v contents of '[fromBegin, fromEnd)' ("input") // _____ uninitialized array element // [...] part of an array guarded by an exception guard object // |.(.,.) part of array guarded by move guard // (middle indicated by ',' and dest by '|') //.. size_type tailLen = toEnd - toBegin; size_type numGuarded = tailLen < numElements ? tailLen : numElements; //.. // Transformation: ABCDE_______ => _______ABCDE (might overlap) //.. TARGET_TYPE *destBegin = toBegin + numElements; if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(tailLen != 0)) { std::memmove((void *)destBegin, toBegin, tailLen * sizeof(TARGET_TYPE)); } //.. // Transformation: |_______(,ABCDE) => vvvvv|__(ABCDE,) //.. TARGET_TYPE *destEnd = toEnd + numElements; AutoArrayMoveDestructor<TARGET_TYPE, ALLOCATOR> guard(toBegin, destEnd - numGuarded, destEnd - numGuarded, destEnd, allocator); while (guard.middle() != guard.end()) { bsl::allocator_traits<ALLOCATOR>::construct(allocator, guard.destination(), BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...); guard.advance(); } // The bitwise 'guard' is now inactive, since 'middle() == end()' and // 'guard.destination()' is the smaller of 'destBegin' or 'toEnd'. if (tailLen < numElements) { // There still is a gap of 'numElements - tailLen' to fill in between // 'toEnd' and 'destBegin'. The elements that have been 'memmove'-ed // need to be guarded, we fill the gap backward from there to keep // guarded portion in one piece. AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> endGuard(destBegin, destEnd, allocator); //.. // Transformation: vvvvv__[ABCDE] => vvvvv[vvABCDE] //.. while (toEnd != destBegin) { bsl::allocator_traits<ALLOCATOR>::construct(allocator, --destBegin, BSLS_COMPILERFEATURES_FORWARD(ARGS,args)...); endGuard.moveBegin(-1); } endGuard.release(); } } template <class TARGET_TYPE, class ALLOCATOR, class... ARGS> void ArrayPrimitives_Imp::emplace(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *, ARGS&&... args) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); // Key to the transformation diagrams: //.. // A...G original contents of '[toBegin, toEnd)' ("tail") // v...v copies of 'value' ("input") // _____ uninitialized array elements // [...] part of array protected by an exception guard object //.. if (toEnd > toBegin) { // Insert in the middle. First, construct a temporary object from the // parameter pack of the strong exception guarantee if the construction // throws. A welcome consequence is that the parameter pack may refer // (directly or indirectly) into a container element. bsls::ObjectBuffer<TARGET_TYPE> space; bsl::allocator_traits<ALLOCATOR>::construct( allocator, BSLS_UTIL_ADDRESSOF(space.object()), BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...); bslma::DestructorProctor<TARGET_TYPE> temp( BSLS_UTIL_ADDRESSOF(space.object())); //.. // Transformation: ABCDEFG_[] => ABCDEFG[G]. //.. bsl::allocator_traits<ALLOCATOR>::construct( allocator, toEnd, bslmf::MovableRefUtil::move_if_noexcept(*(toEnd - 1))); AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> guard(toEnd, toEnd + 1, allocator); //.. // Transformation: ABCDEFG[G] => AABCDEF[G]. //.. TARGET_TYPE *destEnd = toEnd; TARGET_TYPE *srcEnd = toEnd - 1; while (toBegin != srcEnd) { *--destEnd = bslmf::MovableRefUtil::move_if_noexcept(*--srcEnd); } //.. // Transformation: AABCDEFG[G] => vABCDEF[G]. //.. *toBegin = bslmf::MovableRefUtil::move_if_noexcept(space.object()); guard.release(); } else { //.. // Transformation: _ => v. //.. bsl::allocator_traits<ALLOCATOR>::construct( allocator, toEnd, BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...); } } #endif // *** 'erase' overloads: *** template <class TARGET_TYPE, class ALLOCATOR> void ArrayPrimitives_Imp::erase( TARGET_TYPE *first, TARGET_TYPE *middle, TARGET_TYPE *last, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(first, middle)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(middle, last)); // Key to the transformation diagrams: //.. // t...z Original contents of '[first, middle)' // A...G Original contents of '[middle, last)' // _ Destroyed array element //.. //.. // Transformation: tuvABCDEFG => ___ABCDEFG (no throw) //.. ArrayDestructionPrimitives::destroy(first, middle, allocator); //.. // Transformation: ___ABCDEFG => ABCDEFG___ (might overlap, but no throw) //.. size_type numBytes = reinterpret_cast<const char *>(last) - reinterpret_cast<const char *>(middle); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numBytes != 0)) { std::memmove((void *)first, middle, numBytes); } } template <class TARGET_TYPE, class ALLOCATOR> void ArrayPrimitives_Imp::erase(TARGET_TYPE *first, TARGET_TYPE *middle, TARGET_TYPE *last, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(first, middle)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(middle, last)); // Key to the transformation diagrams: //.. // t...z Original contents of '[first, middle)' // A...G Original contents of '[middle, last)' // _ Destructed array element //.. //.. // Transformation: tuvABCDEFG => ABCDEFGEFG. //.. while (middle != last) { *first++ = bslmf::MovableRefUtil::move_if_noexcept(*middle++); } //.. // Transformation: ABCDEFGEFG => ABCDEFG___. //.. ArrayDestructionPrimitives::destroy(first, middle, allocator); } // *** 'insert' with 'value' overloads: *** template <class TARGET_TYPE, class ALLOCATOR> inline void ArrayPrimitives_Imp::insert( TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, const TARGET_TYPE& value, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); // Key to the transformation diagrams: //.. // A...G original contents of '[toBegin, toEnd)' ("tail") // v...v contents of '[fromBegin, fromEnd)' ("input") // _____ uninitialized array element //.. // ALIASING: If 'value' is a reference into the array 'toBegin..toEnd', // then moving the array first might introduce a change in 'value'. Since // type is bitwise copyable, then no memory changes outside the array, so // the test below is sufficient to discover all the possible aliasing. // Note that we never make a copy. const TARGET_TYPE *tempValuePtr = BSLS_UTIL_ADDRESSOF(value); if (toBegin <= tempValuePtr && tempValuePtr < toEnd ) { // Adjust pointer for shifting after the move. tempValuePtr += numElements; } //.. // Transformation: ABCDE___ => ___ABCDE (might overlap). //.. const size_type numBytes = reinterpret_cast<const char*>(toEnd) - reinterpret_cast<const char*>(toBegin); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numBytes != 0)) { std::memmove((void *)(toBegin + numElements), toBegin, numBytes); } //.. // Transformation: ___ABCDE => v__ABCDE (no overlap). //.. // Use 'copyConstruct' instead of 'memcpy' because the former optimizes for // fundamental types using 'operator=' instead, which avoid the 'memcpy' // function call. bsl::allocator_traits<ALLOCATOR>::construct(allocator, toBegin, *tempValuePtr); //.. // Transformation: v__ABCDE => vvvABCDE. //.. bitwiseFillN(reinterpret_cast<char *>(toBegin), sizeof value, numElements * sizeof value); } template <class TARGET_TYPE, class ALLOCATOR> void ArrayPrimitives_Imp::insert( TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, const TARGET_TYPE& value, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); // Key to the transformation diagrams: //.. // A...G original contents of '[toBegin, toEnd)' ("tail") // v...v contents of '[fromBegin, fromEnd)' ("input") // _____ uninitialized array element // [...] part of an array guarded by an exception guard object // |.(.,.) part of array guarded by move guard // (middle indicated by ',' and dest by '|') //.. const TARGET_TYPE *tempValuePtr = BSLS_UTIL_ADDRESSOF(value); if (toBegin <= tempValuePtr && tempValuePtr < toEnd + numElements) { // Adjust pointer for shifting after the move. tempValuePtr += numElements; } size_type tailLen = toEnd - toBegin; size_type numGuarded = tailLen < numElements ? tailLen : numElements; //.. // Transformation: ABCDE_______ => _______ABCDE (might overlap) //.. TARGET_TYPE *destBegin = toBegin + numElements; if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(tailLen != 0)) { std::memmove((void *)destBegin, toBegin, tailLen * sizeof(TARGET_TYPE)); } //.. // Transformation: |_______(,ABCDE) => vvvvv|__(ABCDE,) //.. TARGET_TYPE *destEnd = toEnd + numElements; AutoArrayMoveDestructor<TARGET_TYPE, ALLOCATOR> guard(toBegin, destEnd - numGuarded, destEnd - numGuarded, destEnd, allocator); while (guard.middle() != guard.end()) { bsl::allocator_traits<ALLOCATOR>::construct(allocator, guard.destination(), *tempValuePtr); guard.advance(); } // The bitwise 'guard' is now inactive, since 'middle() == end()' and // 'guard.destination()' is the smaller of 'destBegin' or 'toEnd'. if (tailLen < numElements) { // There still is a gap of 'numElements - tailLen' to fill in between // 'toEnd' and 'destBegin'. The elements that have been 'memmove'-ed // need to be guarded, we fill the gap backward from there to keep // guarded portion in one piece. AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> endGuard(destBegin, destEnd, allocator); //.. // Transformation: vvvvv__[ABCDE] => vvvvv[vvABCDE] //.. while (toEnd != destBegin) { bsl::allocator_traits<ALLOCATOR>::construct(allocator, --destBegin, *tempValuePtr); endGuard.moveBegin(-1); } endGuard.release(); } } template <class TARGET_TYPE, class ALLOCATOR> void ArrayPrimitives_Imp::insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, const TARGET_TYPE& value, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); // Aliasing: Make a temp copy of 'value' (always). The reason is that // 'value' could be a reference inside the input range, or even outside // but with lifetime controlled by one of these values, and so the next // transformation could invalidate 'value'. Note: One cannot rely on // 'TARGET_TYPE' to have a single-argument copy constructor (i.e., // default allocator argument to 0) if it takes an allocator; hence the // constructor proxy. bsls::ObjectBuffer<TARGET_TYPE> space; bslma::ConstructionUtil::construct(BSLS_UTIL_ADDRESSOF(space.object()), bslma::Default::allocator(), value); bslma::DestructorProctor<TARGET_TYPE> temp( BSLS_UTIL_ADDRESSOF(space.object())); // Key to the transformation diagrams: //.. // A...G original contents of '[toBegin, toEnd)' ("tail") // v...v copies of 'value' ("input") // _____ uninitialized array elements // [...] part of array protected by an exception guard object //.. const size_type tailLen = toEnd - toBegin; if (tailLen >= numElements) { // Tail is not shorter than input. //.. // Transformation: ABCDEFG___[] => ABCDEFG[EFG]. //.. moveIfNoexcept(toEnd, // destination toEnd - numElements, // source toEnd, // end source allocator, (bslmf::MetaInt<e_NIL_TRAITS> *)0); AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> guard(toEnd, toEnd + numElements, allocator); // TBD: this does the same thing as the old code - don't like that we // circumvent the whole allocator thing, but for now, let's keep it // consistent. // ConstructorProxy<TARGET_TYPE> // tempValue(value, bslma::Default::allocator()); //.. // Transformation: ABCDEFG[EFG] => ABCABCD[EFG]. //.. TARGET_TYPE *src = toEnd - numElements; TARGET_TYPE *dest = toEnd; while (toBegin != src) { *--dest = bslmf::MovableRefUtil::move_if_noexcept(*--src); } //.. // Transformation: ABCABCD[EFG] => vvvABCD[EFG]. //.. for ( ; toBegin != dest; ++toBegin) { *toBegin = space.object(); } // TBD: this can't be good guard.release(); } else { // Tail is shorter than input. We can avoid the temp copy of value // since there will be space to make a first copy after the tail, and // use that to make the subsequent copies. // // TBD: Update comment now that the assumption is no longer true, and // we make a copy at the top of the call, regardless. We could // restore this optimization if we use metaprogramming to check if // 'moveIfNoexcept' will move or copy, but not convinced it is worth // the complexity. difference_type remElements = numElements - tailLen; //.. // Transformation: ABC_______[] => ABC____[ABC]. //.. moveIfNoexcept(toBegin + numElements, // destination toBegin, // source toEnd, // end source allocator, (bslmf::MetaInt<e_NIL_TRAITS>*)0); AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> guard(toEnd + remElements, toEnd + numElements, allocator); //.. // Transformation: ABC____[ABC] => ABC[vvvvABC]. //.. uninitializedFillN(toEnd, space.object(), remElements, &allocator, (bslmf::MetaInt<e_NIL_TRAITS>*)0); guard.moveBegin(-remElements); //.. // Transformation: ABC[vvvvABC] => vvv[vvvvABC]. //.. for ( ; toBegin != toEnd; ++toBegin) { *toBegin = space.object(); } guard.release(); } } // *** 'insert' with 'FWD_ITER' overloads: *** template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> inline void ArrayPrimitives_Imp::insert( TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, FWD_ITER fromBegin, FWD_ITER fromEnd, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_IS_POINTER_TO_POINTER> *) { // We may be casting a function pointer to a 'void *' here, so this won't // work if we port to an architecture where the two are of different sizes. BSLMF_ASSERT(sizeof(void *) == sizeof(void (*)())); #if defined(BSLALG_ARRAYPRIMITIVES_CANNOT_REMOVE_POINTER_FROM_FUNCTION_POINTER) // fall back on traditional C-style casts. insert((void * *)toBegin, (void * *)toEnd, (void * const *)fromBegin, (void * const *)fromEnd, numElements, allocator, (bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *) 0); #else typedef typename bsl::remove_cv< typename bsl::remove_pointer<TARGET_TYPE>::type>::type NcPtrType; typedef typename bsl::remove_cv< typename bsl::remove_pointer< typename bsl::remove_pointer<FWD_ITER>::type>::type>::type NcIter; insert( reinterpret_cast<void * *>(const_cast<NcPtrType **>(toBegin)), reinterpret_cast<void * *>(const_cast<NcPtrType **>(toEnd)), reinterpret_cast<void * const *>(const_cast<NcIter * const *>(fromBegin)), reinterpret_cast<void * const *>(const_cast<NcIter * const *>(fromEnd)), numElements, allocator, (bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *) 0); #endif } template <class TARGET_TYPE, class ALLOCATOR> inline void ArrayPrimitives_Imp::insert( TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, const TARGET_TYPE *fromBegin, const TARGET_TYPE *fromEnd, size_type numElements, ALLOCATOR , bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *) { BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); // 'FWD_ITER' has been converted to a 'const TARGET_TYPE *' and // 'TARGET_TYPE' is bit-wise copyable. BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(fromBegin, fromEnd)); BSLS_ASSERT_SAFE(fromBegin || 0 == numElements); BSLS_ASSERT_SAFE(fromBegin + numElements == fromEnd); BSLS_ASSERT_SAFE(fromEnd <= toBegin || toEnd + numElements <= fromBegin); (void) fromEnd; // quell warning when 'BSLS_ASSERT_SAFE' is compiled out // Key to the transformation diagrams: //.. // A...G original contents of '[toBegin, toEnd)' ("tail") // t...z contents of '[fromBegin, fromEnd)' ("input") // _____ uninitialized array element //.. //.. // Transformation: ABCDE_______ => _______ABCDE (might overlap). //.. const size_type numBytes = reinterpret_cast<const char*>(toEnd) - reinterpret_cast<const char*>(toBegin); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numBytes != 0)) { std::memmove((void *)(toBegin + numElements), toBegin, numBytes); } //.. // Transformation: _______ABCDE => tuvwxyzABCDE (no overlap). //.. if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(numElements != 0)) { std::memcpy((void *)toBegin, fromBegin, numElements * sizeof(TARGET_TYPE)); } } template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> void ArrayPrimitives_Imp::insert( TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, FWD_ITER fromBegin, FWD_ITER, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *) { // 'TARGET_TYPE' is bit-wise moveable. BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); if (0 == numElements) { return; // RETURN } // The following assertions make sense only if 'FWD_ITER' is a pointer to a // possibly cv-qualified 'TARGET_TYPE', and are tested in that overload // (see above). //.. // BSLS_ASSERT(fromBegin + numElements == fromEnd); // BSLS_ASSERT(fromEnd <= toBegin || toEnd + numElements <= fromBegin); //.. // Key to the transformation diagrams: //.. // A...G original contents of '[toBegin, toEnd)' ("tail") // t...z contents of '[fromBegin, fromEnd)' ("input") // _____ uninitialized array element // [...] part of array guarded by exception guard // |.(.,.) part of array guarded by move guard // (middle indicated by ',' and dest by '|') //.. const size_type tailLen = toEnd - toBegin; const size_type numGuarded = tailLen < numElements ? tailLen : numElements; //.. // Transformation: ABCDE____ => ____ABCDE (might overlap). //.. TARGET_TYPE *destBegin = toBegin + numElements; if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(tailLen != 0)) { std::memmove((void *)destBegin, toBegin, tailLen * sizeof(TARGET_TYPE)); } //.. // Transformation: |_______(,ABCDE) => tuvwx|__(ABCDE,). //.. TARGET_TYPE *destEnd = toEnd + numElements; AutoArrayMoveDestructor<TARGET_TYPE, ALLOCATOR> guard(toBegin, destEnd - numGuarded, destEnd - numGuarded, destEnd, allocator); for (; guard.middle() != guard.end(); ++fromBegin) { bsl::allocator_traits<ALLOCATOR>::construct(allocator, guard.destination(), *fromBegin); guard.advance(); } // The bitwise 'guard' is now inactive, since 'middle() == end()', and // 'guard.destination()' is the smaller of 'destBegin' or 'toEnd'. if (tailLen < numElements) { // There still is a gap of 'numElements - tailLen' to fill in between // 'toEnd' and 'destBegin'. The elements that have been 'memmove'-ed // need to be guarded, and we need to continue to fill the hole at the // same guarding the copied elements as well. AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> endGuard1(toEnd, toEnd, allocator); AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> endGuard2(destBegin, destEnd, allocator); //.. // Transformation: tuvwx[]__[ABCDE] => tuvwx[yz][ABCDE]. //.. for (; toEnd != destBegin; ++fromBegin) { bsl::allocator_traits<ALLOCATOR>::construct(allocator, toEnd, *fromBegin); toEnd = endGuard1.moveEnd(1); } endGuard1.release(); endGuard2.release(); } } template <class TARGET_TYPE, class FWD_ITER, class ALLOCATOR> void ArrayPrimitives_Imp::insert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, FWD_ITER fromBegin, FWD_ITER fromEnd, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); if (0 == numElements) { return; // RETURN } // Key to the transformation diagrams: //.. // A...G original contents of '[toBegin, toEnd)' ("tail") // t...z contents of '[fromBegin, fromEnd)' ("input") // _____ uninitialized array elements // [...] part of array protected by a guard object //.. const size_type tailLen = toEnd - toBegin; if (tailLen > numElements) { // Tail is longer than input. //.. // Transformation: ABCDEFG___[] => ABCDEFG[EFG]. //.. moveIfNoexcept(toEnd, // destination toEnd - numElements, // source toEnd, // end source allocator, (bslmf::MetaInt<e_NIL_TRAITS>*)0); AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> guard(toEnd, toEnd + numElements, allocator); //.. // Transformation: ABCDEFG[EFG] => ABCABCD[EFG]. //.. TARGET_TYPE *src = toEnd - numElements; TARGET_TYPE *dest = toEnd; while (toBegin != src) { *--dest = bslmf::MovableRefUtil::move_if_noexcept(*--src); } //.. // Transformation: ABCABCD[EFG] => tuvABCD[EFG]. //.. for (; toBegin != dest; ++toBegin, ++fromBegin) { *toBegin = *fromBegin; } guard.release(); } else { // Tail is not longer than input (numElements). difference_type remElements = numElements - tailLen; //.. // Transformation: ABC_______[] => ABC____[ABC] //.. moveIfNoexcept(toBegin + numElements, // destination toBegin, // source toEnd, // end source allocator, (bslmf::MetaInt<e_NIL_TRAITS>*)0); AutoArrayDestructor<TARGET_TYPE, ALLOCATOR> guard(toEnd + remElements, toEnd + numElements, allocator); //.. // Transformation: ABC____[ABC] => tuv____[ABC]. //.. for (; toBegin != toEnd; ++fromBegin, ++toBegin) { *toBegin = *fromBegin; } //.. // Transformation: tuv____[ABC] => tuvwxyzABC[]. //.. copyConstruct(toBegin, fromBegin, fromEnd, allocator, (bslmf::MetaInt<e_NIL_TRAITS>*)0); guard.release(); } } template <class FWD_ITER, class ALLOCATOR> void ArrayPrimitives_Imp::insert( void **toBegin, void **toEnd, FWD_ITER fromBegin, FWD_ITER, size_type numElements, ALLOCATOR , bslmf::MetaInt<e_IS_ITERATOR_TO_FUNCTION_POINTER> *) { // This very specific overload is required for the case that 'FWD_ITER' is // an iterator that is not a pointer, iterating over a sequence of function // pointers. The implementation relies on the conditionally-supported // behavior that any function pointer can be 'reinterpret_cast' to // 'void *'. // 'TARGET_TYPE' is bit-wise moveable. BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); if (0 == numElements) { return; // RETURN } // The following assertions make sense only if 'FWD_ITER' is a pointer to a // possibly cv-qualified 'TARGET_TYPE', and are tested in that overload // (see above). //.. // BSLS_ASSERT(fromBegin + numElements == fromEnd); // BSLS_ASSERT(fromEnd <= toBegin || toEnd + numElements <= fromBegin); //.. // Key to the transformation diagrams: //.. // A...G original contents of '[toBegin, toEnd)' ("tail") // t...z contents of '[fromBegin, fromEnd)' ("input") // _____ uninitialized array element // [...] part of array guarded by exception guard // |.(.,.) part of array guarded by move guard // (middle indicated by ',' and dest by '|') //.. const size_type tailLen = toEnd - toBegin; //.. // Transformation: ABCDE____ => ____ABCDE (might overlap). //.. void **destBegin = toBegin + numElements; if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(tailLen != 0)) { std::memmove(destBegin, toBegin, tailLen * sizeof(void **)); } for (size_type i = 0; i < numElements; ++i) { *toBegin = reinterpret_cast<void *>(*fromBegin); ++fromBegin; ++toBegin; } } // *** 'moveInsert' overloads: *** template <class TARGET_TYPE, class ALLOCATOR> inline void ArrayPrimitives_Imp::moveInsert( TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, TARGET_TYPE **lastPtr, TARGET_TYPE *first, TARGET_TYPE *last, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(first, last)); BSLS_ASSERT_SAFE(first || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); BSLS_ASSERT_SAFE(lastPtr); // Functionally indistinguishable from this: *lastPtr = last; insert(toBegin, toEnd, first, last, numElements, allocator, (bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS>*)0); *lastPtr = first; } template <class TARGET_TYPE, class ALLOCATOR> inline void ArrayPrimitives_Imp::moveInsert(TARGET_TYPE *toBegin, TARGET_TYPE *toEnd, TARGET_TYPE **lastPtr, TARGET_TYPE *first, TARGET_TYPE *last, size_type numElements, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(toBegin, toEnd)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(first, last)); BSLS_ASSERT_SAFE(first || 0 == numElements); BSLMF_ASSERT((bsl::is_same<size_type, std::size_t>::value)); BSLS_ASSERT_SAFE(lastPtr); // There isn't any advantage at destroying [first,last) one by one as we're // moving it, except perhaps for slightly better memory usage. *lastPtr = last; insert(toBegin, toEnd, first, last, numElements, allocator, (bslmf::MetaInt<e_NIL_TRAITS>*)0); ArrayDestructionPrimitives::destroy(first, last, allocator); *lastPtr = first; } // *** 'rotate' overloads: *** template <class TARGET_TYPE> inline void ArrayPrimitives_Imp::rotate( TARGET_TYPE *begin, TARGET_TYPE *middle, TARGET_TYPE *end, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(begin, middle)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(middle, end)); bitwiseRotate(reinterpret_cast<char *>(begin), reinterpret_cast<char *>(middle), reinterpret_cast<char *>(end)); } template <class TARGET_TYPE> void ArrayPrimitives_Imp::rotate(TARGET_TYPE *begin, TARGET_TYPE *middle, TARGET_TYPE *end, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(begin, middle)); BSLS_ASSERT_SAFE(!ArrayPrimitives_Imp::isInvalidRange(middle, end)); if (begin == middle || middle == end) { // This test changes into O(1) what would otherwise be O(N): Do not // remove! return; // RETURN } // This case is simple enough, it should be taken care of on its own. const std::size_t numElements = middle - begin; const std::size_t remElements = end - middle; if (numElements == remElements) { for (; middle != end; ++begin, ++middle) { TARGET_TYPE tmp(*middle); *middle = *begin; *begin = tmp; } return; // RETURN } // This algorithm proceeds by decomposing the rotation into cycles, which // can then be rotated using a single element buffer. First we compute the // 'gcd(end - begin, numElements)' which is the number of cycles in the // rotation. std::size_t numCycles = end - begin; std::size_t remainder = numElements; while (remainder != 0) { std::size_t t = numCycles % remainder; numCycles = remainder; remainder = t; } // Key to the transformation diagrams: //.. // A...D Contents of the current cycle // W...Z Contents of another cycle // _ Elements not in the current cycle //.. for (std::size_t i = 0; i < numCycles; ++i) { // Let the current cycle be initially 'A__B__C__D__', (note that its // stride is 'length / numCycles') and let (*) denote the current // position of 'ptr'. TARGET_TYPE *ptr = begin; // seed for current cycle: A(*)__B__C__D__ TARGET_TYPE tmp = *ptr; // value held at the seed: tmp == A if (numElements < remElements) { // Rotate the cycle forward by numElements positions (or backward // by -(length-numElements)=-remElements positions if crossing the // boundary forward). The transformation is: //.. // A(*)__B__C__D__ => B__B(*)__C__D__ // => B__C__C(*)__D__ // => B__C__D__D(*)__ //.. // The length of the cycle is always 'length / numCycles', but it // crosses the range boundaries 'numElements / numCycles' times, // each triggering an extra assignment in the 'if' clause below, so // the loop must only be executed: //.. // (length - numElements) / numCycles = remElements / numCycles //.. // times. std::size_t cycleSize = remElements / numCycles; for (std::size_t j = 0; j < cycleSize; ++j) { if (ptr > begin + remElements) { // Wrap around the range boundaries. (Note that // '-remElements == numElements - (end - begin)'.) *ptr = *(ptr - remElements); ptr -= remElements; } *ptr = *(ptr + numElements); ptr += numElements; } } else { // Rotate the cycle backward by '-remElements' positions (or // forward by 'numElements' positions if crossing the boundary // backward). The transformation is: //.. // A(*)__B__C__D__ => D__B__C__D(*)__ // => D__B__C(*)__C__ // => D__B(*)__B__C__ //.. // The length of the cycle is always 'length/numCycles', but going // backward (which adds an initial extra crossing) crosses the // range boundaries 'remElements/numCycles+1' times each of which // trigger an extra assignment in the 'if' clause below, so the // loop must only be executed: //.. // (length - remElements) / numCycles - 1 = // numElements / numCycles - 1 //.. // times. std::size_t cycleSize = numElements / numCycles - 1; for (std::size_t j = 0; j < cycleSize; ++j) { if (ptr < end - numElements) { *ptr = *(ptr + numElements); ptr += numElements; } *ptr = *(ptr - remElements); ptr -= remElements; } } *ptr = tmp; // Close the cycle, e.g.: //.. // (first case): B__C__D__D(*)__ => B__C__D__A__ // (second case): D__D(*)__B__C__ => D__A__B__C__ //.. ++begin; // and move on to the next cycle: //.. // => _W__X__Y__Z_ //.. } } // *** 'shiftAndInsert' overloads: *** template <class ALLOCATOR> inline void ArrayPrimitives_Imp::shiftAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer begin, typename bsl::allocator_traits<ALLOCATOR>::pointer end, bslmf::MovableRef< typename bsl::allocator_traits<ALLOCATOR>::value_type> value, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_COPYABLE_TRAITS> *) { BSLS_ASSERT_SAFE(begin != end); // the range is non-empty typedef typename bsl::allocator_traits<ALLOCATOR>::value_type ValueType; // ALIASING: If 'value' is a reference into the array '[begin, end)', // then moving the array first might introduce a change in 'value'. // Fortunately we can easily predict its new position after the shift. ValueType *valuePtr = BSLS_UTIL_ADDRESSOF(bslmf::MovableRefUtil::access(value)); if (begin <= valuePtr && valuePtr < end) { valuePtr += 1; // new address after the shift } #if defined(BSLS_PLATFORM_PRAGMA_GCC_DIAGNOSTIC_GCC) // clang does not support this pragma #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wclass-memaccess" #endif // shift std::memmove(begin + 1, begin, (end - begin) * sizeof(ValueType)); // insert bsl::allocator_traits<ALLOCATOR>::construct( allocator, begin, bslmf::MovableRefUtil::move_if_noexcept(*valuePtr)); #if defined(BSLS_PLATFORM_PRAGMA_GCC_DIAGNOSTIC_GCC) #pragma GCC diagnostic pop #endif } template <class ALLOCATOR> inline void ArrayPrimitives_Imp::shiftAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer begin, typename bsl::allocator_traits<ALLOCATOR>::pointer end, bslmf::MovableRef< typename bsl::allocator_traits<ALLOCATOR>::value_type> value, ALLOCATOR allocator, bslmf::MetaInt<e_BITWISE_MOVEABLE_TRAITS> *) { BSLS_ASSERT_SAFE(begin != end); // the range is non-empty typedef typename bsl::allocator_traits<ALLOCATOR>::value_type ValueType; // ALIASING: If 'value' is a reference into the array '[begin, end)', // then moving the array first might introduce a change in 'value'. // Fortunately we can easily predict its new position after the shift. ValueType *valuePtr = BSLS_UTIL_ADDRESSOF(bslmf::MovableRefUtil::access(value)); if (begin <= valuePtr && valuePtr < end) { valuePtr += 1; // new address after the shift } // shift size_t bytesNum = (end - begin) * sizeof(ValueType); #if defined(BSLS_PLATFORM_PRAGMA_GCC_DIAGNOSTIC_GCC) // clang does not support this pragma #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wclass-memaccess" #endif std::memmove(begin + 1, begin, bytesNum); class ElementsProctor { // Moves the elements back if 'construct' throws. // DATA ValueType *d_begin; size_t d_bytesNum; public: // CREATORS ElementsProctor(ValueType *p, size_t n) : d_begin(p), d_bytesNum(n) {} ~ElementsProctor() { if(d_bytesNum) std::memmove(d_begin, d_begin + 1, d_bytesNum); } // MANIPULATORS void release() { d_bytesNum = 0; } } proctor(begin, bytesNum); // insert bsl::allocator_traits<ALLOCATOR>::construct( allocator, begin, bslmf::MovableRefUtil::move_if_noexcept(*valuePtr)); proctor.release(); #if defined(BSLS_PLATFORM_PRAGMA_GCC_DIAGNOSTIC_GCC) #pragma GCC diagnostic pop #endif } template <class ALLOCATOR> inline void ArrayPrimitives_Imp::shiftAndInsert( typename bsl::allocator_traits<ALLOCATOR>::pointer begin, typename bsl::allocator_traits<ALLOCATOR>::pointer end, bslmf::MovableRef< typename bsl::allocator_traits<ALLOCATOR>::value_type> value, ALLOCATOR allocator, bslmf::MetaInt<e_NIL_TRAITS> *) { BSLS_ASSERT_SAFE(begin != end); // the range is non-empty typedef typename bsl::allocator_traits<ALLOCATOR>::value_type ValueType; // ALIASING: If 'value' is a reference into the array '[begin, end)', // then moving the array first might introduce a change in 'value'. // Fortunately we can easily predict its new position after the shift. ValueType *valuePtr = BSLS_UTIL_ADDRESSOF(bslmf::MovableRefUtil::access(value)); if (begin <= valuePtr && valuePtr < end) { valuePtr += 1; // new address after the shift } // Key to the transformation diagrams: //.. // A...G original contents of '[toBegin, toEnd)' ("tail") // a...g moved-from or copied values // v moved 'value' ("input") // _____ uninitialized array elements // [...] part of array protected by an exception guard object //.. //.. // Transformation: ABCDEFG_[] => ABCDEFg[G]. //.. bsl::allocator_traits<ALLOCATOR>::construct( allocator, end, bslmf::MovableRefUtil::move_if_noexcept(*(end - 1))); bslalg::AutoArrayDestructor<ValueType, ALLOCATOR> guard( end, end + 1, allocator); //.. // Transformation: ABCDEFg[G] => aABCDEF[G]. //.. ValueType *dst = end; ValueType *src = end - 1; while (src != begin) { *--dst = bslmf::MovableRefUtil::move_if_noexcept(*--src); } //.. // Transformation: aABCDEFG[G] => vABCDEF[G]. //.. *begin = bslmf::MovableRefUtil::move_if_noexcept(*valuePtr); guard.release(); } } // close package namespace #ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY // ============================================================================ // BACKWARD COMPATIBILITY // ============================================================================ typedef bslalg::ArrayPrimitives bslalg_ArrayPrimitives; // This alias is defined for backward compatibility. #endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY } // close enterprise namespace #if defined(BSLALG_ARRAYPRIMITIVES_CANNOT_REMOVE_POINTER_FROM_FUNCTION_POINTER) # undef BSLALG_ARRAYPRIMITIVES_CANNOT_REMOVE_POINTER_FROM_FUNCTION_POINTER #endif #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 ----------------------------------