// bslma_stdallocator.h -*-C++-*- #ifndef INCLUDED_BSLMA_STDALLOCATOR #define INCLUDED_BSLMA_STDALLOCATOR #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide an STL-compatible proxy for 'bslma::Allocator' objects. // //@CLASSES: // bsl::allocator: STL-compatible allocator template // bsl::allocator_traits<bsl::allocator>: specialization for 'bsl::allocator' // //@CANONICAL_HEADER: bsl_memory.h // //@SEE_ALSO: bslma_allocator // // TBD: update component-level doc //@DESCRIPTION: This component is for internal use only. Please include // '<bsl_memory.h>' instead and use 'bsl::allocator' directly. This component // provides an STL-compatible proxy for any allocator class derived from // 'bslma::Allocator'. The proxy class, 'bsl::allocator' is a template that // adheres to the allocator requirements defined in section 20.1.5 // [lib.allocator.requirements] of the C++ standard. 'bsl::allocator' may be // used to instantiate any class template that is parameterized by a standard // allocator. The container is expected to allocate memory for its own use // through the allocator. Different types of allocator use different // allocation mechanisms, so this mechanism gives the programmer control over // how the container obtains memory. // // The 'bsl::allocator' template is intended to solve a problem created by the // C++ standard allocator protocol. Since, in STL, the allocator type is // specified as a container template parameter, the allocation mechanism // becomes an explicit part of the resulting container type. Two containers // cannot be of the same type unless they are instantiated with the same // allocator type, and therefore the same allocation mechanism. // 'bsl::allocator' breaks the connection between allocator type and allocation // mechanism. The allocation mechanism is chosen at *run-time* by // *initializing* (contrast with *instantiating*) the 'bsl::allocator' with a // pointer to a *mechanism* *object* derived from 'bslma::Allocator'. Each // class derived from 'bslma::Allocator' implements a specific allocation // mechanism and is thus called a *mechanism* *class* within this component. // The 'bsl::allocator' object forwards calls made through the standard // allocator interface to the mechanism object with which it was initialized. // In this way, two containers instantiated with 'bsl::allocator' can utilize // different allocation mechanisms even though they have the same compile-time // type. The default mechanism object, if none is supplied to the // 'bsl::allocator' constructor, is 'bslma::Default::defaultAllocator()'. // // Instantiations of 'bsl::allocator' have full value semantics (well-behaved // copy construction, assignment, and tests for equality). Note, however, that // a 'bsl::allocator' object does not "own" the 'bslma::Allocator' with which // it is initialized. In practice , this means that copying a 'bsl::allocator' // object does not copy its mechanism object and destroying a 'bsl::allocator' // does not destroy its mechanism object. Two 'bsl::allocator' objects compare // equal if and only if they share the same mechanism object. // ///Restrictions on Allocator Usage ///------------------------------- // The allocator requirements section of the C++ standard (section 20.1.5 // [lib.allocator.requirements]) permits containers to assume that two // allocators of the same type always compare equal. This assumption is // incorrect for instantiations of 'bsl::allocator'. Therefore, any container // (or other facility) that can use 'bsl::allocator' must operate correctly in // the presence of non-equal 'bsl::allocator' objects. In practice, this means // that a container cannot transfer ownership of allocated memory to another // container unless the two containers use equal allocators. Two // 'bsl::allocator' objects will compare equal if and only if they were // initialized with the same mechanism object. // ///Usage ///----- // We first show how to define a container type parameterized with an STL-style // allocator template parameter. For simplicity, we choose a fixed-size array // to avoid issues concerning reallocation, dynamic growth, etc. Furthermore, // we do not assume the 'bslma' allocation protocol, which would dictate that // we pass-through the allocator to the parameterized 'T' contained type (see // the 'bslma_allocator' component and 'bslalg' package). The interface would // be as follows: //.. // // my_fixedsizearray.h // // // ======================= // // class my_FixedSizeArray // // ======================= // // template <class TYPE, class ALLOC> // class my_FixedSizeArray { // // This class provides an array of (the template parameter) 'TYPE' // // passed of fixed length at construction, using an instance of the // // parameterized 'ALLOC' type to supply memory. // // // DATA // ALLOC d_allocator; // int d_length; // TYPE *d_array; // // // INVARIANTS // // public: // // TYPES // typedef ALLOC allocator_type; // typedef TYPE value_type; // // // CREATORS // explicit my_FixedSizeArray(int length, // const ALLOC& allocator = ALLOC()); // // Create a fixed-size array of the specified 'length', using the // // optionally specified 'allocator' to supply memory. If // // 'allocator' is not specified, a default-constructed instance of // // the parameterized 'ALLOC' type is used. Note that all the // // elements in that array are default-constructed. // // my_FixedSizeArray(const my_FixedSizeArray& original, // const ALLOC& allocator = ALLOC()); // // Create a copy of the specified 'original' fixed-size array, // // using the optionally specified 'allocator' to supply memory. If // // 'allocator' is not specified, a default-constructed instance of // // the parameterized 'ALLOC' type is used. // // ~my_FixedSizeArray(); // // Destroy this fixed size array. // // // MANIPULATORS // TYPE& operator[](int index); // // Return a reference to the modifiable element at the specified // // 'index' position in this fixed size array. // // // ACCESSORS // const TYPE& operator[](int index) const; // // Return a reference to the modifiable element at the specified // // 'index' position in this fixed size array. // // const ALLOC& allocator() const; // // Return a reference to the non-modifiable allocator used by this // // fixed size array to supply memory. This is here for // // illustrative purposes. We should not generally have an accessor // // to return the allocator. // // int length() const; // // Return the length specified at construction of this fixed size // // array. // }; // // // FREE OPERATORS // template<class TYPE, class ALLOC> // bool operator==(const my_FixedSizeArray<TYPE, ALLOC>& lhs, // const my_FixedSizeArray<TYPE, ALLOC>& rhs); // // Return 'true' if the specified 'lhs' fixed-size array has the same // // value as the specified 'rhs' fixed-size array, and 'false' // // otherwise. Two fixed-size arrays have the same value if they have // // the same length and if the element at any index in 'lhs' has the // // same value as the corresponding element at the same index in 'rhs'. // // namespace BloombergLP { // namespace bslma { // // template <class TYPE, class ALLOC> // struct UsesBslmaAllocator< my_FixedSizeArray<TYPE, ALLOC> > // : bsl::is_convertible<Allocator*, ALLOC>::type // { // }; // // } // close namespace bslma // } // close enterprise namespace // //.. // The implementation is straightforward //.. // // ----------------------- // // class my_FixedSizeArray // // ----------------------- // // // CREATORS // template<class TYPE, class ALLOC> // my_FixedSizeArray<TYPE, ALLOC>::my_FixedSizeArray(int length, // const ALLOC& allocator) // : d_allocator(allocator), d_length(length) // { // d_array = d_allocator.allocate(d_length); // sizeof(T)*d_length bytes // // // Default construct each element of the array: // for (int i = 0; i < d_length; ++i) { // d_allocator.construct(&d_array[i], TYPE()); // } // } // // template<class TYPE, class ALLOC> // my_FixedSizeArray<TYPE, ALLOC>::my_FixedSizeArray( // const my_FixedSizeArray& original, // const ALLOC& allocator) // : d_allocator(allocator), d_length(original.d_length) // { // d_array = d_allocator.allocate(d_length); // sizeof(T)*d_length bytes // // // copy construct each element of the array: // for (int i = 0; i < d_length; ++i) { // d_allocator.construct(&d_array[i], original.d_array[i]); // } // } // // template<class TYPE, class ALLOC> // my_FixedSizeArray<TYPE, ALLOC>::~my_FixedSizeArray() // { // // Call destructor for each element // for (int i = 0; i < d_length; ++i) { // d_allocator.destroy(&d_array[i]); // } // // // Return memory to allocator. // d_allocator.deallocate(d_array, d_length); // } // // // MANIPULATORS // template<class TYPE, class ALLOC> // inline TYPE& my_FixedSizeArray<TYPE, ALLOC>::operator[](int index) // { // return d_array[index]; // } // // // ACCESSORS // template<class TYPE, class ALLOC> // inline // const TYPE& my_FixedSizeArray<TYPE, ALLOC>::operator[](int index) const // { // return d_array[index]; // } // // template<class TYPE, class ALLOC> // inline // const ALLOC& my_FixedSizeArray<TYPE, ALLOC>::allocator() const // { // return d_allocator; // } // // // FREE OPERATORS // template<class TYPE, class ALLOC> // bool operator==(const my_FixedSizeArray<TYPE, ALLOC>& lhs, // const my_FixedSizeArray<TYPE, ALLOC>& rhs) // { // if (lhs.length() != rhs.length()) { // return false; // RETURN // } // for (int i = 0; i < lhs.length(); ++i) { // if (lhs[i] != rhs[i]) { // return false; // RETURN // } // } // return true; // } // // template<class TYPE, class ALLOC> // inline int my_FixedSizeArray<TYPE, ALLOC>::length() const // { // return d_length; // } // //.. // Now we declare an allocator mechanism. Our mechanism will be to simply call // the global 'operator new' and 'operator delete' functions, and count the // number of blocks outstanding (allocated but not deallocated). Note that a // more reusable implementation would take an underlying mechanism at // construction. We keep things simple only for the sake of this example. //.. // // my_countingallocator.h // // // ========================== // // class my_CountingAllocator // // ========================== // // class my_CountingAllocator : public bslma::Allocator { // // This concrete implementation of the 'bslma::Allocator' protocol // // maintains some statistics of the number of blocks outstanding (i.e., // // allocated but not yet deallocated). // // // DATA // int d_blocksOutstanding; // // public: // // CREATORS // my_CountingAllocator(); // // Create a counting allocator that uses the operators 'new' and // // 'delete' to supply and free memory. // // // MANIPULATORS // virtual void *allocate(size_type size); // // Return a pointer to an uninitialized memory of the specified // // size (in bytes). // // virtual void deallocate(void *address); // // Return the memory at the specified 'address' to this allocator. // // // ACCESSORS // int blocksOutstanding() const; // // Return the number of blocks outstanding (i.e., allocated but not // // yet deallocated by this counting allocator). // }; //.. // The implementation is really straightforward: //.. // // my_countingallocator.cpp // // // -------------------------- // // class my_CountingAllocator // // -------------------------- // // // CREATORS // my_CountingAllocator::my_CountingAllocator() // : d_blocksOutstanding(0) // { // } // // // MANIPULATORS // void *my_CountingAllocator::allocate(size_type size) // { // ++d_blocksOutstanding; // return operator new(size); // } // // void my_CountingAllocator::deallocate(void *address) // { // --d_blocksOutstanding; // operator delete(address); // } // // // ACCESSORS // int my_CountingAllocator::blocksOutstanding() const // { // return d_blocksOutstanding; // } //.. // Now we can create array objects with different allocator mechanisms. First // we create an array, 'a1', using the default allocator and fill it with the // values '1 .. 5': //.. // void usageExample() { // // my_FixedSizeArray<int, bsl::allocator<int> > a1(5); // assert(5 == a1.length()); // assert(bslma::Default::defaultAllocator() == a1.allocator()); // // for (int i = 0; i < a1.length(); ++i) { // a1[i] = i + 1; // } //.. // Then we create a copy of 'a1' using the counting allocator. The values of // 'a1' and 'a2' are equal, even though they have different allocation // mechanisms. //.. // my_CountingAllocator countingAlloc; // my_FixedSizeArray<int, bsl::allocator<int> > a2(a1,&countingAlloc); // assert(a1 == a2); // assert(a1.allocator() != a2.allocator()); // assert(&countingAlloc == a2.allocator()); // assert(1 == countingAlloc.blocksOutstanding()); //.. // Then we create a copy of 'a2' using the default allocator. The values of // 'a1', 'a2' and 'a3' are equal, even though they have different allocation // mechanisms. //.. // my_FixedSizeArray<int, bsl::allocator<int> > a3(a2); // assert(a1 == a3); // assert(a1 == a2); // assert(a2 == a3); // assert(a1.allocator() == a3.allocator()); // assert(a1.allocator() != a2.allocator()); // assert(a2.allocator() != a3.allocator()); // assert(bsl::allocator<int>() == a3.allocator()); // } //.. // To exercise the propagation of the allocator of 'MyContainer' to its // elements, we first create a representative element class, 'MyType', that // allocates memory using the bslma allocator protocol: //.. // #include <bslma_default.h> // // class MyType { // // bslma::Allocator *d_allocator_p; // // etc. // public: // // TRAITS // BSLMF_NESTED_TRAIT_DECLARATION(MyType, bslma::UsesBslmaAllocator); // // // CREATORS // explicit MyType(bslma::Allocator* basicAlloc = 0) // : d_allocator_p(bslma::Default::allocator(basicAlloc)) { /* ... */ } // MyType(const MyType&) // : d_allocator_p(bslma::Default::allocator(0)) { /* ... */ } // MyType(const MyType&, bslma::Allocator* basicAlloc) // : d_allocator_p(bslma::Default::allocator(basicAlloc)) { /* ... */ } // // etc. // // // ACCESSORS // bslma::Allocator *allocator() const { return d_allocator_p; } // // // etc. //}; //.. // Finally, we instantiate 'my_FixedSizeArray' using 'MyType' and verify that, // when we provide the address of an allocator to the constructor of the // container, the same address is passed to the constructor of the container's // element. We also verify that, when the container is copy-constructed, the // copy uses the default allocator, not the allocator from the original; // moreover, we verify that the element stored in the copy also uses the // default allocator. //.. // #include <bslmf_issame.h> // // void usageExample2() // { // bslma::TestAllocator testAlloc; // my_FixedSizeArray<MyType, bsl::allocator<MyType> > C1a(7, &testAlloc); // ASSERT((bsl::is_same< // my_FixedSizeArray<MyType, bsl::allocator<MyType> >::allocator_type, // bsl::allocator<MyType> >::value)); // ASSERT(C1a.allocator() == bsl::allocator<MyType>(&testAlloc)); // ASSERT(C1a[0].allocator() == &testAlloc); // // my_FixedSizeArray<MyType, bsl::allocator<MyType> > C2a(C1a); // ASSERT(C2a.allocator() != C1a.allocator()); // ASSERT(C2a.allocator() == bsl::allocator<MyType>()); // ASSERT(C2a[0].allocator() != &testAlloc); // ASSERT(C2a[0].allocator() == bslma::Default::defaultAllocator()); // // MyType dummy; // my_FixedSizeArray<MyType, bsl::allocator<MyType> > C1b(7, &testAlloc); // ASSERT((bsl::is_same< // my_FixedSizeArray<MyType, bsl::allocator<MyType> >::allocator_type, // bsl::allocator<MyType> >::value)); // ASSERT(C1b.allocator() == bsl::allocator<MyType>(&testAlloc)); // ASSERT(C1b[0].allocator() == &testAlloc); // // my_FixedSizeArray<MyType, bsl::allocator<MyType> > C2b(C1b); // ASSERT(C2b.allocator() != C1b.allocator()); // ASSERT(C2b.allocator() == bsl::allocator<MyType>()); // ASSERT(C2b[0].allocator() != &testAlloc); // ASSERT(C2b[0].allocator() == bslma::Default::defaultAllocator()); //} //.. #include <bslscm_version.h> #include <bslma_allocator.h> #include <bslma_allocatortraits.h> #include <bslma_constructionutil.h> #include <bslma_default.h> #include <bslma_destructionutil.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_assert.h> #include <bslmf_isbitwiseequalitycomparable.h> #include <bslmf_isbitwisemoveable.h> #include <bslmf_issame.h> #include <bslmf_istriviallycopyable.h> #include <bslmf_nestedtraitdeclaration.h> #include <bslmf_util.h> // 'forward(V)' #include <bsls_assert.h> #include <bsls_compilerfeatures.h> #include <bsls_platform.h> #include <bsls_util.h> // 'forward<T>(V)' #include <climits> #include <cstddef> #include <new> #if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // Include version that can be compiled with C++03 // Generated on Fri May 13 11:05:19 2022 // Command line: sim_cpp11_features.pl bslma_stdallocator.h # define COMPILING_BSLMA_STDALLOCATOR_H # include <bslma_stdallocator_cpp03.h> # undef COMPILING_BSLMA_STDALLOCATOR_H #else namespace bsl { // =============== // class allocator // =============== template <class TYPE> class allocator { // An STL-compatible allocator that forwards allocation calls to an // underlying mechanism object of a type derived from 'bslma::Allocator'. // This class template adheres to the allocator requirements defined in // section 20.1.5 [lib.allocator.requirements] of the C++ standard and may // be used to instantiate any [container] class template that follows the // STL allocator protocol. The allocation mechanism is chosen at run-time, // giving the programmer run-time control over how a container allocates // and frees memory. // DATA BloombergLP::bslma::Allocator *d_mechanism; public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(allocator, bsl::is_trivially_copyable); BSLMF_NESTED_TRAIT_DECLARATION(allocator, BloombergLP::bslmf::IsBitwiseMoveable); BSLMF_NESTED_TRAIT_DECLARATION( allocator, BloombergLP::bslmf::IsBitwiseEqualityComparable); // Declare nested type traits for this class. // PUBLIC TYPES typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef TYPE *pointer; typedef const TYPE *const_pointer; typedef TYPE& reference; typedef const TYPE& const_reference; typedef TYPE value_type; template <class ANY_TYPE> struct rebind { // This nested 'struct' template, parameterized by 'ANY_TYPE', provides // a namespace for an 'other' type alias, which is an allocator type // following the same template as this one but that allocates elements // of 'ANY_TYPE'. Note that this allocator type is convertible to and // from 'other' for any type, including 'void'. typedef allocator<ANY_TYPE> other; }; // CREATORS allocator(); // Create a proxy object which will forward allocation calls to the // object pointed to by 'bslma::Default::defaultAllocator()'. // Postcondition: //.. // this->mechanism() == bslma::Default::defaultAllocator(); //.. allocator(BloombergLP::bslma::Allocator *mechanism); // IMPLICIT // Convert a 'bslma::Allocator' pointer to an 'allocator' object which // forwards allocation calls to the object pointed to by the specified // 'mechanism'. If 'mechanism' is 0, then the currently installed // default allocator is used instead. Postcondition: // '0 == mechanism || this->mechanism() == mechanism'. allocator(const allocator& original); // Create a proxy object using the same mechanism as the specified // 'original'. Postcondition: 'this->mechanism() == rhs.mechanism()'. template <class ANY_TYPE> allocator(const allocator<ANY_TYPE>& rhs); // Create a proxy object sharing the same mechanism object as the // specified 'rhs'. The newly constructed allocator will compare equal // to 'rhs', even though they are instantiated on different types. // Postcondition: 'this->mechanism() == rhs.mechanism()'. //! ~allocator(); // Destroy this object. Note that this does not delete the object // pointed to by 'mechanism()'. Also note that this method's // definition is compiler generated. // MANIPULATORS #ifdef BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS allocator& operator=(const allocator& rhs) = default; // Assign to this object the value of the specified 'rhs'. // Postcondition: 'this->mechanism() == rhs->mechanism()'. Note that // this does not delete the object pointed to by the previous value of // 'mechanism()'. Also note that this method's definition is compiler // generated. Also note that this must be explicitly defaulted to // silence compiler warnings on later versions of C++. #else //! allocator& operator=(const allocator& rhs) = default; #endif pointer allocate(size_type n, const void *hint = 0); // Allocate enough (properly aligned) space for the specified 'n' // objects of (template parameter) 'TYPE' by calling 'allocate' on the // mechanism object. The optionally specified 'hint' argument is // ignored by this allocator type. The behavior is undefined unless // 'n <= max_size()'. void deallocate(pointer p, size_type n = 1); // Return memory previously allocated with 'allocate' to the underlying // mechanism object by calling 'deallocate' on the mechanism object // with the specified 'p'. The optionally specified 'n' argument is // ignored by this allocator type. #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=14 template <class ELEMENT_TYPE, class... Args> void construct(ELEMENT_TYPE *address, Args&&... arguments); // Construct an object of (template parameter) 'TYPE', by forwarding // the specified (variable number of) 'arguments' to the corresponding // constructor of 'ELEMENT_TYPE', at the specified uninitialized memory // 'address'. The behavior is undefined unless 'address' is properly // aligned for objects of 'ELEMENT_TYPE'. #endif template <class ELEMENT_TYPE> void destroy(ELEMENT_TYPE *address); // Call the 'TYPE' destructor for the object pointed to by the // specified 'p'. Do not directly deallocate any memory. // ACCESSORS pointer address(reference x) const; // Return the address of the object referred to by the specified 'x', // even if the (template parameter) 'TYPE' overloads the unary // 'operator&'. const_pointer address(const_reference x) const; // Return the address of the object referred to by the specified 'x', // even if the (template parameter) 'TYPE' overloads the unary // 'operator&'. size_type max_size() const; // Return the maximum number of elements of (template parameter) 'TYPE' // that can be allocated using this allocator. Note that there is no // guarantee that attempts at allocating fewer elements than the value // returned by 'max_size' will not throw. BloombergLP::bslma::Allocator *mechanism() const; // Return a pointer to the mechanism object to which this proxy // forwards allocation and deallocation calls. allocator<TYPE> select_on_container_copy_construction() const; // TBD: add comment } ; // ===================== // class allocator<void> // ===================== template <> class allocator<void> { // Specialization of 'allocator<T>' where 'T' is 'void'. Does not contain // members that are unrepresentable for 'void' // DATA BloombergLP::bslma::Allocator *d_mechanism; public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(allocator, bsl::is_trivially_copyable); BSLMF_NESTED_TRAIT_DECLARATION(allocator, BloombergLP::bslmf::IsBitwiseMoveable); BSLMF_NESTED_TRAIT_DECLARATION( allocator, BloombergLP::bslmf::IsBitwiseEqualityComparable); // Declare nested type traits for this class. // PUBLIC TYPES typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef void *pointer; typedef const void *const_pointer; typedef void value_type; template <class ANY_TYPE> struct rebind { typedef allocator<ANY_TYPE> other; }; // CREATORS allocator(); // Construct a proxy object which will forward allocation calls to the // object pointed to by 'bslma::Default::defaultAllocator()'. allocator(BloombergLP::bslma::Allocator *mechanism); // IMPLICIT // Convert a 'bslma::Allocator' pointer to an 'allocator' object which // forwards allocation calls to the object pointed to by the specified // 'mechanism'. If 'mechanism' is 0, then the current default // allocator is used instead. Postcondition: // '0 == mechanism || this->mechanism() == mechanism'. allocator(const allocator& original); // Create a proxy object using the same mechanism as the specified // 'original'. Postcondition: 'this->mechanism() == rhs.mechanism()'. template <class ANY_TYPE> allocator(const allocator<ANY_TYPE>& rhs); // Construct a proxy object sharing the same mechanism object as the // specified 'rhs'. The newly constructed allocator will compare equal // to 'rhs', even though they are instantiated on different types. // Postcondition: 'this->mechanism() == rhs.mechanism()'. //! ~allocator(); // Destroy this object. Note that this does not delete the object // pointed to by 'mechanism()'. Also note that this method's // definition is compiler generated. // MANIPULATORS //! allocator& operator=(const allocator& rhs); // Assign this object the value of the specified 'rhs'. Postcondition: // 'this->mechanism() == rhs->mechanism()'. Note that this does not // delete the object pointed to by the previous value of 'mechanism()'. // Also note that this method's definition is compiler generated. // ACCESSORS BloombergLP::bslma::Allocator *mechanism() const; // Return a pointer to the mechanism object to which this proxy // forwards allocation and deallocation calls. allocator<void> select_on_container_copy_construction() const; // TBD: add comment }; // ======================================== // class allocator_traits<allocator<TYPE> > // ======================================== template <class TYPE> struct allocator_traits<allocator<TYPE> > { // This 'struct' template provides a specialization of the // 'allocator_traits' class template for 'bsl::allocator'. // PUBLIC TYPES typedef allocator<TYPE> allocator_type; typedef TYPE value_type; typedef TYPE *pointer; typedef const TYPE *const_pointer; typedef void *void_pointer; typedef const void *const_void_pointer; typedef std::ptrdiff_t difference_type; typedef std::size_t size_type; #ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES template <class ELEMENT_TYPE> using rebind_alloc = allocator<ELEMENT_TYPE>; template <class ELEMENT_TYPE> using rebind_traits = allocator_traits<allocator<ELEMENT_TYPE> >; #else template <class ELEMENT_TYPE> struct rebind_alloc : allocator<ELEMENT_TYPE> { rebind_alloc() : allocator<ELEMENT_TYPE>() { } template <typename ARG> rebind_alloc(const ARG& allocatorArg) // Convert from anything that can be used to cosntruct the base // type. This might be better if SFINAE-ed out using // 'is_convertible', but stressing older compilers more seems // unwise. : allocator<ELEMENT_TYPE>(allocatorArg) { } }; template <class ELEMENT_TYPE> struct rebind_traits : allocator_traits<allocator<ELEMENT_TYPE> > { }; #endif static pointer allocate(allocator<TYPE>& m, size_type n) { return m.allocate(n); } static pointer allocate(allocator<TYPE>& m, size_type n, const_void_pointer hint) { return m.allocate(n, hint); } static void deallocate(allocator<TYPE>& m, pointer p, size_type n) { m.deallocate(p, n); } #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=14 template <class ELEMENT_TYPE, class... Args> static void construct(allocator<TYPE>& m, ELEMENT_TYPE *p, Args&&... arguments) { m.construct(p, BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...); } #endif template <class ELEMENT_TYPE> static void destroy(allocator<TYPE>& m, ELEMENT_TYPE *p) { m.destroy(p); } static size_type max_size(const allocator<TYPE>& m) { return m.max_size(); } // Allocator propagation traits static allocator<TYPE> select_on_container_copy_construction( const allocator<TYPE>&) { return allocator<TYPE>(); } typedef false_type is_always_equal; typedef false_type propagate_on_container_copy_assignment; typedef false_type propagate_on_container_move_assignment; typedef false_type propagate_on_container_swap; }; // FREE OPERATORS template <class T1, class T2> inline bool operator==(const allocator<T1>& lhs, const allocator<T2>& rhs); // Return 'true' if the specified 'lhs' and 'rhs' are proxies for the same // 'bslma::Allocator' object. This is a practical implementation of the // STL requirement that two allocators compare equal if and only if memory // allocated from one can be deallocated from the other. Note that the two // allocators need not be instantiated on the same type in order to compare // equal. template <class T1, class T2> inline bool operator!=(const allocator<T1>& lhs, const allocator<T2>& rhs); // Return 'true' unless the specified 'lhs' and 'rhs' are proxies for the // same 'bslma::Allocator' object, in which case return 'false'. This is a // practical implementation of the STL requirement that two allocators // compare equal if and only if memory allocated from one can be // deallocated from the other. Note that the two allocators need not be // instantiated on the same type in order to compare equal. template <class TYPE> inline bool operator==(const allocator<TYPE>& lhs, const BloombergLP::bslma::Allocator *rhs); // Return 'true' if the specified 'lhs' is a proxy for the specified 'rhs', // and 'false' otherwise. template <class TYPE> inline bool operator!=(const allocator<TYPE>& lhs, const BloombergLP::bslma::Allocator *rhs); // Return 'true' unless the specified 'lhs' is a proxy for the specified // 'rhs', in which case return 'false'. template <class TYPE> inline bool operator==(const BloombergLP::bslma::Allocator *lhs, const allocator<TYPE>& rhs); // Return 'true' if the specified 'rhs' is a proxy for the specified 'lhs', // and 'false' otherwise. template <class TYPE> inline bool operator!=(const BloombergLP::bslma::Allocator *lhs, const allocator<TYPE>& rhs); // Return 'true' unless the specified 'rhs' is a proxy for the specified // 'lhs', in which case return 'false'. // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // --------------- // class allocator // --------------- // LOW-LEVEL ACCESSORS template <class TYPE> inline BloombergLP::bslma::Allocator *allocator<TYPE>::mechanism() const { return d_mechanism; } // CREATORS template <class TYPE> inline allocator<TYPE>::allocator() : d_mechanism(BloombergLP::bslma::Default::defaultAllocator()) { } template <class TYPE> inline allocator<TYPE>::allocator(BloombergLP::bslma::Allocator *mechanism) : d_mechanism(BloombergLP::bslma::Default::allocator(mechanism)) { } template <class TYPE> inline allocator<TYPE>::allocator(const allocator& original) : d_mechanism(original.mechanism()) { } template <class TYPE> template <class ANY_TYPE> inline allocator<TYPE>::allocator(const allocator<ANY_TYPE>& rhs) : d_mechanism(rhs.mechanism()) { } // MANIPULATORS template <class TYPE> inline typename allocator<TYPE>::pointer allocator<TYPE>::allocate( typename allocator::size_type n, const void *hint) { BSLS_ASSERT_SAFE(n <= this->max_size()); (void) hint; // suppress unused parameter warning return static_cast<pointer>(d_mechanism->allocate(n * sizeof(TYPE))); } template <class TYPE> inline void allocator<TYPE>::deallocate(typename allocator::pointer p, typename allocator::size_type n) { (void) n; // suppress unused parameter warning d_mechanism->deallocate(p); } #if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES template <class TYPE> template <class ELEMENT_TYPE, class... Args> inline void allocator<TYPE>::construct(ELEMENT_TYPE *address, Args&&... arguments) { BloombergLP::bslma::ConstructionUtil::construct( address, d_mechanism, BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...); } #endif template <class TYPE> template <class ELEMENT_TYPE> inline void allocator<TYPE>::destroy(ELEMENT_TYPE *address) { BloombergLP::bslma::DestructionUtil::destroy(address); } // ACCESSORS template <class TYPE> inline typename allocator<TYPE>::const_pointer allocator<TYPE>::address( const_reference x) const { return BSLS_UTIL_ADDRESSOF(x); } template <class TYPE> inline typename allocator<TYPE>::pointer allocator<TYPE>::address(reference x) const { return BSLS_UTIL_ADDRESSOF(x); } template <class TYPE> inline typename allocator<TYPE>::size_type allocator<TYPE>::max_size() const { // Return the largest value, 'v', such that 'v * sizeof(T)' fits in a // 'size_type'. // We will calculate MAX_NUM_BYTES based on our knowledge that // 'bslma::Allocator::size_type' is just an alias for 'std::size_t'. First // demonstrate that is true: BSLMF_ASSERT((bsl::is_same<BloombergLP::bslma::Allocator::size_type, std::size_t>::value)); static const std::size_t MAX_NUM_BYTES = ~std::size_t(0); static const std::size_t MAX_NUM_ELEMENTS = MAX_NUM_BYTES / sizeof(TYPE); return MAX_NUM_ELEMENTS; } template <class TYPE> inline allocator<TYPE> allocator<TYPE>::select_on_container_copy_construction() const { return allocator<TYPE>(); } // --------------------- // class allocator<void> // --------------------- // LOW-LEVEL ACCESSORS inline BloombergLP::bslma::Allocator *allocator<void>::mechanism() const { return d_mechanism; } // CREATORS inline allocator<void>::allocator() : d_mechanism(BloombergLP::bslma::Default::defaultAllocator()) { } inline allocator<void>::allocator(BloombergLP::bslma::Allocator *mechanism) : d_mechanism(BloombergLP::bslma::Default::allocator(mechanism)) { } // 'template <>' is needed only for versions of xlC prior to 9 #if defined(__xlC__) && __xlC__ < 0x900 template <> #endif inline allocator<void>::allocator(const allocator<void>& original) : d_mechanism(original.mechanism()) { } template <class ANY_TYPE> inline allocator<void>::allocator(const allocator<ANY_TYPE>& rhs) : d_mechanism(rhs.mechanism()) { } inline allocator<void> allocator<void>::select_on_container_copy_construction() const { return allocator<void>(); } // FREE OPERATORS template <class T1, class T2> inline bool operator==(const allocator<T1>& lhs, const allocator<T2>& rhs) { return lhs.mechanism() == rhs.mechanism(); } template <class T1, class T2> inline bool operator!=(const allocator<T1>& lhs, const allocator<T2>& rhs) { return !(lhs == rhs); } template <class TYPE> inline bool operator==(const allocator<TYPE>& lhs, const BloombergLP::bslma::Allocator *rhs) { return lhs.mechanism() == rhs; } template <class TYPE> inline bool operator!=(const allocator<TYPE>& lhs, const BloombergLP::bslma::Allocator *rhs) { return !(lhs == rhs); } template <class TYPE> inline bool operator==(const BloombergLP::bslma::Allocator *lhs, const allocator<TYPE>& rhs) { return lhs == rhs.mechanism(); } template <class TYPE> inline bool operator!=(const BloombergLP::bslma::Allocator *lhs, const allocator<TYPE>& rhs) { return !(lhs == rhs); } } // close namespace bsl // ============================================================================ // TYPE TRAITS // ============================================================================ namespace BloombergLP { namespace bslma { template <class TYPE> struct UsesBslmaAllocator< ::bsl::allocator<TYPE> > : bsl::false_type { }; } // close namespace bslma } // close enterprise namespace #endif // End C++11 code #endif // ---------------------------------------------------------------------------- // Copyright 2013 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------