// bdlma_bufferimputil.h -*-C++-*- #ifndef INCLUDED_BDLMA_BUFFERIMPUTIL #define INCLUDED_BDLMA_BUFFERIMPUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide pure procedures for allocating memory from a buffer. // //@CLASSES: // bdlma::BufferImpUtil: pure procedures for allocating memory from a buffer // //@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'. // }; //.. // 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'. #include <bdlscm_version.h> #include <bsls_alignment.h> #include <bsls_types.h> namespace BloombergLP { namespace bdlma { // ==================== // struct BufferImpUtil // ==================== struct BufferImpUtil { // This 'struct' provides a namespace for a suite of pure procedures for // allocating memory from a buffer. // CLASS METHODS static void *allocateFromBuffer(bsls::Types::IntPtr *cursor, char *buffer, bsls::Types::size_type bufferSize, bsls::Types::size_type size, bsls::Alignment::Strategy strategy); // Allocate a memory block of the specified 'size' (in bytes) from the // specified 'buffer' having the specified 'bufferSize' (in bytes) at // the specified 'cursor' position, using the specified alignment // 'strategy'. Return the address of the allocated memory block if // 'buffer' contains sufficient available memory, and 0 otherwise. The // 'cursor' is set to the first byte position immediately after the // allocated memory if there is sufficient memory, and not modified // otherwise. The behavior is undefined unless '0 < size', // '0 <= *cursor', and '*cursor <= bufferSize'. static void *allocateMaximallyAlignedFromBuffer( bsls::Types::IntPtr *cursor, char *buffer, bsls::Types::size_type bufferSize, bsls::Types::size_type size); // Allocate a maximally-aligned memory block of the specified 'size' // (in bytes) from the specified 'buffer' having the specified // 'bufferSize' (in bytes) at the specified 'cursor' position. Return // the address of the allocated memory block if 'buffer' contains // sufficient available memory, and 0 otherwise. The 'cursor' is set // to the first byte position immediately after the allocated memory if // there is sufficient memory, and not modified otherwise. The // behavior is undefined unless '0 < size', '0 <= *cursor', and // '*cursor <= bufferSize'. static void *allocateNaturallyAlignedFromBuffer( bsls::Types::IntPtr *cursor, char *buffer, bsls::Types::size_type bufferSize, bsls::Types::size_type size); // Allocate a naturally-aligned memory block of the specified 'size' // (in bytes) from the specified 'buffer' having the specified // 'bufferSize' (in bytes) at the specified 'cursor' position. Return // the address of the allocated memory block if 'buffer' contains // sufficient available memory, and 0 otherwise. The 'cursor' is set // to the first byte position immediately after the allocated memory if // there is sufficient memory, and not modified otherwise. The // behavior is undefined unless '0 < size', '0 <= *cursor', and // '*cursor <= bufferSize'. static void *allocateOneByteAlignedFromBuffer( bsls::Types::IntPtr *cursor, char *buffer, bsls::Types::size_type bufferSize, bsls::Types::size_type size); // Allocate a 1-byte-aligned memory block of the specified 'size' (in // bytes) from the specified 'buffer' having the specified 'bufferSize' // (in bytes) at the specified 'cursor' position. Return the address // of the allocated memory block if 'buffer' contains sufficient // available memory, and 0 otherwise. The 'cursor' is set to the first // byte position immediately after the allocated memory if there is // sufficient memory, and not modified otherwise. The behavior is // undefined unless '0 < size', '0 <= *cursor', and // '*cursor <= bufferSize'. static void *allocateFromBufferRaw(bsls::Types::IntPtr *cursor, char *buffer, bsls::Types::size_type size, bsls::Alignment::Strategy strategy); // Allocate a memory block of the specified 'size' (in bytes) from the // specified 'buffer' at the specified 'cursor' position, using the // specified alignment 'strategy'. Return the address of the allocated // memory block. The 'cursor' is set to the first byte position // immediately after the allocated memory. The behavior is undefined // unless '0 < size', 'buffer' contains sufficient available memory, // and 'cursor' refers to a valid position in 'buffer'. static void *allocateMaximallyAlignedFromBufferRaw( bsls::Types::IntPtr *cursor, char *buffer, bsls::Types::size_type size); // Allocate a maximally-aligned memory block of the specified 'size' // (in bytes) from the specified 'buffer' at the specified 'cursor' // position. Return the address of the allocated memory block. The // 'cursor' is set to the first byte position immediately after the // allocated memory. The behavior is undefined unless '0 < size', // 'buffer' contains sufficient available memory, and 'cursor' refers // to a valid position in 'buffer'. static void *allocateNaturallyAlignedFromBufferRaw( bsls::Types::IntPtr *cursor, char *buffer, bsls::Types::size_type size); // Allocate a naturally-aligned memory block of the specified 'size' // (in bytes) from the specified 'buffer' at the specified 'cursor' // position. Return the address of the allocated memory block. The // 'cursor' is set to the first byte position immediately after the // allocated memory. The behavior is undefined unless '0 < size', // 'buffer' contains sufficient available memory, and 'cursor' refers // to a valid position in 'buffer'. static void *allocateOneByteAlignedFromBufferRaw( bsls::Types::IntPtr *cursor, char *buffer, bsls::Types::size_type size); // Allocate a 1-byte-aligned memory block of the specified 'size' (in // bytes) from the specified 'buffer' at the specified 'cursor' // position. Return the address of the allocated memory block. The // 'cursor' is set to the first byte position immediately after the // allocated memory. The behavior is undefined unless '0 < size', // 'buffer' contains sufficient available memory, and 'cursor' refers // to a valid position in 'buffer'. }; } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2016 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------