Browse Source

CelSprite: Unify width storage

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
Gleb Mazovetskiy 4 years ago
parent
commit
e2dbbb3d95
  1. 8
      Source/engine/cel_sprite.hpp
  2. 50
      Source/utils/pointer_value_union.hpp

8
Source/engine/cel_sprite.hpp

@ -3,6 +3,7 @@
#include <memory>
#include <utility>
#include "utils/pointer_value_union.hpp"
#include "utils/stdcompat/cstddef.hpp"
namespace devilution {
@ -23,7 +24,7 @@ public:
CelSprite(const byte *data, const uint16_t *widths)
: data_ptr_(data)
, widths_(widths)
, width_(widths)
{
}
@ -41,7 +42,7 @@ public:
[[nodiscard]] uint16_t Width(std::size_t frame = 1) const
{
return widths_ == nullptr ? width_ : widths_[frame];
return width_.HoldsPointer() ? width_.AsPointer()[frame] : width_.AsValue();
}
[[nodiscard]] bool operator==(CelSprite other) const
@ -55,8 +56,7 @@ public:
private:
const byte *data_ptr_;
uint16_t width_ = 0;
const uint16_t *widths_ = nullptr; // unowned
PointerOrValue<uint16_t> width_;
};
/**

50
Source/utils/pointer_value_union.hpp

@ -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…
Cancel
Save