|
Wildmeshing Toolkit
|
Preallocated storage plus the atomic counter that hands slots out of it. More...
#include <SlotPool.hpp>
Public Types | |
| using | value_type = T |
Public Member Functions | |
| SlotPool (const SlotPool &)=delete | |
| SlotPool & | operator= (const SlotPool &)=delete |
| size_t | capacity () const |
| Slots the storage can hold: the end of the spare region. | |
| size_t | live () const |
| void | set_live (size_t n) |
Set the live count directly. For init and consolidate, which fill [0, n) themselves. | |
| void | resize (size_t n) |
| Resize the storage. Does not touch the live count – the caller decides that. | |
| void | shrink_to_fit () |
| void | clear () |
| Drop the storage and the live count together, leaving an empty pool. | |
| T & | operator[] (size_t i) |
| const T & | operator[] (size_t i) const |
| size_t | request (size_t n) |
Atomically reserve n contiguous fresh slots. | |
Exhaustion flag | |
Set by | |
| bool | refused () const |
| void | clear_refused () |
Whole-storage iteration | |
These span | |
| auto | begin () |
| auto | end () |
| auto | begin () const |
| auto | end () const |
Private Attributes | |
| std::vector< T > | m_data |
| std::atomic< size_t > | m_live {0} |
| std::atomic< bool > | m_refused {false} |
Preallocated storage plus the atomic counter that hands slots out of it.
The mesh classes keep their connectivity in a vector that is deliberately larger than the live mesh: [0, live()) is filled, and [live(), capacity()) is spare headroom that operations consume. Operations run in parallel, so the counter is advanced with a CAS loop and a request that would run past capacity() is REFUSED rather than served by growing the storage – growing means reallocating, which would move the connectivity out from under concurrent readers. Callers ask for their slots up front and abort before mutating when the answer is a refusal.
Pairing the counter with the storage is the point of this class. The invariant that matters is live() <= capacity(), and it can only be checked – or maintained – where both are in reach. It is also the seat for any future growth strategy: implementing one here covers every allocation site in both meshes at once.
Not copyable or movable, because of the atomic. The meshes that hold these were already neither, for the same reason.
request is safe to call concurrently. Everything else – resize, clear, set_live, shrink_to_fit – is for the serial points between passes, and operator[] is subject to the usual rule that a reader must not race the grower.
|
inline |
Slots handed out so far: the end of the live region, and the next index request would return. Named apart from capacity() because the two are genuinely different numbers, and conflating them is what makes the spare region hard to reason about.
|
inline |
Atomically reserve n contiguous fresh slots.
capacity(). A refusal leaves the counter untouched, so the slots that remain stay available to a later, smaller request; a request that leaked would push live() past capacity() and send subsequent iteration out of bounds.n == 0 reports the current live() without consuming anything.