// bslma_stdtestallocator.h -*-C++-*- #ifndef INCLUDED_BSLMA_STDTESTALLOCATOR #define INCLUDED_BSLMA_STDTESTALLOCATOR #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide stl-compatible, 'bslma'-style allocator to track usage. // //@CLASSES: // bslma::StdTestAllocator: instrumented 'bslma-style' stl allocator template // //@MACROS: // //@SEE_ALSO: TBD // //@DESCRIPTION: TBD #include <bslscm_version.h> #include <bslma_constructionutil.h> #include <bslma_destructionutil.h> #include <bslma_testallocator.h> #include <bslma_default.h> #include <bslmf_isbitwiseequalitycomparable.h> #include <bslmf_isbitwisemoveable.h> #include <bslmf_issame.h> #include <bslmf_istriviallycopyable.h> #include <bslmf_nestedtraitdeclaration.h> namespace BloombergLP { namespace bslma { // ====================== // class StdTestAllocator // ====================== template <class TYPE> class StdTestAllocator { // An STL-compatible test allocator that forwards allocation calls to an // underlying mechanism object of a type derived from // 'bslma::TestAllocator'. 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 TestAllocator *d_mechanism; public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(StdTestAllocator, bsl::is_trivially_copyable); BSLMF_NESTED_TRAIT_DECLARATION(StdTestAllocator, bslmf::IsBitwiseMoveable); BSLMF_NESTED_TRAIT_DECLARATION(StdTestAllocator, 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 typename bsl::conditional<bsl::is_void<TYPE>::value, void, TYPE&>::type reference; typedef typename bsl::conditional<bsl::is_void<TYPE>::value, void, const TYPE&>::type const_reference; // 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 a 'StdTestAllocator' // type following the same template as this one but that allocates // elements of 'ANY_TYPE'. Note that this 'StdTestAllocator' type is // convertible to and from 'other' for any type, including 'void'. typedef StdTestAllocator<ANY_TYPE> other; }; // CREATORS StdTestAllocator(); // TBD: fix comment to mention that the default allocator has to be // a test 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(); //.. StdTestAllocator(Allocator *mechanism); // IMPLICIT // TBD: fix comment to mention that 'mechanism' has to be a test // allocator. // Convert a 'bslma::Allocator' pointer to an test 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'. StdTestAllocator(const StdTestAllocator& original); // Create a proxy object using the same mechanism as the specified // 'original'. Postcondition: 'this->mechanism() == rhs.mechanism()'. template <class ANY_TYPE> StdTestAllocator(const StdTestAllocator<ANY_TYPE>& rhs); // Create a proxy object sharing the same mechanism object as the // specified 'rhs'. The newly constructed test allocator will compare // equal to 'rhs', even though they are instantiated on different // types. Postcondition: 'this->mechanism() == rhs.mechanism()'. //! ~StdTestAllocator(); // 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. //! StdTestAllocator& operator=(const StdTestAllocator& rhs); // 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. // MANIPULATORS 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 test 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 test allocator type. template <class ELEMENT_TYPE> void construct(ELEMENT_TYPE *address, const TYPE& val); // Copy-construct an object of (template parameter) 'TYPE' from the // specified 'val' at the memory address specified by 'p'. Do not // directly allocate memory. The behavior is undefined unless 'p' is // not properly aligned for objects of the given 'TYPE'. 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 test allocator. Note that there is // no guarantee that attempts at allocating fewer elements than the // value returned by 'max_size' will not throw. TestAllocator *mechanism() const; // Return a pointer to the mechanism object to which this proxy // forwards allocation and deallocation calls. }; // FREE OPERATORS template <class T1, class T2> inline bool operator==(const StdTestAllocator<T1>& lhs, const StdTestAllocator<T2>& rhs); // Return 'true' if the specified 'lhs' and 'rhs' are proxies for the same // 'bslma::TestAllocator' 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 StdTestAllocator<T1>& lhs, const StdTestAllocator<T2>& rhs); // Return 'true' unless the specified 'lhs' and 'rhs' are proxies for the // same 'bslma::TestAllocator' 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 StdTestAllocator<TYPE>& lhs, const TestAllocator *rhs); // Return 'true' if the specified 'lhs' is a proxy for the specified 'rhs', // and 'false' otherwise. template <class TYPE> inline bool operator!=(const StdTestAllocator<TYPE>& lhs, const TestAllocator *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 TestAllocator *lhs, const StdTestAllocator<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 TestAllocator *lhs, const StdTestAllocator<TYPE>& rhs); // Return 'true' unless the specified 'rhs' is a proxy for the specified // 'lhs', in which case return 'false'. // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // ---------------------- // class StdTestAllocator // ---------------------- // LOW-LEVEL ACCESSORS template <class TYPE> inline TestAllocator *StdTestAllocator<TYPE>::mechanism() const { return d_mechanism; } // CREATORS template <class TYPE> inline StdTestAllocator<TYPE>::StdTestAllocator() : d_mechanism(dynamic_cast<TestAllocator *>(Default::defaultAllocator())) { BSLS_ASSERT_SAFE(d_mechanism); } template <class TYPE> inline StdTestAllocator<TYPE>::StdTestAllocator(Allocator *mechanism) : d_mechanism(dynamic_cast<TestAllocator *>(Default::allocator(mechanism))) { BSLS_ASSERT_SAFE(d_mechanism); } template <class TYPE> inline StdTestAllocator<TYPE>::StdTestAllocator(const StdTestAllocator& original) : d_mechanism(original.mechanism()) { BSLS_ASSERT_SAFE(d_mechanism); } template <class TYPE> template <class ANY_TYPE> inline StdTestAllocator<TYPE>::StdTestAllocator(const StdTestAllocator<ANY_TYPE>& rhs) : d_mechanism(rhs.mechanism()) { BSLS_ASSERT_SAFE(d_mechanism); } // MANIPULATORS template <class TYPE> inline typename StdTestAllocator<TYPE>::pointer StdTestAllocator<TYPE>::allocate(typename StdTestAllocator::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 StdTestAllocator<TYPE>::deallocate(typename StdTestAllocator::pointer p, typename StdTestAllocator::size_type n) { (void) n; // suppress unused parameter warning d_mechanism->deallocate(p); } template <class TYPE> template <class ELEMENT_TYPE> inline void StdTestAllocator<TYPE>::construct(ELEMENT_TYPE *address, const TYPE& val) { new (static_cast<void*>(address)) ELEMENT_TYPE(val); } template <class TYPE> template <class ELEMENT_TYPE> inline void StdTestAllocator<TYPE>::destroy(ELEMENT_TYPE *address) { DestructionUtil::destroy(address); } // ACCESSORS template <class TYPE> inline typename StdTestAllocator<TYPE>::const_pointer StdTestAllocator<TYPE>::address(const_reference x) const { return BSLS_UTIL_ADDRESSOF(x); } template <class TYPE> inline typename StdTestAllocator<TYPE>::pointer StdTestAllocator<TYPE>::address(reference x) const { return BSLS_UTIL_ADDRESSOF(x); } template <class TYPE> inline typename StdTestAllocator<TYPE>::size_type StdTestAllocator<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<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; } // FREE OPERATORS template <class T1, class T2> inline bool operator==(const StdTestAllocator<T1>& lhs, const StdTestAllocator<T2>& rhs) { return lhs.mechanism() == rhs.mechanism(); } template <class T1, class T2> inline bool operator!=(const StdTestAllocator<T1>& lhs, const StdTestAllocator<T2>& rhs) { return ! (lhs == rhs); } template <class TYPE> inline bool operator==(const StdTestAllocator<TYPE>& lhs, const TestAllocator *rhs) { return lhs.mechanism() == rhs; } template <class TYPE> inline bool operator!=(const StdTestAllocator<TYPE>& lhs, const TestAllocator *rhs) { return ! (lhs == rhs); } template <class TYPE> inline bool operator==(const TestAllocator *lhs, const StdTestAllocator<TYPE>& rhs) { return lhs == rhs.mechanism(); } template <class TYPE> inline bool operator!=(const TestAllocator *lhs, const StdTestAllocator<TYPE>& rhs) { return ! (lhs == rhs); } } // close package namespace } // close enterprise namespace #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 ----------------------------------