Quick Links:

bal | bbl | bdl | bsl

Namespaces | Functions

Component bdlma_sequentialpool
[Package bdlma]

Provide sequential memory using dynamically-allocated buffers. More...

Namespaces

namespace  bdlma

Functions

void * operator new (bsl::size_t size, BloombergLP::bdlma::SequentialPool &pool)
void operator delete (void *address, BloombergLP::bdlma::SequentialPool &pool)

Detailed Description

Outline
Purpose:
Provide sequential memory using dynamically-allocated buffers.
Classes:
bdlma::SequentialPool memory pool using dynamically-allocated buffers
See also:
Component bdlma_infrequentdeleteblocklist, Component bdlma_sequentialallocator
Description:
This component provides a fast sequential memory pool, bdlma::SequentialPool, that dispenses heterogeneous memory blocks (of varying, user-specified sizes) from a dynamically-allocated internal buffer. If an allocation request exceeds the remaining free memory space in the internal buffer, the pool either replenishes its buffer with new memory to satisfy the request, or returns a separate memory block, depending on whether the request size exceeds an optionally-specified maximum buffer size. 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.
A bdlma::SequentialPool is typically used when fast allocation and deallocation is needed, but the user does not know in advance the maximum amount of memory needed.
Optional initialSize Parameter:
An optional initialSize parameter can be supplied at construction to specify the initial size of the internal buffer. If initialSize is not supplied, an implementation-defined value is used for the initial internal size of the buffer.
Optional maxBufferSize Parameter:
If initialSize is specified, an optional maxBufferSize parameter can be supplied at construction to specify the maximum buffer size 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 maxBufferSize >= initialSize. Note that reserveCapacity always ensures that the requested number of bytes is available (allocating a new internal buffer if necessary) regardless of whether the size of the request exceeds maxBufferSize.
Optional growthStrategy Parameter:
An optional growthStrategy parameter can be supplied at construction to specify the growth rate of the dynamically-allocated buffers. The buffers can grow either geometrically or remain constant in size. If growthStrategy is not specified, geometric growth is used. See bsls_blockgrowth for more details.
Optional alignmentStrategy Parameter:
An optional alignmentStrategy parameter can be supplied at construction to specify the memory alignment strategy. Allocated memory blocks can either follow maximum alignment, natural alignment, or 1-byte alignment. If alignmentStrategy is not specified, natural alignment is used. See bsls_alignment for more details.
Usage:
This section illustrates intended use of this component.
Example 1: Using bdlma::SequentialPool for Efficient Allocations:
Suppose we define a container class, my_IntDoubleArray, 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. For efficient memory allocation, we can use a bdlma::SequentialPool for memory allocation:
  // my_intdoublearray.h

  class my_IntDoubleArray {
      // 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::SequentialPool
             d_pool;          // sequential memory pool used to supply memory

    private:
      // PRIVATE MANIPULATORS
      void increaseSize();
          // Increase the capacity of the internal arrays used to store
          // elements added to this array by at least one element.

      // Not implemented:
      my_IntDoubleArray(const my_IntDoubleArray&);

    public:
      // TYPES
      enum Type { k_MY_INT, k_MY_DOUBLE };

      // CREATORS
      explicit my_IntDoubleArray(bslma::Allocator *basicAllocator = 0);
          // Create an 'int'-'double' array.  Optionally specify a
          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
          // 0, the currently installed default allocator is used.

      ~my_IntDoubleArray();
          // 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.

      // ...
  };
The use of a sequential pool and the release method allows the removeAll method to quickly deallocate memory of all elements:
  // MANIPULATORS
  inline
  void my_IntDoubleArray::removeAll()
  {
      d_pool.release();
      d_length = 0;
  }
The sequential pool optimizes the allocation of memory by using dynamically-allocated buffers to supply memory. This greatly reduces the amount of dynamic allocation needed:
  // my_intdoublearray.cpp

  enum { k_INITIAL_SIZE = 1 };

  // PRIVATE MANIPULATORS
  void my_IntDoubleArray::increaseSize()
  {
      // Implementation elided.
      // ...
  }

  // CREATORS
  my_IntDoubleArray::my_IntDoubleArray(bslma::Allocator *basicAllocator)
  : d_length(0)
  , d_capacity(k_INITIAL_SIZE)
  , d_pool(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));
  }
Note that in the destructor, all outstanding memory blocks are deallocated automatically when d_pool is destroyed:
  my_IntDoubleArray::~my_IntDoubleArray()
  {
      assert(0 <= d_length);
      assert(0 <= d_capacity);
      assert(d_length <= d_capacity);
  }

  // MANIPULATORS
  void my_IntDoubleArray::appendInt(int value)
  {
      if (d_length >= d_capacity) {
          increaseSize();
      }

      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;
  }

  void my_IntDoubleArray::appendDouble(double value)
  {
      if (d_length >= d_capacity) {
          increaseSize();
      }

      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;
  }
Example 2: Implementing an Allocator Using bdlma::SequentialPool:
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::SequentialPool. bdlma::SequentialPool can be used directly to implement such an allocator.
Note that the documentation for this class is simplified for this usage example. Please see bdlma_sequentialallocator for full documentation of a similar class.
  class my_SequentialAllocator : 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 dynamically-allocated internal buffers.

      // DATA
      bdlma::SequentialPool d_pool;  // memory manager for allocated memory
                                     // blocks

    public:
      // CREATORS
      explicit my_SequentialAllocator(bslma::Allocator *basicAllocator = 0);
          // Create an allocator for allocating memory blocks from
          // dynamically-allocated internal buffers.  Optionally specify a
          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
          // 0, the currently installed default allocator is used.

      ~my_SequentialAllocator();
          // 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_SequentialAllocator::my_SequentialAllocator(
                                            bslma::Allocator *basicAllocator)
  : d_pool(basicAllocator)
  {
  }

  inline
  my_SequentialAllocator::~my_SequentialAllocator()
  {
      d_pool.release();
  }

  // MANIPULATORS
  inline
  void *my_SequentialAllocator::allocate(size_type size)
  {
      return d_pool.allocate(size);
  }

  inline
  void my_SequentialAllocator::deallocate(void *)
  {
  }

Function Documentation

void* operator new ( bsl::size_t  size,
BloombergLP::bdlma::SequentialPool &  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::SequentialPool *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::SequentialPool *pool, my_Type *t)
      {
          t->~my_Type();
      }
void operator delete ( void *  address,
BloombergLP::bdlma::SequentialPool &  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.