EBGeometry
Compact, header-only C++ library for fast evaluation of signed distance functions
Loading...
Searching...
No Matches
Classes | Public Member Functions | Static Public Member Functions | List of all members
EBGeometry::Pool Class Reference

Growable bump arena over a MemoryResource. More...

#include <EBGeometry_Pool.hpp>

Public Member Functions

 Pool (MemoryResource &a_resource, size_t a_initialBytes=0)
 Construct an empty pool over a_resource, optionally pre-reserving a block.
 
 ~Pool () noexcept
 Destructor. Returns the block to the backing resource.
 
 Pool (const Pool &)=delete
 Copy constructor. Deleted: a pool uniquely owns its block.
 
Pool & operator= (const Pool &)=delete
 Copy assignment. Deleted: a pool uniquely owns its block.
 
 Pool (Pool &&a_other) noexcept
 Move constructor. Steals a_other's block and leaves it empty.
 
Pool & operator= (Pool &&a_other) noexcept
 Move assignment. Frees any current block, then steals a_other's.
 
uint64_t reserve (size_t a_count, size_t a_elemSize, size_t a_alignment)
 Bump-reserve a_count * a_elemSize bytes aligned to a_alignment.
 
void freeze () noexcept
 Freeze the block: forbid further reserve, stabilize base, enable mirror.
 
void * base () const noexcept
 Base address of the block.
 
const PoolControl * control () const noexcept
 This pool's stable control block, through which pool-resident objects re-resolve the base on every access.
 
uint64_t id () const noexcept
 Identity of this pool, unique among all pools constructed in this process.
 
uint64_t mirrorOf () const noexcept
 Identity of the pool this one ultimately mirrors, or zero if it is not a mirror.
 
uint64_t rootId () const noexcept
 Identity of the root of this pool's mirror chain.
 
size_t usedBytes () const noexcept
 Bytes currently in use (the bump cursor).
 
size_t capacityBytes () const noexcept
 Bytes currently allocated for the block.
 
bool isFrozen () const noexcept
 Whether the pool has been frozen.
 
MemoryResource & resource () const noexcept
 The backing memory resource.
 

Static Public Member Functions

static Pool mirror (const Pool &a_src, MemoryResource &a_dstResource)
 Mirror a frozen pool's whole block into another resource.
 

Detailed Description

Growable bump arena over a MemoryResource.

Move-only, single-owner RAII. See the file-level documentation for how growth, freezing and mirroring interact, and reserve for the resolve-use-discard rule.

Note
This is one of the two deliberately non-trivial types of the memory foundation (it owns a block and a resource pointer with RAII semantics); everything stored inside it is trivially copyable POD, but the pool itself is not, so no std::is_trivially_copyable_v static_assert applies here.

Constructor & Destructor Documentation

◆ Pool() [1/2]

EBGeometry::Pool::Pool ( MemoryResource &  a_resource,
size_t  a_initialBytes = 0 
)
explicit

Construct an empty pool over a_resource, optionally pre-reserving a block.

Aborts, in every build, if a_resource is not host-accessible or if a_initialBytes is more than a block can hold (the largest multiple of PoolBaseAlign a size_t holds).

Parameters
[in]a_resourceMemory resource that backs every allocation of this pool. Must outlive the pool.
[in]a_initialBytesIf non-zero, the initial block byte capacity to reserve up front (avoids the first grow). The block is still empty (usedBytes()==0).

◆ Pool() [2/2]

EBGeometry::Pool::Pool ( Pool &&  a_other)
noexcept

Move constructor. Steals a_other's block and leaves it empty.

Parameters
[in,out]a_otherSource pool, left owning nothing.

Member Function Documentation

◆ base()

void * EBGeometry::Pool::base ( ) const
inlinenoexcept

Base address of the block.

Returns
Pointer to the first byte of the block (null if nothing has been reserved yet, or if this pool has been moved from).

◆ capacityBytes()

size_t EBGeometry::Pool::capacityBytes ( ) const
inlinenoexcept

Bytes currently allocated for the block.

Returns
Block byte capacity.

◆ control()

const PoolControl * EBGeometry::Pool::control ( ) const
inlinenoexcept

This pool's stable control block, through which pool-resident objects re-resolve the base on every access.

The returned address is fixed for the lifetime of the pool and survives every move of the pool object, which is precisely why pool-resident objects store this rather than a Pool*. It does not survive the pool's destruction: the pool must outlive every object reserved from it.

Returns
Pointer to the control block (null only for a moved-from pool).

◆ freeze()

void EBGeometry::Pool::freeze ( )
noexcept

Freeze the block: forbid further reserve, stabilize base, enable mirror.

Idempotent and irreversible. The only precondition it establishes is the one mirror needs (a block that can no longer be reallocated); a reserve after it aborts, in every build. Freezing is not required to query anything built in the pool.

◆ id()

