BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlma_bufferimputil

Detailed Description

Outline

Purpose

Provide pure procedures for allocating memory from a buffer.

Classes

See also
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'.
};
Definition bslma_allocator.h:457
std::size_t size_type
Definition bsls_types.h:124
std::ptrdiff_t IntPtr
Definition bsls_types.h:130

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);
&d_cursor,
d_buffer_p,
d_bufferSize,
size,
static void * allocateFromBuffer(bsls::Types::IntPtr *cursor, char *buffer, bsls::Types::size_type bufferSize, bsls::Types::size_type size, bsls::Alignment::Strategy strategy)
@ BSLS_NATURAL
Definition bsls_alignment.h:246

Note that if there is insufficient space in d_buffer_p, allocateFromBuffer returns 0:

if (address) {
return address; // RETURN
}
replenishBuffer(size);
&d_cursor,
d_buffer_p,
size,
}
static void * allocateFromBufferRaw(bsls::Types::IntPtr *cursor, char *buffer, bsls::Types::size_type size, bsls::Alignment::Strategy strategy)

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.