carb::extras::HandleDatabase¶
Defined in carb/extras/HandleDatabase.h
-
template<class
Mapped
, classHandle
, classAllocator
= std::allocator<Mapped>>
classcarb::extras
::
HandleDatabase
¶ Provides an OS-style mapping of a Handle to a Resource.
Essentially HandleDatabase is a fast thread-safe reference-counted associative container.
A given Handle value is typically never reused, however, it is possible for a handle value to be reused if billions of handles are requested.
- Thread Safety
Unless otherwise mentioned, HandleDatabase functions may be called simultaneously from multiple threads.
The HandleDatabase can store at most
(2^31)-1
items, or 2,147,483,647 items simultaneously, provided the memory exists to support it.Implementation Details:
HandleDatabase achieves its speed and thread-safety by having a fixed-size base array (
m_database
) where each element is an array of size 2^(base array index). As such, these arrays double the size of the previous index array. These base arrays are never freed, simplifying thread safety and allowing HandleDatabase to be mostly lockless. This array-of-arrays forms a non-contiguous indexable array where the base array and offset can be computed from a 32-bit index value (seeindexToBucketAndOffset
).The Handle is a 64-bit value composed of two 32-bit values. The least-significant 32 bits is the index value into the array-of-arrays described above. The most-significant 32 bits is a lifecycle counter. Every time a new Mapped object is constructed, the lifecycle counter is incremented. This value forms a contract between a handle and the Mapped object at the index indicated by the Handle. If the lifecycle counter doesn’t match, the Handle is invalid. As this lifecycle counter is incremented, there is the possibility of rollover after 2^31 handles are generated at a given index. The most significant bit will then be set as a rollover flag so that handleWasValid() continues to operate correctly. The handleWasValid() function returns
true
for any Handle where the lifecycle counter at the given index is greater-than-or-equal to the Handle’s lifecycle counter, or if the rollover flag is set.- tparam Mapped
The “value” type that is associated with a Handle.
- tparam Handle
The “key” type. Must be an unsigned integer or pointer type and 64-bit. This is an opaque type that cannot be dereferenced.
- tparam Allocator
The allocator that will be used to allocate memory. Must be capable of allocating large contiguous blocks of memory.
Public Types
-
using
HandleRefType
= HandleRef<Mapped, Handle, Allocator>¶ An alias to the HandleRef for this HandleDatabase.
-
using
scoped_handle_ref_type
= HandleRefType¶ Deprecated: Use HandleRefType instead.
Public Functions
-
inline constexpr
HandleDatabase
() noexcept¶ Constructor.
- Thread Safety
The constructor must complete in a single thread before any other functions may be called on
*this
.
-
inline
~HandleDatabase
()¶ Destructor.
- Thread Safety
All other functions on
*this
must be finished before the destructor can be called.
-
inline bool
handleWasValid
(Handle handle) const¶ Checks to see if a handle is valid or was ever valid in the past.
- Parameters
handle – The Handle to check.
- Returns
true
if ahandle
is currently valid or was valid in the past and has since been released;false
otherwise.
-
template<class ...
Args
>
inline std::pair<Handle, Mapped*>createHandle
(Args&&... args)¶ Creates a new Mapped type with the given arguments.
- Parameters
args – The arguments to pass to the Mapped constructor.
- Returns
A
std::pair
of the Handle that can uniquly identify the new Mapped type, and a pointer to the newly constructed Mapped type.
-
inline Mapped *
getValueFromHandle
(Handle handle) const¶ Attempts to find the Mapped type represented by
handle
.- Thread Safety
Not thread-safe as the Mapped type could be destroyed if another thread calls release().
- Parameters
handle – A handle previously returned from createHandle(). Invalid or previously-valid handles will merely result in a
nullptr
result without an assert or any other side-effects.- Returns
A pointer to a valid Mapped type if the handle was valid;
nullptr
otherwise.
-
inline Handle
getHandleFromValue
(const Mapped *mapped) const¶ Retrieves the Handle representing
mapped
.Warning
Providing
mapped
that is no longer valid or was not returned from one of the HandleDatabase functions is undefined.- Parameters
mapped – A Mapped type previously created with createHandle().
- Returns
The Handle representing
mapped
.
-
inline Mapped *
tryAddRef
(Handle handle)¶ Atomically attempts to add a reference for the given Handle.
- Parameters
handle – A handle previously returned from createHandle(). Invalid or previously-valid handles will merely result in a
nullptr
result without an assert or any other side-effects.- Returns
A pointer to a valid Mapped type if a reference could be added;
nullptr
otherwise.
-
inline void
addRef
(Handle handle)¶ Atomically adds a reference for the given Handle; fatal if
handle
is invalid.- Parameters
handle – A valid handle previously returned from createHandle(). Invalid or previously-valid handles will result in
std::terminate()
being called.
-
inline void
addRef
(Mapped *mapped)¶ Atomically adds a reference for the Handle representing
mapped
.Warning
Providing
mapped
that is no longer valid or was not returned from one of the HandleDatabase functions is undefined.- Parameters
mapped – A Mapped type previously created with createHandle().
-
inline bool
release
(Handle handle)¶ Atomically releases a reference for the given Handle, potentially freeing the associated Mapped type.
- Parameters
handle – A valid handle previously returned from createHandle(). Invalid or previously-valid handles will result in an assert in Debug builds, but return
false
with no side effects in Release builds.- Returns
true
if the last reference was released andhandle
is no longer valid;false
if Handle is not valid or is previously-valid or a non-final reference was released.
-
inline bool
release
(Mapped *mapped)¶ Atomically releases a reference for the Handle representing
mapped
.Warning
Provided
mapped
that is no longer valid or was not returned from one of the HandleDatabase functions is undefined.- Parameters
mapped – A Mapped type previously created with createHandle().
- Returns
true
if the last reference was released andmapped
is no longer valid;false
if a reference other than the last reference was released.
-
inline bool
releaseIfLastRef
(Handle handle)¶ Atomically releases a reference if and only if it’s the last reference.
- Parameters
handle – A valid handle previously returned from createHandle(). Invalid or previously-valid handles will result in an assert in Debug builds, but return
false
with no side effects in Release builds.- Returns
true
if the last reference was released andhandle
is no longer valid;false
otherwise.
-
inline bool
releaseIfLastRef
(Mapped *mapped)¶ Atomically releases a reference if and only if it’s the last reference.
Warning
Provided
mapped
that is no longer valid or was not returned from one of the HandleDatabase functions is undefined.- Parameters
mapped – A Mapped type previously created with createHandle().
- Returns
true
if the last reference was released andmapped
is no longer valid;false
otherwise.
-
inline HandleRefType
makeScopedRef
(Handle handle)¶ Attempts to atomically add a reference to
handle
, and returns a HandleRef tohandle
.- Parameters
handle – A handle previously returned from createHandle(). Invalid or previously-valid handles will merely result in an empty HandleRef result without an assert or any other side-effects.
- Returns
If tryAddRef() would return a valid Mapped type for
handle
, then a HandleRef that manages the reference is returned; otherwise an empty HandleRef is returned.
-
inline const HandleRefType
makeScopedRef
(Handle handle) const¶ Attempts to atomically add a reference to
handle
, and returns a HandleRef tohandle
.- Parameters
handle – A handle previously returned from createHandle(). Invalid or previously-valid handles will merely result in an empty HandleRef result without an assert or any other side-effects.
- Returns
If tryAddRef() would return a valid Mapped type for
handle
, then a HandleRef that manages the reference is returned; otherwise an empty HandleRef is returned.
-
template<class
Func
>
inline voidforEachHandle
(Func &&f) const¶ Calls the provided
Func
invokeable object for each valid handle and its associated mapped type.- Thread Safety
This function is not safe to call if any other thread would be calling releaseIfLastRef() or release() to release the last reference of a Handle. Other threads calling createHandle() when this function is called may result in handles being skipped.
- Parameters
f – An invokeable object with signature
void(Handle, Mapped*)
.
-
inline size_t
clear
()¶ Iterates over all valid handles and sets their reference counts to zero, destroying the associated mapped type.
- Thread Safety
This function is NOT safe to call if any other thread is calling ANY other HandleDatabase function except for clear() or handleWasValid().
- Returns
The number of handles that were released to zero.