uint64_t EBGeometry::Pool::id ( ) const
inlinenoexcept

Identity of this pool, unique among all pools constructed in this process.

Assigned at construction from a monotonic counter and never reused; a mirror gets its own fresh identity. Used by mirrorOf to record lineage.

Returns
This pool's identity (zero only for a moved-from pool).

◆ isFrozen()

bool EBGeometry::Pool::isFrozen ( ) const
inlinenoexcept

Whether the pool has been frozen.

Returns
True after freeze.

◆ mirror()

static Pool EBGeometry::Pool::mirror ( const Pool &  a_src,
MemoryResource &  a_dstResource 
)
static

Mirror a frozen pool's whole block into another resource.

Allocates a fresh block of exactly a_src.usedBytes() from a_dstResource, copies the entire block byte-for-byte (via GPU::memcpy for a host/device transfer, or std::memcpy for a host-to-host copy), and returns the result frozen. Every PODVector offset resolves unchanged against the new base – this is the host-to-device mirror (and, host-to-host, an exact independent copy). A device-to-host mirror copies results back; a device-to-device mirror (neither resource host-accessible) aborts, in every build.

Parameters
[in]a_srcSource pool. Must be frozen (a_src.isFrozen()); an unfrozen source aborts, in every build.
[in]a_dstResourceDestination resource for the mirrored block. Must outlive the returned pool.
Returns
A new, frozen pool holding a byte-identical copy of a_src's block.

◆ mirrorOf()

uint64_t EBGeometry::Pool::mirrorOf ( ) const
inlinenoexcept

Identity of the pool this one ultimately mirrors, or zero if it is not a mirror.

This names the root of the mirror chain, not the immediate source: mirroring host -> pinned staging -> device leaves the device pool naming the original host pool, not the staging pool. That is what lets a pool-resident object built in the host pool validate a rebase onto the device pool (see EBGeometry::DCEL::MeshT::rebasedView) without having to know how many hops the block traveled.

Returns
Identity of the root source pool, or 0 if this pool is not a mirror.

◆ operator=()

Pool & EBGeometry::Pool::operator= ( Pool &&  a_other)
noexcept

Move assignment. Frees any current block, then steals a_other's.

Parameters
[in,out]a_otherSource pool, left owning nothing.
Returns
Reference to this pool.

◆ reserve()

uint64_t EBGeometry::Pool::reserve ( size_t  a_count,
size_t  a_elemSize,
size_t  a_alignment 
)

Bump-reserve a_count * a_elemSize bytes aligned to a_alignment.

Returns the byte offset of the reserved sub-region from base. May grow the block (on a host-accessible resource only). Forbidden after freeze(): a reserve on a frozen pool, an invalid a_alignment, or a request that, added to the bytes already reserved, is more than a block can hold (the largest multiple of PoolBaseAlign a size_t holds), aborts with a message in every build.

Warning
A grow does not extend the block in place: it allocates a new block, copies the live bytes into it, and deallocates the old one. Every address that was already resolved against the old base – a raw pointer, a T& handed out by PODVector::at or by a pool-resident container's accessor, a PODSpan from PODVector::bind – is dangling afterwards. Every PODVector is unaffected, because it stores a byte offset rather than an address, and so is anything that re-resolves through PoolControl::m_base.

The rule is therefore: resolve, use, discard. A resolved address must not outlive the next reserve on the same pool. To carry data across a reserve, carry it by value and write it back through a fresh resolution:

Edge e = mesh.getEdge(3); // snapshot; independent of any base
mesh.reserveFaces(pool, n); // may grow, moving the block
e.setFace(7);
mesh.getEdge(3) = e; // fresh resolution against the current base

Note that the hazard is intermittent – a grow only happens when the request exceeds the current capacity – and its quiet form is worse than a crash: if the freed block is still mapped, a write through a stale address lands in the abandoned copy and is silently lost.

Parameters
[in]a_countNumber of elements.
[in]a_elemSizeSize of one element in bytes.
[in]a_alignmentRequired alignment of the sub-region (power of two, <= PoolBaseAlign).
Returns
Byte offset of the sub-region from base; base() + offset is a_alignment-aligned.

◆ resource()

MemoryResource & EBGeometry::Pool::resource ( ) const
inlinenoexcept

The backing memory resource.

Returns
Reference to the resource passed at construction.

◆ rootId()

uint64_t EBGeometry::Pool::rootId ( ) const
inlinenoexcept

Identity of the root of this pool's mirror chain.

This pool's own identity if it is not a mirror, else mirrorOf. Two pools with the same root hold byte-identical copies of the root's block, as far as the root's frozen contents go, so a descriptor built in one can be rebased onto any other.

Returns
The root identity (zero only for a moved-from pool).

◆ usedBytes()

size_t EBGeometry::Pool::usedBytes ( ) const
inlinenoexcept

Bytes currently in use (the bump cursor).

Returns
Number of reserved bytes.

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