You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
50 lines
1.0 KiB
50 lines
1.0 KiB
#pragma once |
|
|
|
#include <cstdint> |
|
|
|
namespace devilution { |
|
|
|
/** |
|
* @brief A tagged union of a pointer and a value in the space of a single pointer. |
|
* |
|
* Requires the type T to have alignment > 1. |
|
* Internally, uses the last bit to hold the tag: |
|
* 0 if it is a pointer, guaranteed by T's alignment requirements. |
|
* 1 if it is a value. |
|
*/ |
|
template <typename T> |
|
class PointerOrValue { |
|
static_assert(alignof(T) > 1, "requires alignof > 1"); |
|
static_assert(sizeof(T) < sizeof(T *), "type too large"); |
|
|
|
public: |
|
explicit PointerOrValue(const T *ptr) |
|
: repr_(reinterpret_cast<uintptr_t>(ptr)) |
|
{ |
|
} |
|
|
|
explicit PointerOrValue(T val) |
|
: repr_((static_cast<uintptr_t>(val) << 1) | 1) |
|
{ |
|
} |
|
|
|
[[nodiscard]] bool HoldsPointer() const |
|
{ |
|
return (repr_ & 1) == 0; |
|
} |
|
|
|
[[nodiscard]] const T *AsPointer() const |
|
{ |
|
return reinterpret_cast<const T *>(repr_); |
|
} |
|
|
|
[[nodiscard]] T AsValue() const |
|
{ |
|
return repr_ >> 1; |
|
} |
|
|
|
private: |
|
uintptr_t repr_; |
|
}; |
|
|
|
} // namespace devilution
|
|
|