Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdlma_infrequentdeleteblocklist
[Package bdlma]

Provide allocation and management of infrequently deleted blocks. More...

Namespaces

namespace  bdlma

Detailed Description

Outline
Purpose:
Provide allocation and management of infrequently deleted blocks.
Classes:
bdlma::InfrequentDeleteBlockList manager of infrequently deleted blocks
See also:
Component 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.