Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdlma_bufferimputil
[Package bdlma]

Provide pure procedures for allocating memory from a buffer. More...

Namespaces

namespace  bdlma

Detailed Description

Outline
Purpose:
Provide pure procedures for allocating memory from a buffer.
Classes:
bdlma::BufferImpUtil pure procedures for allocating memory from a buffer
See also:
Component bdlma_buffermanager
Description:
This component provides a struct, bdlma::BufferImpUtil, that implements procedures for allocating memory from a buffer using an indicated memory alignment strategy. Each of the procedures take a buffer, the size of the buffer, a cursor pointing to the free memory within the buffer, and the allocation size. Two of the procedures, allocateFromBuffer and allocateFromBufferRaw, take an additional argument that specifies the memory alignment strategy to apply. The other six procedures apply a specific memory alignment strategy as indicated by their names (e.g., allocateNaturallyAlignedFromBuffer and allocateMaximallyAlignedFromBufferRaw). In all cases, a pointer to the allocated memory is returned, and the cursor passed in is updated to point to the portion of the buffer that contains the next available free memory.
For example, suppose we initially have a 2-byte aligned buffer having a size of 5 bytes, and a cursor pointing to the first byte:
                          0     1     2     3     4
                        _____ _____ _____ _____ _____
  buffer (size = 5):   |  F  |  F  |  F  |  F  |  F  |          A - allocated
                       `=====^=====^=====^=====^====='          F - free
                          ^                                     W - wasted
                          |
                        cursor
Using natural alignment, suppose 1 byte is allocated from the buffer using allocateFromBuffer:
  BufferImpUtil::allocateFromBuffer(&cursor, buffer, bufferSize, 1
                                    bsls::AlignmentStrategy::BSLS_NATURAL);
The cursor will be advanced as follows:
                          0     1     2     3     4
                        _____ _____ _____ _____ _____
  buffer (size = 5):   |  A  |  F  |  F  |  F  |  F  |          A - allocated
                       `=====^=====^=====^=====^====='          F - free
                                ^                               W - wasted
                                |
                              cursor
Suppose allocateFromBuffer is then used to allocate 2 bytes:
  BufferImpUtil::allocateFromBuffer(&cursor, buffer, bufferSize, 2,
                                    bsls::AlignmentStrategy::BSLS_NATURAL);
The cursor will be advanced as follows (after taking into consideration the alignment strategy used):
                          0     1     2     3     4
                        _____ _____ _____ _____ _____
  buffer (size = 5):   |  A  |  W  |  A  |  A  |  F  |          A - allocated
                       `=====^=====^=====^=====^====='          F - free
                                                  ^             W - wasted
                                                  |
                                                cursor
The byte at (only) position 1 is skipped because of the natural alignment strategy (otherwise, more bytes would have been skipped if maximum alignment was used). See bsls_alignment for more details about memory alignment.
Raw versus Non-Raw:
The raw and non-raw versions differ in behavior only when the requested memory size is larger than the memory available within the provided buffer (after taking memory alignment into consideration). The raw versions result in undefined behavior, while the non-raw versions return 0. Note that the safety of the non-raw versions comes at the extra cost of a conditional statement. For example, clients of the non-raw versions must check the return value to ensure successful allocation.
Usage:
This component is typically used by a class that manages a memory buffer. First, suppose we have a class that maintains a linked list of memory blocks, details of which are elided:
  class BlockList {
      // ...
  };
We can then create our memory manager using BlockList:
  class my_SequentialPool {
      // This class allocates memory from an internal pool of memory buffers
      // using natural alignment.  All allocated memory is managed internally
      // by the pool and released when the pool is destroyed.

      // DATA
      char                   *d_buffer_p;    // pointer to current buffer

      bsls::Types::size_type  d_bufferSize;  // size (in bytes) of the
                                             // current buffer

      bsls::Types::IntPtr     d_cursor;      // byte offset to unused memory
                                             // in buffer

      BlockList               d_blockList;   // used to replenish memory

    private:
      // PRIVATE MANIPULATORS
      void replenishBuffer(bsls::Types::size_type size);
          // Replenish the current buffer with memory that satisfies an
          // allocation request having at least the specified 'size' (in
          // bytes).

    public:
      // CREATORS
      explicit my_SequentialPool(bslma::Allocator *basicAllocator = 0);
          // Create a memory pool that dispenses heterogeneous blocks of
          // memory (of varying, user-specified sizes).  Optionally specify a
          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
          // 0, the currently installed default allocator is used.

      ~my_SequentialPool();
          // Destroy this memory pool and release all associated memory.

      // MANIPULATORS
      void *allocate(bsls::Types::size_type size);
          // Return the address of a contiguous block of naturally-aligned
          // memory of the specified 'size' (in bytes).  The behavior is
          // undefined unless '0 < size'.
  };
The implementations of the constructor and destructor are elided since allocate alone is sufficient to illustrate the use of bdlma::BufferImpUtil:
  void *my_SequentialPool::allocate(bsls::Types::size_type size)
  {
      assert(0 < size);

      void *address = bdlma::BufferImpUtil::allocateFromBuffer(
                                              &d_cursor,
                                              d_buffer_p,
                                              d_bufferSize,
                                              size,
                                              bsls::Alignment::BSLS_NATURAL);
Note that if there is insufficient space in d_buffer_p, allocateFromBuffer returns 0:
      if (address) {
          return address;                                           // RETURN
      }

      replenishBuffer(size);

      return bdlma::BufferImpUtil::allocateFromBufferRaw(
                                              &d_cursor,
                                              d_buffer_p,
                                              size,
                                              bsls::Alignment::BSLS_NATURAL);
  }
Note that the raw version is used because the contract of replenishBuffer guarantees that the buffer will have sufficient space to satisfy the allocation request of the specified size.