// bslma_allocatoradaptor.h -*-C++-*- #ifndef INCLUDED_BSLMA_ALLOCATORADAPTOR #define INCLUDED_BSLMA_ALLOCATORADAPTOR #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a polymorphic adaptor for STL-style allocators // //@CLASSES: AllocatorAdaptor<ALLOC> // //@SEE_ALSO: // //@DESCRIPTION: Within the BDE libraries, the prefered way to handle memory // allocation is through a pointer to the polymorphic base class, // 'bslma::Allocator'. The use of a run-time polymorphism for the allocator // has numerous advantages over the compile-time polymorphism used by the STL // components. However, there are times when client code may have an // STL-style allocator available and needs to use it with a BDE component. // // This component provides a class template, 'AllocatorAdaptor' that wraps the // STL-style allocator in an object of class derived from 'bslma::Allocator'. // A pointer to the object can thus be used with any component that uses // BDE-style memory allocation. // ///Usage ///----- // Let's start with a simple class, 'my::FilePath', which allocates storage // using a 'bslma::Allocator': //.. // #include <bslma_allocator.h> // #include <bslma_default.h> // #include <bsls_nullptr.h> // // #include <cstring> // #include <cstdlib> // // namespace my { // // class FilePath { // // Store the path of a file or directory // bslma::Allocator *d_allocator; // char *d_data; // // public: // FilePath(bslma::Allocator* basicAllocator = 0 /* nullptr */) // : d_allocator(bslma::Default::allocator(basicAllocator)) // , d_data(0 /* nullptr */) { } // // FilePath(const char* s, bslma::Allocator* basicAllocator = 0) // : d_allocator(bslma::Default::allocator(basicAllocator)) // { // d_data = // static_cast<char*>(d_allocator->allocate(std::strlen(s) + 1)); // std::strcpy(d_data, s); // } // // bslma::Allocator *getAllocator() const { return d_allocator; } // // //... // }; // // } // close namespace my //.. // Next, assume that an STL-allocator exists that uses memory exactly the way // you need: //.. // template <class TYPE> // class MagicAllocator { // bool d_useMalloc; // public: // typedef TYPE value_type; // typedef TYPE *pointer; // typedef const TYPE *const_pointer; // typedef unsigned size_type; // typedef int difference_type; // // template <class U> // struct rebind { // typedef MagicAllocator<U> other; // }; // // explicit MagicAllocator(bool useMalloc = false) // : d_useMalloc(useMalloc) { } // // template <class U> // MagicAllocator(const MagicAllocator<U>& other) // : d_useMalloc(other.getUseMalloc()) { } // // value_type *allocate(std::size_t n, void* = 0 /* nullptr */) { // if (d_useMalloc) // return (value_type*) std::malloc(n * sizeof(value_type)); // else // return (value_type*) ::operator new(n * sizeof(value_type)); // } // // void deallocate(value_type *p, std::size_t) { // if (d_useMalloc) // std::free(p); // else // ::operator delete(p); // } // // static size_type max_size() { return UINT_MAX / sizeof(TYPE); } // // void construct(pointer p, const TYPE& value) // { new((void *)p) TYPE(value); } // // void destroy(pointer p) { p->~TYPE(); } // // int getUseMalloc() const { return d_useMalloc; } // }; // // template <class T, class U> // inline // bool operator==(const MagicAllocator<T>& a, const MagicAllocator<U>& b) // { // return a.getUseMalloc() == b.getUseMalloc(); // } // // template <class T, class U> // inline // bool operator!=(const MagicAllocator<T>& a, const MagicAllocator<U>& b) // { // return a.getUseMalloc() != b.getUseMalloc(); // } //.. // Now, if we want to create a 'FilePath' using a 'MagicAllocator', we // need to adapt the 'MagicAllocator' to the 'bslma::Allocator' protocol. // This is where 'bslma::AllocatorAdaptor' comes in: //.. // int main() // { // MagicAllocator<char> ma(true); // bslma::AllocatorAdaptor<MagicAllocator<char> >::Type maa(ma); // // my::FilePath usrbin("/usr/local/bin", &maa); // // assert(&maa == usrbin.getAllocator()); // assert(ma == maa.adaptedAllocator()); // // return 0; // } //.. #include <bslscm_version.h> #include <bslma_allocator.h> #include <bslmf_assert.h> #include <bslmf_issame.h> #include <bsls_alignmentutil.h> #include <bsls_compilerfeatures.h> namespace BloombergLP { namespace bslma { // =================================== // class template AllocatorAdaptor_Imp // =================================== template <class STL_ALLOC> class AllocatorAdaptor_Imp : public Allocator { // Component-private class. Do not use. This class provides the actual // interface and implementaiton for 'AllocatorAdaptor', which inherits // from it. The indirection is necessary so that // 'AllocatorAdaptor<Alloc<T>>' and 'AllocatorAdaptor<Alloc<U>>' produce // only one instantiation of this template: // 'AllocatorAdaptor_imp<Alloc<char>>'. BSLMF_ASSERT((bsl::is_same<typename STL_ALLOC::value_type, char>::value)); // PRIVATE TYPES typedef bsls::AlignmentUtil::MaxAlignedType MaxAlignedType; // PRIVATE DATA typename STL_ALLOC::template rebind<MaxAlignedType>::other d_stlAllocator; // NOT ASSIGNABLE AllocatorAdaptor_Imp& operator=(const AllocatorAdaptor_Imp&); // = delete public: // TYPES typedef AllocatorAdaptor_Imp Type; typedef STL_ALLOC StlAllocatorType; // CREATORS AllocatorAdaptor_Imp(); // = default // Construct a polymorphic wrapper around a default-constructed // STL-style allocator. AllocatorAdaptor_Imp(const StlAllocatorType& stla); // Construct a polymorphic wrapper around a copy of the specified // 'stla' STL-style allocator. #if defined(BSLS_COMPILERFEATURES_SUPPORT_DEFAULTED_FUNCTIONS) AllocatorAdaptor_Imp(const AllocatorAdaptor_Imp& original) = default; // Create an 'AllocatorAdaptor_Imp' object that can allocate and // deallocate memory as if it were the specified 'original' object. #endif virtual ~AllocatorAdaptor_Imp(); // Destroy this object and the STL-style allocator that it wraps. // MANIPULATORS virtual void *allocate(size_type size); // Return a maximally-aligned block of memory no smaller than 'size' // bytes allocated from the STL-style allocator that was supplied to // this object's constructor. Any exceptions thrown by the underlying // STL-style allocator are propagated out from this member. virtual void deallocate(void *address); // Return the memory block at the specified 'address' back to the // STL-allocator. If 'address' is null, this funciton has no effect. // The behavior is undefined unless 'address' was allocated using this // allocator object and has not already been deallocated. // ACCESSORS STL_ALLOC adaptedAllocator() const; // Return a copy of the STL allocator stored within this object. }; // =============================== // class template AllocatorAdaptor // =============================== #ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES template <class STL_ALLOC> using AllocatorAdaptor = AllocatorAdaptor_Imp<typename STL_ALLOC::template rebind<char>::other>; // Polymorphic wrapper around an STL-style allocator. Note that // 'AllocatorAdaptor<A>::Type' is the same type regardless of whether or // not the compiler supports alias templates. It should be used, // therefore, whenever the exact type of the adaptor is important. #else template <class STL_ALLOC> class AllocatorAdaptor : public AllocatorAdaptor_Imp<typename STL_ALLOC::template rebind<char>::other> { // Polymorphic wrapper around an object of the specified 'STL_ALLOC' // STL-style allocator template parameter. A pointer to an object of this // class can thus be used with any component that uses BDE-style memory // allocation. Note that 'AllocatorAdaptor<A>::Type' is the same type // regardless of whether or not the compiler supports alias templates. It // should be used, therefore, whenever the exact type of the adaptor is // important. typedef typename STL_ALLOC::template rebind<char>::other ReboundSTLAlloc; // Not assignable AllocatorAdaptor& operator=(const AllocatorAdaptor&); // = delete public: // CREATORS AllocatorAdaptor(); // = default // Constructs a polymorphic wrapper around a default-constructed // STL-style allocator. AllocatorAdaptor(const STL_ALLOC& stla); // Constructs a polymorphic wrapper around a copy of the specified // 'stla' STL-style allocator. //! AllocatorAdaptor(const AllocatorAdaptor&); //! ~AllocatorAdaptor(); }; #endif // BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES } // close package namespace // =========================================================================== // TEMPLATE IMPLEMENTATION // =========================================================================== // ----------------------------------- // class template AllocatorAdaptor_Imp // ----------------------------------- // CREATORS template <class STL_ALLOC> inline bslma::AllocatorAdaptor_Imp<STL_ALLOC>::AllocatorAdaptor_Imp() : d_stlAllocator() { } template <class STL_ALLOC> inline bslma::AllocatorAdaptor_Imp<STL_ALLOC>::AllocatorAdaptor_Imp( const StlAllocatorType& stla) : d_stlAllocator(stla) { } template <class STL_ALLOC> inline bslma::AllocatorAdaptor_Imp<STL_ALLOC>::~AllocatorAdaptor_Imp() { } // MANIPULATORS template <class STL_ALLOC> void *bslma::AllocatorAdaptor_Imp<STL_ALLOC>::allocate(size_type size) { BSLMF_ASSERT(sizeof(size_type) <= sizeof(MaxAlignedType)); // Compute number of 'MaxAlignedType' objects needed to make up 'size' // bytes plus an extra one to hold the size. size_type n = 1 + (size+sizeof(MaxAlignedType)-1) / sizeof(MaxAlignedType); MaxAlignedType* p = d_stlAllocator.allocate(n); *reinterpret_cast<size_type*>(p) = n; return ++p; } template <class STL_ALLOC> void bslma::AllocatorAdaptor_Imp<STL_ALLOC>::deallocate(void *address) { MaxAlignedType *p = static_cast<MaxAlignedType*>(address); // Extract size from slot before 'p' size_type n = *reinterpret_cast<size_type*>(--p); d_stlAllocator.deallocate(p, n); } // ACCESSORS template <class STL_ALLOC> STL_ALLOC bslma::AllocatorAdaptor_Imp<STL_ALLOC>::adaptedAllocator() const { return d_stlAllocator; } #ifndef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES // ------------------------------- // class template AllocatorAdaptor // ------------------------------- // CREATORS template <class STL_ALLOC> inline bslma::AllocatorAdaptor<STL_ALLOC>::AllocatorAdaptor() // = default { } template <class STL_ALLOC> inline bslma::AllocatorAdaptor<STL_ALLOC>::AllocatorAdaptor(const STL_ALLOC& stla) : bslma::AllocatorAdaptor_Imp<ReboundSTLAlloc>(stla) { } #endif // ! BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES } // close enterprise namespace #endif // ! defined(INCLUDED_BSLMA_ALLOCATORADAPTOR) // ---------------------------------------------------------------------------- // 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 ----------------------------------