Skip to main content
Pigweed's logo Pigweed
code_xml
  1. Home
  2. Reference
  3. C/C++
  4. pw_allocator
  5. Forwarding allocators
  6. pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler > Class Template Reference
Loading...
Searching...
No Matches
pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler > Class Template Reference

Overview

template<typename Prefix, typename Suffix = void, typename ErrorHandler = internal::DefaultFrameErrorHandler>
class pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >

An allocator that can "frame" its allocation with a leading prefix type, a trailing suffix type, or both.

At least one of Prefix and Suffix must be a type other than void, since in that case there is no need for a frame.

In addition to the template parameter types, each allocation will include up to three additional size_t fields.

  • The offset of the suffix field from the data, i.e. from the allocated pointer. This field is omitted if the suffix type is void. When present, this field is located just before the usable memory.
  • The offset of the data from the start of the frame. This field is located just after the prefix, if the prefix type is not void, or at the start of the frame.
  • The offset of the frame from the start of the data. This has the same value as the frame offset, but can be located using only the data pointer. This field is located just before the suffix offset, if the suffix type is not void, or just before the usable memory.

The frame offset and data offset locations may match, i.e. the field just after the prefix is right before the suffix offset or usable memory. In this case, only one offset is stored as both the frame and data offset.

Thus assuming sizeof(size_t) == 4, requesting a 64-byte allocation with a 16-byte alignment from a FramingAllocator<uint32_t, uint16_t> might result in an allocation that looks like:

Address Type Contents Pointed at by:
+---------+-------------+--------------------+--------------------------+
| 0x...00 | Prefix | user-defined | frame |
| | (uint32_t) | | GetFrame(data) |
| | | | GetPrefix(data) |
+---------+-------------+--------------------+--------------------------+
| 0x...04 | size_t | frame_offset =0x10 | GetFrameOffsetPtr(frame) |
+---------+-------------+--------------------+--------------------------+
| 0x...08 | size_t | data_offset =0x10 | GetDataOffsetPtr(data) |
+---------+-------------+--------------------+--------------------------+
| 0x...0C | size_t | suffix_offset=0x40 | GetSuffixOffsetPtr(data) |
+---------+-------------+--------------------+--------------------------+
| 0x...10 | std::byte[] | usable space | data |
| | | | GetData(frame) |
+---------+-------------+--------------------+--------------------------+
| 0x...50 | Suffix | user-defined | GetSuffix(data) |
| | (uint16_t) | | |
+---------+-------------+--------------------+--------------------------+
void * GetFrame(void *data) const
Definition: framing_allocator.h:820
Suffix * GetSuffix(void *data) const
Definition: framing_allocator.h:847
void * GetData(void *frame) const
Definition: framing_allocator.h:834
Prefix * GetPrefix(void *data) const
Definition: framing_allocator.h:840

Alternatively, if the selected memory for the same allocation happens to start at 0x...04, the prefix offsets will be combined:

Address Type Contents Pointed at by:
+---------+-------------+--------------------+--------------------------+
| 0x...04 | Prefix | user-defined | frame |
| | (uint32_t) | | GetFrame(data) |
| | | | GetPrefix(data) |
+---------+-------------+--------------------+--------------------------+
| 0x...08 | size_t | frame_offset, | GetFrameOffsetPtr(frame) |
| | | data_offset =0x0C | GetDataOffsetPtr(data) |
+---------+-------------+--------------------+--------------------------+
| 0x...0C | size_t | suffix_offset=0x40 | GetSuffixOffsetPtr(data) |
+---------+-------------+--------------------+--------------------------+
| 0x...10 | std::byte[] | usable space | data |
| | | | GetData(frame) |
+---------+-------------+--------------------+--------------------------+
| 0x...50 | Suffix | user-defined | GetSuffix(data) |
| | (uint16_t) | | |
+---------+-------------+--------------------+--------------------------+

Let's drop the suffix for simplicity. If we make a similar allocation from a FramingAllocator<uint32_t, void> that happens to start at 0x...0C, we get the worst case scenario for padding to maintain alignment:

