// bdlma_infrequentdeleteblocklist.h -*-C++-*- #ifndef INCLUDED_BDLMA_INFREQUENTDELETEBLOCKLIST #define INCLUDED_BDLMA_INFREQUENTDELETEBLOCKLIST #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide allocation and management of infrequently deleted blocks. // //@CLASSES: // bdlma::InfrequentDeleteBlockList: manager of infrequently deleted blocks // //@SEE_ALSO: bdlma_blocklist // //@DESCRIPTION: This component implements a low-level memory manager, // 'bdlma::InfrequentDeleteBlockList', that allocates and manages a sequence of // memory blocks, each of a potentially different size as specified during the // 'allocate' method's invocation. The 'release' method of a // 'bdlma::InfrequentDeleteBlockList' object deallocates the entire sequence of // outstanding memory blocks, as does its destructor. Note that, in contrast // to 'bdlma::BlockList', the 'bdlma::InfrequentDeleteBlockList' class does // *not* support the deallocation of individual items. In particular, although // 'bdlma::InfrequentDeleteBlockList' has a 'deallocate' method, that method // has no effect. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Creating a Memory Pools for Strings /// - - - - - - - - - - - - - - - - - - - - - - - // A 'bdlma::InfrequentDeleteBlockList' object is commonly used to supply // memory to more elaborate memory managers that distribute parts of each // (larger) allocated memory block supplied by the // 'bdlma::InfrequentDeleteBlockList' object. The 'my_StrPool' memory pool // manager shown below requests relatively large blocks of memory from its // 'bdlma::InfrequentDeleteBlockList' member object and distributes memory // chunks of varying sizes from each block on demand: //.. // // my_strpool.h // // class my_StrPool { // // // DATA // char *d_block_p; // current memory block // // bsls::Types::size_type d_blockSize; // size of current memory block // // bsls::Types::IntPtr d_cursor; // offset to next available byte // // in block // // bdlma::InfrequentDeleteBlockList // d_blockList; // supplies managed memory blocks // // private: // // PRIVATE MANIPULATORS // void *allocateBlock(bsls::Types::size_type numBytes); // // Request a memory block of at least the specified 'numBytes' size // // and allocate the initial 'numBytes' from this block. Return the // // address of the allocated memory. The behavior is undefined // // unless '0 < numBytes'. // // private: // // NOT IMPLEMENTED // my_StrPool(const my_StrPool&); // my_StrPool& operator=(const my_StrPool&); // // public: // // CREATORS // explicit // my_StrPool(bslma::Allocator *basicAllocator = 0); // // Create a string pool. Optionally specify a 'basicAllocator' // // used to supply memory. If 'basicAllocator' is 0, the currently // // installed default allocator is used. // // ~my_StrPool(); // // Destroy this object and release all associated memory. // // // MANIPULATORS // void *allocate(bsls::Types::size_type size); // // Return the address of a contiguous block of memory of the // // specified 'size' (in bytes). If 'size' is 0, no memory is // // allocated and 0 is returned. // // void release(); // // Release all memory currently allocated through this object. // }; // // // MANIPULATORS // inline // void my_StrPool::release() // { // d_blockList.release(); // d_block_p = 0; // } // // // ... // // // my_strpool.cpp // // enum { // k_INITIAL_SIZE = 128, // initial block size // // k_GROWTH_FACTOR = 2, // multiplicative factor by which to grow block // // k_THRESHOLD = 128 // size beyond which an individual block may be // // allocated if it doesn't fit in current block // }; // // // PRIVATE MANIPULATORS // void *my_StrPool::allocateBlock(bsls::Types::size_type numBytes) // { // assert(0 < numBytes); // // if (k_THRESHOLD < numBytes) { // // Allocate separate block if above threshold. // // return reinterpret_cast<char *>( // d_blockList.allocate(numBytes)); // RETURN // } // // if (d_block_p) { // // Do not increase block size if no current block. // // d_blockSize *= k_GROWTH_FACTOR; // } // d_block_p = reinterpret_cast<char*>(d_blockList.allocate(d_blockSize)); // d_cursor = numBytes; // // return d_block_p; // } // // // CREATORS // my_StrPool::my_StrPool(bslma::Allocator *basicAllocator) // : d_block_p(0) // , d_blockSize(k_INITIAL_SIZE) // , d_cursor(0) // , d_blockList(basicAllocator) // the blocklist knows about 'bslma_default' // { // } // // my_StrPool::~my_StrPool() // { // assert(k_INITIAL_SIZE <= d_blockSize); // assert(!d_block_p || (0 <= d_cursor && d_cursor <= // static_cast<bsls::Types::IntPtr>(d_blockSize))); // } // // // MANIPULATORS // void *my_StrPool::allocate(bsls::Types::size_type size) // { // if (0 == size) { // return 0; // RETURN // } // // if (d_block_p && size + d_cursor <= d_blockSize) { // char *p = d_block_p + d_cursor; // d_cursor += size; // return p; // RETURN // } // else { // return allocateBlock(size); // RETURN // } // } //.. // In the code shown above, the 'my_StrPool' memory manager allocates from its // 'bdlma::InfrequentDeleteBlockList' member object an initial memory block of // size 'k_INITIAL_SIZE'. This size is multiplied by 'k_GROWTH_FACTOR' each // time a depleted memory block is replaced by a newly-allocated block. The // 'allocate' method distributes memory from the current memory block // piecemeal, except when the requested size (1) is not available in the // current block, or (2) exceeds the 'k_THRESHOLD', in which case a separate // memory block is allocated and returned. When the 'my_StrPool' memory // manager is destroyed, its 'bdlma::InfrequentDeleteBlockList' member object // is also destroyed, which in turn automatically deallocates all of its // managed memory blocks. #include <bdlscm_version.h> #include <bslma_allocator.h> #include <bslma_default.h> #include <bsls_alignmentutil.h> #include <bsls_types.h> namespace BloombergLP { namespace bdlma { // =============================== // class InfrequentDeleteBlockList // =============================== class InfrequentDeleteBlockList { // This class implements a low-level memory manager that allocates and // manages a sequence of memory blocks -- each potentially of a different // size as specified during the invocation of the 'allocate' method. The // 'release' method deallocates the entire sequence of memory blocks, as // does the destructor. Note that memory blocks cannot be deallocated // individually. // PRIVATE TYPES struct Block { // This 'struct' overlays the beginning of each managed block of // allocated memory, implementing a singly-linked list of managed // blocks, and thereby enabling constant-time additions to the list of // blocks. Block *d_next_p; // next pointer bsls::AlignmentUtil::MaxAlignedType d_memory; // force alignment }; // DATA Block *d_head_p; // address of 1st block of memory (or 0) bslma::Allocator *d_allocator_p; // memory allocator (held, not owned) private: // NOT IMPLEMENTED InfrequentDeleteBlockList(const InfrequentDeleteBlockList&); InfrequentDeleteBlockList& operator=(const InfrequentDeleteBlockList&); public: // CREATORS explicit InfrequentDeleteBlockList(bslma::Allocator *basicAllocator = 0); // Create an empty block list suitable for managing memory blocks of // varying sizes. Optionally specify a 'basicAllocator' used to supply // memory. If 'basicAllocator' is 0, the currently installed default // allocator is used. ~InfrequentDeleteBlockList(); // Destroy this object and deallocate all outstanding memory blocks // managed by this object. // MANIPULATORS void *allocate(bsls::Types::size_type size); // Return the address of a contiguous block of memory of the specified // 'size' (in bytes). If 'size' is 0, no memory is allocated and 0 is // returned. The returned memory is guaranteed to be maximally // aligned. void deallocate(void *address); // This method has no effect on the memory block at the specified // 'address' as all memory allocated by this object is managed. The // behavior is undefined unless 'address' was allocated by this object, // and has not already been released. void release(); // Deallocate all memory blocks managed by this object, returning this // object to its default-constructed state. void releaseAllButLastBlock(); // Deallocate all except the most-recently obtained block of the memory // blocks managed by this object. If no blocks are managed, this // method has no effect. // ACCESSORS // Aspects bslma::Allocator *allocator() const; // Return the allocator used by this object to supply memory. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ------------------------------- // class InfrequentDeleteBlockList // ------------------------------- // CREATORS inline InfrequentDeleteBlockList::InfrequentDeleteBlockList( bslma::Allocator *basicAllocator) : d_head_p(0) , d_allocator_p(bslma::Default::allocator(basicAllocator)) { } // MANIPULATORS inline void InfrequentDeleteBlockList::deallocate(void *) { } // ACCESSORS // Aspects inline bslma::Allocator *InfrequentDeleteBlockList::allocator() const { return d_allocator_p; } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2020 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 ----------------------------------