#pragma once #include 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 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(ptr)) { } explicit PointerOrValue(T val) : repr_((static_cast(val) << 1) | 1) { } [[nodiscard]] bool HoldsPointer() const { return (repr_ & 1) == 0; } [[nodiscard]] const T *AsPointer() const { return reinterpret_cast(repr_); } [[nodiscard]] T AsValue() const { return static_cast(repr_ >> 1); } private: uintptr_t repr_; }; } // namespace devilution