|
Celeritas 0.7+07fbe3c
|
Type-safe "optional" index for accessing an array or collection of data. More...
#include <OpaqueId.hh>
Public Types | |
Type aliases | |
| using | tag_type = TagT |
| using | value_type = IndexT |
| using | index_type = IndexT |
| using | difference_type = std::make_signed_t< IndexT > |
| using | size_type = value_type |
Public Member Functions | |
| constexpr | OpaqueId (nullid_t) |
| Construct implicitly from a null type. | |
| constexpr | OpaqueId () |
| Default to null state. | |
| constexpr | OpaqueId (value_type index) |
| Construct explicitly with a stored value (validity not checked) | |
| constexpr | operator bool () const noexcept |
| Whether this ID is in a valid (assigned) state. | |
| constexpr value_type | operator* () const noexcept |
| Unchecked dereference: caller must ensure the ID is valid. | |
| constexpr value_type | value () const noexcept(ndebug) |
| Get the value, asserting non-null in debug builds. | |
| constexpr value_type const * | data () const noexcept |
| Access the underlying data for cached loading on device. | |
Pointer-like operators | |
| constexpr OpaqueId & | operator++ () noexcept(ndebug) |
| constexpr OpaqueId | operator++ (int) noexcept(ndebug) |
| constexpr OpaqueId & | operator-- () noexcept(ndebug) |
| constexpr OpaqueId | operator-- (int) noexcept(ndebug) |
Deprecated access | |
| |
| constexpr value_type | get () const noexcept(ndebug) |
Get the ID's value: use value() instead. | |
| constexpr value_type | unchecked_get () const noexcept |
Get the value without checking: use operator* instead. | |
Friends | |
| std::ostream & | operator<< (std::ostream &os, OpaqueId v) |
| Output an opaque ID's value or a placeholder if unavailable. | |
Pointer-like arithmetic | |
Get the distance between two opaque IDs | |
| difference_type | operator- (OpaqueId self, OpaqueId other) |
| Increment an opaque ID by an offset, checking against underflow. | |
| template<class J > | |
| auto | operator+ (OpaqueId id, J offset) -> std::enable_if_t< std::is_integral_v< J >, OpaqueId > |
| Increment an opaque ID by an offset, checking against underflow. | |
| template<class J > | |
| auto | operator+ (J offset, OpaqueId id) -> std::enable_if_t< std::is_integral_v< J >, OpaqueId > |
| Increment an opaque ID by an offset (symmetric) | |
| template<class J > | |
| auto | operator- (OpaqueId id, J offset) -> std::enable_if_t< std::is_integral_v< J >, OpaqueId > |
| Decrement an opaque ID by an offset. | |
Compare two OpaqueId of the same type | |
| constexpr friend bool | operator== (OpaqueId lhs, OpaqueId rhs) noexcept |
| constexpr friend bool | operator!= (OpaqueId lhs, OpaqueId rhs) noexcept |
| constexpr friend bool | operator< (OpaqueId lhs, OpaqueId rhs) noexcept |
| constexpr friend bool | operator> (OpaqueId lhs, OpaqueId rhs) noexcept |
| constexpr friend bool | operator<= (OpaqueId lhs, OpaqueId rhs) noexcept |
| constexpr friend bool | operator>= (OpaqueId lhs, OpaqueId rhs) noexcept |
Compare with nullid | |
| constexpr friend bool | operator== (OpaqueId id, nullid_t) noexcept |
| constexpr friend bool | operator== (nullid_t, OpaqueId id) noexcept |
| constexpr friend bool | operator!= (OpaqueId id, nullid_t) noexcept |
| constexpr friend bool | operator!= (nullid_t, OpaqueId id) noexcept |
Compare with unsigned int | |
This allows size checking for containers | |
| template<class J > | |
| constexpr friend auto | operator< (OpaqueId lhs, J rhs) noexcept -> std::enable_if_t< std::is_unsigned_v< J >, bool > |
| template<class J > | |
| constexpr friend auto | operator<= (OpaqueId lhs, J rhs) noexcept -> std::enable_if_t< std::is_unsigned_v< J >, bool > |
Type-safe "optional" index for accessing an array or collection of data.
| TagT | Type of an item at the index corresponding to this ID |
| IndexT | Unsigned integer acting as the stored value |
Indexing into arrays with integers, rather than storing pointers, is key to easy and safe data management across host/device boundaries. Pointers in C++ can act as a reference to an array or element of data, and they also have a type, which not only gives the stride width in bytes but also prevents accidental aliasing.
The OpaqueId class is an attempt to model integer indexing (device-friendly) with pointer semantics (type-safe). Annotating index offsets with a type gives the offsets a semantic meaning, and it gives the developer compile-time type safety. As an example, it prevents index arguments in a function call from being provided out of order.
The typical usage of an OpaqueId should be as std::optional<IndexT>. The default-constructed value, nullid, cannot be used to index into an array, nor does it represent a valid element. An OpaqueId object evaluates to true if it has a value (OpaqueId{3}), or false if it does not (OpaqueId{}). The invalid state is usually referred to in the codebase as a "null ID". Analogous to std::optional, nullid can be used for comparison, assignment, and construction.
nullid nullid id_cast for safe construction from general (or differently sized) integersbool or by comparing with nullid id < vec.size()operator* : vec[*id]Collection::operator[] range The OpaqueId is hashable, sortable, and printable. It can be loaded via cached device memory using ldg .
std::partition and erase to remove null IDs from a vector.LdgWrapper.nullid is an instance of nullid_t that compares to any OpaqueId as its "null" value.is_opaque_id_v allows checking for generic typesMakeSize_t is a descriptive type alias to get the unsigned integer value_type of an opaque ID, used for container capacities.id_cast safely converts integers to OpaqueId.TagT argument should usually be the value type of the array: