Quick Links: |
Provide sequential memory using an external buffer and a fallback. More...
Namespaces | |
namespace | bdlma |
Functions | |
void * | operator new (bsl::size_t size, BloombergLP::bdlma::BufferedSequentialPool &pool) |
void | operator delete (void *address, BloombergLP::bdlma::BufferedSequentialPool &pool) |
bdlma::BufferedSequentialPool | pool using an external buffer and a fallback |
bdlma::BufferedSequentialPool
, that dispenses heterogeneous memory blocks (of varying, user-specified sizes) from an external buffer. If an allocation request exceeds the remaining free memory space in the external buffer, the pool will fall back to a sequence of dynamically allocated buffers. Users can optionally specify a growth strategy at construction that governs the growth rate of the dynamically-allocated buffers. If no growth strategy is specified at construction, geometric growth is used. Users can also optionally specify an alignment strategy at construction that governs the alignment of allocated memory blocks. If no alignment strategy is specified, natural alignment is used. The release
method releases all memory allocated through the pool, as does the destructor. The rewind
method releases all memory allocated through the pool and returns to the underlying allocator only memory that was allocated outside of the typical internal buffer growth of the pool (i.e., large blocks). Note that individually allocated memory blocks cannot be separately deallocated. bdlma::BufferedSequentialPool
is typically used when users have a reasonable estimation of the amount of memory needed. This amount of memory would typically be created directly on the program stack, and used as the initial external buffer of the pool for fast memory allocation. While the buffer has sufficient capacity, memory allocations using the pool will not trigger any dynamic memory allocation, will have optimal locality of reference, and will not require deallocation upon destruction. maxBufferSize
parameter can be supplied at construction to specify the maximum size (in bytes) of the dynamically-allocated buffers for geometric growth. Once the internal buffer grows up to the maxBufferSize
, further requests that exceed this size will be served by a separate memory block instead of the internal buffer. The behavior is undefined unless size <= maxBufferSize
, where size
is the extent (in bytes) of the external buffer supplied at construction. n
bytes of memory is supplied at construction, it does not mean that n
bytes of memory are available before dynamic memory allocation is triggered. This is due to memory alignment requirements. If the buffer supplied is not aligned, the first call to the allocate
method may automatically skip one or more bytes such that the memory allocated is properly aligned. The number of bytes that are wasted depends on whether natural alignment, maximum alignment, or 1-byte alignment is used (see bsls_alignment
for more details). my_BufferedIntDoubleArray
, that holds both int
and double
values. The class can be implemented using two parallel arrays: one storing the type information, and the other storing pointers to the int
and double
values. Furthermore, if we can approximate the amount of memory needed, we can use a bdlma::BufferedSequentialPool
for memory allocation for maximum efficiency: // my_bufferedintdoublearray.h class my_BufferedIntDoubleArray { // This class implements an efficient container for an array that // stores both 'int' and 'double' values. // DATA char *d_typeArray_p; // array indicating the type of corresponding // values stored in 'd_valueArray_p' void **d_valueArray_p; // array of pointers to the values stored int d_length; // number of values stored int d_capacity; // physical capacity of the type and value // arrays bdlma::BufferedSequentialPool d_pool; // buffered sequential memory pool used to // supply memory private: // NOT IMPLEMENTED my_BufferedIntDoubleArray(const my_BufferedIntDoubleArray&); private: // PRIVATE MANIPULATORS void increaseCapacity(); // Increase the capacity of the internal arrays used to store // elements added to this array by at least one element. public: // TYPES enum Type { k_MY_INT, k_MY_DOUBLE }; // CREATORS my_BufferedIntDoubleArray(char *buffer, int size, bslma::Allocator *basicAllocator = 0); // Create a fast 'int'-'double' array that initially allocates // memory sequentially from the specified 'buffer' having the // specified 'size' (in bytes). Optionally specify a // 'basicAllocator' used to supply memory if 'buffer' capacity is // exceeded. If 'basicAllocator' is 0, the currently installed // default allocator is used. ~my_BufferedIntDoubleArray(); // Destroy this array and all elements held by it. // ... // MANIPULATORS void appendInt(int value); // Append the specified 'int' 'value' to this array. void appendDouble(double value); // Append the specified 'double' 'value' to this array. void removeAll(); // Remove all elements from this array. // ... };
release
method allows the removeAll
method to quickly deallocate memory of all elements: // MANIPULATORS inline void my_BufferedIntDoubleArray::removeAll() { d_pool.release(); // *very* efficient if 'd_pool' has not exhausted // the buffer supplied at construction d_length = 0; }
// my_bufferedintdoublearray.cpp enum { k_INITIAL_SIZE = 1 }; // PRIVATE MANIPULATORS void my_BufferedIntDoubleArray::increaseCapacity() { // Implementation elided. // ... } // CREATORS my_BufferedIntDoubleArray::my_BufferedIntDoubleArray( char *buffer, int size, bslma::Allocator *basicAllocator) : d_length(0) , d_capacity(k_INITIAL_SIZE) , d_pool(buffer, size, basicAllocator) { d_typeArray_p = static_cast<char *>( d_pool.allocate(d_capacity * sizeof *d_typeArray_p)); d_valueArray_p = static_cast<void **>( d_pool.allocate(d_capacity * sizeof *d_valueArray_p)); }
d_pool
is destroyed: my_BufferedIntDoubleArray::~my_BufferedIntDoubleArray() { assert(0 <= d_length); assert(0 <= d_capacity); assert(d_length <= d_capacity); } // MANIPULATORS void my_BufferedIntDoubleArray::appendDouble(double value) { if (d_length >= d_capacity) { increaseCapacity(); } double *item = static_cast<double *>(d_pool.allocate(sizeof *item)); *item = value; d_typeArray_p[d_length] = static_cast<char>(k_MY_DOUBLE); d_valueArray_p[d_length] = item; ++d_length; } void my_BufferedIntDoubleArray::appendInt(int value) { if (d_length >= d_capacity) { increaseCapacity(); } int *item = static_cast<int *>(d_pool.allocate(sizeof *item)); *item = value; d_typeArray_p[d_length] = static_cast<char>(k_MY_INT); d_valueArray_p[d_length] = item; ++d_length; }
bslma::Allocator
is used throughout the interfaces of BDE components. Suppose we would like to create a fast allocator, my_FastAllocator
, that allocates memory from a buffer in a similar fashion to bdlma::BufferedSequentialPool
. bdlma::BufferedSequentialPool
can be used directly to implement such an allocator. bdlma_bufferedsequentialallocator
for full documentation of a similar class. class my_FastAllocator : public bslma::Allocator { // This class implements the 'bslma::Allocator' protocol to provide a // fast allocator of heterogeneous blocks of memory (of varying, // user-specified sizes) from an external buffer whose address and size // are supplied at construction. // DATA bdlma::BufferedSequentialPool d_pool; // memory manager for allocated // memory blocks // CREATORS my_FastAllocator(char *buffer, int size, bslma::Allocator *basicAllocator = 0); // Create an allocator for allocating memory blocks from the // specified external 'buffer' of the specified 'size' (in bytes). // Optionally specify a 'basicAllocator' used to supply memory // should the capacity of 'buffer' be exhausted. If // 'basicAllocator' is 0, the currently installed default allocator // is used. ~my_FastAllocator(); // Destroy this allocator. All memory allocated from this // allocator is released. // MANIPULATORS virtual void *allocate(size_type size); // Return the address of a contiguous block of memory of the // specified 'size' (in bytes). virtual void deallocate(void *address); // This method has no effect on the memory block at the specified // 'address' as all memory allocated by this allocator is managed. // The behavior is undefined unless 'address' was allocated by this // allocator, and has not already been deallocated. }; // CREATORS inline my_FastAllocator::my_FastAllocator(char *buffer, int size, bslma::Allocator *basicAllocator) : d_pool(buffer, size, basicAllocator) { } inline my_FastAllocator::~my_FastAllocator() { d_pool.release(); } // MANIPULATORS inline void *my_FastAllocator::allocate(size_type size) { return d_pool.allocate(size); } inline void my_FastAllocator::deallocate(void *) { }
void* operator new | ( | bsl::size_t | size, | |
BloombergLP::bdlma::BufferedSequentialPool & | pool | |||
) |
Return a block of memory of the specified size
(in bytes) allocated from the specified pool
. Note that an object may allocate additional memory internally, requiring the allocator to be passed in as a constructor argument:
my_Type *newMyType(bdlma::BufferedSequentialPool *pool, bslma::Allocator *basicAllocator) { return new (*pool) my_Type(..., basicAllocator); }
Also note that the analogous version of operator delete
should not be called directly. Instead, this component provides a static template member function, deleteObject
, parameterized by TYPE
that performs the following:
void deleteMyType(bdlma::BufferedSequentialPool *pool, my_Type *t) { t->~my_Type(); }
void operator delete | ( | void * | address, | |
BloombergLP::bdlma::BufferedSequentialPool & | pool | |||
) |
Use the specified pool
to deallocate the memory at the specified address
. The behavior is undefined unless address
was allocated using pool
and has not already been deallocated. This operator is supplied solely to allow the compiler to arrange for it to be called in case of an exception.