Address Type Contents Pointed at by:
+---------+-------------+--------------------+--------------------------+
| 0x...0C | Prefix | user-defined | frame |
| | (uint32_t) | | GetFrame(data) |
| | | | GetPrefix(data) |
+---------+-------------+--------------------+--------------------------+
| 0x...10 | size_t | frame_offset =0x14 | GetFrameOffsetPtr(frame) |
+---------+-------------+--------------------+--------------------------+
| 0x...14 | N/A | 8 bytes of padding | N/A |
+---------+-------------+--------------------+--------------------------+
| 0x...1C | size_t | data_offset =0x14 | GetDataOffsetPtr(data) |
+---------+-------------+--------------------+--------------------------+
| 0x...20 | std::byte[] | usable space | data |
| | | | GetData(frame) |
+---------+-------------+--------------------+--------------------------+

Finally, requesting a 64-byte allocation with a 16-byte alignment from a suffix-only FramingAllocator<void, uint16_t> might result in an allocation that looks like:

Address Type Contents Pointed at by:
+---------+-------------+--------------------+--------------------------+
| 0x...00 | size_t | frame_offset =0x10 | frame |
| | | | GetFrame(data) |
| | | | GetFrameOffsetPtr(frame) |
+---------+-------------+--------------------+--------------------------+
| 0x...04 | N/A | 4 bytes of padding | N/A |
+---------+-------------+--------------------+--------------------------+
| 0x...08 | size_t | data_offset =0x10 | GetDataOffsetPtr(data) |
+---------+-------------+--------------------+--------------------------+
| 0x...0C | size_t | suffix_offset=0x40 | GetSuffixOffsetPtr(data) |
+---------+-------------+--------------------+--------------------------+
| 0x...10 | std::byte[] | usable space | data |
| | | | GetData(frame) |
+---------+-------------+--------------------+--------------------------+
| 0x...50 | Suffix | user-defined | GetSuffix(data) |
| | (uint16_t) | | |
+---------+-------------+--------------------+--------------------------+
Note
As illustrated above, the choice of prefix and suffix types and overall alignment can significantly affect the amount of overhead required. When possible, keep alignment requirements low. Ideally, Suffix and the allocated data both have an alignment of alignof(size_t) or less.
Template Parameters
PrefixA default constructible and trivially copyable type to place before each allocation, or void. alignof(Prefix) must be at most alignof(size_t).
SuffixA default constructible and trivially copyable type to place after each allocation, or void.
ErrorHandlerUsed to report frame validation errors.
Inheritance diagram for pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >:
pw::allocator::internal::BaseFramingAllocator< ErrorHandler > pw::allocator::ForwardingAllocator pw::Allocator pw::Deallocator pw::allocator::internal::BasicGuardedAllocator< internal::DefaultGuardErrorHandler >

Protected Types

using Base = internal::BaseFramingAllocator< ErrorHandler >
 
- Protected Types inherited from pw::Deallocator
enum class  InfoType {
  kRequestedLayoutOf , kUsableLayoutOf , kAllocatedLayoutOf , kCapacity ,
  kRecognizes
}
 

Protected Member Functions

constexpr FramingAllocator (pw::Allocator &allocator)
 
void * DoAllocate (Layout layout) override
 
void DoDeallocate (void *ptr) override
 
bool DoResize (void *ptr, size_t new_size) override
 
bool DoBeforeReallocate (void *ptr, Layout new_layout) override
 
void DoAfterReallocateCopy (void *ptr, Layout new_layout, void *new_ptr) override
 
Result< Layout > DoGetInfo (Deallocator::InfoType info_type, const void *ptr) const override
 
void * GetFrame (void *data) const
 
const void * GetFrame (const void *data) const
 
Prefix * GetPrefix (void *data) const
 
const Prefix * GetPrefix (const void *data) const
 
void * GetData (void *frame) const
 
const void * GetData (const void *data) const
 
Suffix * GetSuffix (void *data) const
 
const Suffix * GetSuffix (const void *data) const
 
- Protected Member Functions inherited from pw::allocator::internal::BaseFramingAllocator< ErrorHandler >
constexpr BaseFramingAllocator (Allocator &allocator)
 
ByteSpan AllocateFrame (Layout prefix, Layout data, Layout suffix)
 
bool ResizeFrame (void *data, size_t new_size, Layout suffix, void *tmp_suffix)
 
Result< Layout > GetFrameInfo (InfoType info_type, const void *data, Layout suffix) const
 
Result< size_t > GetFrameSize (const void *frame) const
 
- Protected Member Functions inherited from pw::allocator::ForwardingAllocator
constexpr ForwardingAllocator (const Capabilities &capabilities) noexcept
 
constexpr ForwardingAllocator (pw::Allocator &allocator) noexcept
 
constexpr void Init (pw::Allocator &allocator)
 
