Browse Source
Reduces the size of a CelSprite by taking advantage of the fact that 16-bit pointers are aligned, so the last bit is always 0.pull/4220/merge
2 changed files with 54 additions and 4 deletions
@ -0,0 +1,50 @@
|
||||
#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
|
||||
Loading…
Reference in new issue