constexpr pw::Allocator & allocator ()
 
constexpr const pw::Allocator & allocator () const
 
void * DoAllocate (Layout layout) override
 
void DoDeallocate (void *ptr) override
 
bool DoResize (void *ptr, size_t new_size) override
 
bool DoBeforeReallocate (void *ptr, Layout new_layout) override
 
void DoAfterReallocateCopy (void *ptr, Layout new_layout, void *new_ptr) override
 
void DoAfterReallocateDone (Layout new_layout, void *new_ptr) override
 
size_t DoGetAllocated () const override
 
std::optional< Fragmentation > DoMeasureFragmentation () const override
 Returns fragmentation information for the allocator's memory region.
 
Result< Layout > DoGetInfo (InfoType info_type, const void *ptr) const override
 
- Protected Member Functions inherited from pw::Allocator
constexpr Allocator () noexcept=default
 TODO(b/326509341): Remove when downstream consumers migrate.
 
constexpr Allocator (const Capabilities &capabilities) noexcept
 
virtual void * DoAllocate (Layout layout)=0
 
virtual bool DoResize (void *ptr, size_t new_size)
 
virtual void * DoReallocate (void *ptr, Layout new_layout)
 
virtual bool DoBeforeReallocate (void *ptr, Layout new_layout)
 
virtual void DoAfterReallocateCopy (void *ptr, Layout new_layout, void *new_ptr)
 
virtual void DoAfterReallocateDone (Layout new_layout, void *new_ptr)
 
virtual size_t DoGetAllocated () const
 
virtual std::optional< Fragmentation > DoMeasureFragmentation () const
 Returns fragmentation information for the allocator's memory region.
 
- Protected Member Functions inherited from pw::Deallocator
constexpr Deallocator ()=default
 TODO(b/326509341): Remove when downstream consumers migrate.
 
constexpr Deallocator (const Capabilities &capabilities)
 
Result< Layout > GetInfo (InfoType info_type, const void *ptr) const
 
Result< Layout > GetRequestedLayout (const void *ptr) const
 
Result< Layout > GetUsableLayout (const void *ptr) const
 
Result< Layout > GetAllocatedLayout (const void *ptr) const
 
bool Recognizes (const void *ptr) const
 
virtual void DoDeallocate (void *ptr)=0
 
virtual Result< Layout > DoGetInfo (InfoType, const void *) const
 

Additional Inherited Members

- Public Types inherited from pw::Allocator
using Fragmentation = allocator::Fragmentation
 
- Public Types inherited from pw::Deallocator
using Capabilities = allocator::Capabilities
 
using Capability = allocator::Capability
 
using Layout = allocator::Layout
 
- Public Member Functions inherited from pw::Allocator
void * Allocate (Layout layout)
 
template<typename T , int &... kExplicitGuard, std::enable_if_t<!std::is_array_v< T >, int > = 0, typename... Args>
T * New (Args &&... args)
 
template<typename T , int &... kExplicitGuard, typename ElementType = std::remove_extent_t<T>, std::enable_if_t< is_bounded_array_v< T >, int > = 0>
ElementType * New ()
 
template<typename T , int &... kExplicitGuard, typename ElementType = std::remove_extent_t<T>, std::enable_if_t< is_unbounded_array_v< T >, int > = 0>
ElementType * New (size_t count)
 
template<typename T , int &... kExplicitGuard, typename ElementType = std::remove_extent_t<T>, std::enable_if_t< is_unbounded_array_v< T >, int > = 0>
ElementType * New (size_t count, size_t alignment)
 Constructs an alignment-byte aligned array of count objects.
 
template<typename T , int &... kExplicitGuard, std::enable_if_t<!std::is_array_v< T >, int > = 0, typename... Args>
UniquePtr< T > MakeUnique (Args &&... args)
 
template<typename T , std::enable_if_t< is_unbounded_array_v< T >, int > = 0>
UniquePtr< T > MakeUnique (size_t size)
 
template<typename T , std::enable_if_t< is_unbounded_array_v< T >, int > = 0>
UniquePtr< T > MakeUnique (size_t size, size_t alignment)
 
template<typename T , std::enable_if_t< is_bounded_array_v< T >, int > = 0>
UniquePtr< T > MakeUnique ()
 
template<typename T , int &... kExplicitGuard, std::enable_if_t<!std::is_array_v< T >, int > = 0, typename... Args>
SharedPtr< T > MakeShared (Args &&... args)
 
template<typename T , std::enable_if_t< is_unbounded_array_v< T >, int > = 0>
SharedPtr< T > MakeShared (size_t size)
 
template<typename T , std::enable_if_t< is_unbounded_array_v< T >, int > = 0>
SharedPtr< T > MakeShared (size_t size, size_t alignment)
 
template<typename T , std::enable_if_t< is_bounded_array_v< T >, int > = 0>
SharedPtr< T > MakeShared ()
 
bool Resize (void *ptr, size_t new_size)
 
void * Reallocate (void *ptr, Layout new_layout)
 
size_t GetAllocated () const
 
std::optional< Fragmentation > MeasureFragmentation () const
 Returns fragmentation information for the allocator's memory region.
 
- Public Member Functions inherited from pw::Deallocator
constexpr const Capabilities & capabilities () const
 
constexpr bool HasCapability (Capability capability) const
 Returns whether a given capability is enabled for this object.
 
void Deallocate (void *ptr)
 
template<typename ElementType >
void DeleteArray (ElementType *ptr, size_t count)
 
template<typename ElementType >
void Destroy (ElementType *ptr, size_t count)
 
StatusWithSize GetCapacity () const
 
bool IsEqual (const Deallocator &other) const
 
template<typename T , int &... kExplicitGuard, std::enable_if_t<!std::is_array_v< T >, int > = 0>
void Delete (T *ptr)
 
template<typename T , int &... kExplicitGuard, typename ElementType = std::remove_extent_t<T>, std::enable_if_t< is_bounded_array_v< T >, int > = 0>
void Delete (ElementType *ptr)
 
template<typename T , int &... kExplicitGuard, typename ElementType = std::remove_extent_t<T>, std::enable_if_t< is_unbounded_array_v< T >, int > = 0>
void Delete (ElementType *ptr, size_t count)
 
- Static Protected Member Functions inherited from pw::allocator::internal::BaseFramingAllocator< ErrorHandler >
static constexpr size_t Distance (const void *start, const void *end)
 Returns the distance between two pointers in bytes.
 
static void UpdateOffsets (void *frame, void *data, void *suffix)
 
static void * GetFrame (void *data, bool has_suffix, bool checked=true)
 
static const void * GetFrame (const void *data, bool has_suffix, bool checked=true)
 
static void * GetData (void *frame, Result< size_t > frame_size, Layout prefix)
 
static const void * GetData (const void *frame, Result< size_t > frame_size, Layout prefix)
 
static void * GetSuffix (void *data, size_t data_size, Layout suffix)
 
static const void * GetSuffix (const void *data, size_t data_size, Layout suffix)
 
- Static Protected Member Functions inherited from pw::Allocator
static bool BeforeReallocate (Allocator &allocator, void *ptr, Layout new_layout)
 
static void AfterReallocateCopy (Allocator &allocator, void *ptr, Layout new_layout, void *new_ptr)
 
static void AfterReallocateDone (Allocator &allocator, Layout new_layout, void *new_ptr)
 
- Static Protected Member Functions inherited from pw::Deallocator
static Result< Layout > GetInfo (const Deallocator &deallocator, InfoType info_type, const void *ptr)
 
static Result< Layout > GetRequestedLayout (const Deallocator &deallocator, const void *ptr)
 
static Result< Layout > GetUsableLayout (const Deallocator &deallocator, const void *ptr)
 
static Result< Layout > GetAllocatedLayout (const Deallocator &deallocator, const void *ptr)
 
static bool Recognizes (const Deallocator &deallocator, const void *ptr)
 
- Static Protected Attributes inherited from pw::Deallocator
template<typename T >
static constexpr bool is_bounded_array_v = ::pw::is_bounded_array_v<T>
 
template<typename T >
static constexpr bool is_unbounded_array_v = ::pw::is_unbounded_array_v<T>
 

Member Function Documentation

◆ DoAfterReallocateCopy()

template<typename Prefix , typename Suffix , typename ErrorHandler >
void pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >::DoAfterReallocateCopy ( void *  ptr,
Layout  new_layout,
void *  new_ptr 
)
overrideprotectedvirtual

Called as part of the default implementation of DoReallocate once the data from ptr has been resized or copied to new_ptr.

By default, does nothing. Derived types may implement this method to add additional behavior. If they do, they must call DoAfterReallocateCopy on their base type before performing any other action.

ptr and new_ptr are guaranteed to be non-null, and new_layout.size() is guaranteed to be non-zero.

Reimplemented from pw::allocator::ForwardingAllocator.

Reimplemented in pw::allocator::internal::BasicGuardedAllocator< internal::DefaultGuardErrorHandler >.

◆ DoAllocate()

template<typename Prefix , typename Suffix , typename ErrorHandler >
void * pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >::DoAllocate ( Layout  layout)
overrideprotectedvirtual

Allocates a block of memory with the specified size and alignment.

Returns nullptr if the allocation cannot be made, or the layout has a size of 0.

Parameters
[in]layoutDescribes the memory to be allocated.

Reimplemented from pw::allocator::ForwardingAllocator.

Reimplemented in pw::allocator::internal::BasicGuardedAllocator< internal::DefaultGuardErrorHandler >.

◆ DoBeforeReallocate()

template<typename Prefix , typename Suffix , typename ErrorHandler >
bool pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >::DoBeforeReallocate ( void *  ptr,
Layout  new_layout 
)
overrideprotectedvirtual

Called at the start of the default implementation of DoReallocate.

By default, returns true. Derived types may implement this method to add additional behavior. If they do, they must return false or the value returned by DoBeforeReallocate. If false is returned, the reallocation fails and returns null.

ptr is guaranteed to be non-null, and new_layout.size() is guaranteed to be non-zero.

Reimplemented from pw::allocator::ForwardingAllocator.

Reimplemented in pw::allocator::internal::BasicGuardedAllocator< internal::DefaultGuardErrorHandler >.

◆ DoDeallocate()

template<typename Prefix , typename Suffix , typename ErrorHandler >
void pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >::DoDeallocate ( void *  ptr)
overrideprotectedvirtual

Releases a previously-allocated block of memory.

The given pointer must have been previously provided by this memory resource; otherwise the behavior is undefined.

Parameters
[in]ptrPointer to previously-allocated memory.

Reimplemented from pw::allocator::ForwardingAllocator.

Reimplemented in pw::allocator::internal::BasicGuardedAllocator< internal::DefaultGuardErrorHandler >.

◆ DoGetInfo()

template<typename Prefix , typename Suffix = void, typename ErrorHandler = internal::DefaultFrameErrorHandler>
Result< Layout > pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >::DoGetInfo ( Deallocator::InfoType  info_type,
const void *  ptr 
) const
inlineoverrideprotectedvirtual

Returns deallocator-specific information about allocations.

Deallocators may support any number of InfoTypes. See that type for what each supported type returns. For unsupported types, this method returns UNIMPLEMENTED.

Reimplemented from pw::allocator::ForwardingAllocator.

◆ DoResize()

template<typename Prefix , typename Suffix , typename ErrorHandler >
bool pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >::DoResize ( void *  ptr,
size_t  new_size 
)
overrideprotectedvirtual

Modifies the size of an previously-allocated block of memory without copying any data.

Returns true if its size was changed without copying data to a new allocation; otherwise returns false.

In particular, it always returns true if the old_layout.size() equals new_size, and always returns false if the given pointer is null, the old_layout.size() is 0, or the new_size is 0.

Parameters
[in]ptrPointer to previously-allocated memory.
[in]new_sizeRequested new size for the memory allocation.

Reimplemented from pw::allocator::ForwardingAllocator.

Reimplemented in pw::allocator::internal::BasicGuardedAllocator< internal::DefaultGuardErrorHandler >.

◆ GetData()

template<typename Prefix , typename Suffix , typename ErrorHandler >
void * pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >::GetData ( void *  frame) const
protected

Returns a data pointer from a frame pointer.

◆ GetFrame()

template<typename Prefix , typename Suffix , typename ErrorHandler >
void * pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >::GetFrame ( void *  data) const
protected

Returns the frame pointer from a data pointer, that is, return a pointer to memory holding the prefix, usable memory, and suffix from a pointer to the usable memory.

◆ GetPrefix()

template<typename Prefix , typename Suffix , typename ErrorHandler >
auto pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >::GetPrefix ( void *  data) const
protected

Returns a pointer to prefix.

It is an error to call this method if the prefix type is void.

◆ GetSuffix()

template<typename Prefix , typename Suffix , typename ErrorHandler >
auto pw::allocator::FramingAllocator< Prefix, Suffix, ErrorHandler >::GetSuffix ( void *  data) const
protected

Returns a pointer to the suffix.

It is an error to call this method if the suffix type is void.


The documentation for this class was generated from the following file: