From d1b61b02b1a6bdaa337ff060eda3d3d5fb67827d Mon Sep 17 00:00:00 2001 From: Hannes Schulze Date: Thu, 6 Feb 2025 16:34:23 +0100 Subject: refactor: move containers into separate directory --- lib/nes/common/containers/box.hh | 78 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 lib/nes/common/containers/box.hh (limited to 'lib/nes/common/containers/box.hh') diff --git a/lib/nes/common/containers/box.hh b/lib/nes/common/containers/box.hh new file mode 100644 index 0000000..7bf2848 --- /dev/null +++ b/lib/nes/common/containers/box.hh @@ -0,0 +1,78 @@ +#pragma once + +#include "nes/common/types.hh" +#include "nes/common/debug.hh" + +namespace nes +{ + /// Wrapper around an object, allowing for it to be uninitialized or reassigned even if the object type doesn't + /// support it. + /// + /// Basically a std::unique_ptr but stored in-place (and thus not movable). + template + class box + { + bool initialized_{ false }; + alignas(T) u8 buffer_[sizeof(T)]; + + public: + /// Create an empty box. + explicit box() = default; + + ~box() + { + clear(); + } + + box(box const&) = delete; + box(box&&) = delete; + auto operator=(box const&) -> box& = delete; + auto operator=(box&&) -> box& = delete; + + auto operator*() -> T& + { + NES_ASSERT(has_value() && "expected box to be non-empty"); + return *get(); + } + + auto operator*() const -> T const& + { + NES_ASSERT(has_value() && "expected box to be non-empty"); + return *get(); + } + + auto operator->() -> T* + { + NES_ASSERT(has_value() && "expected box to be non-empty"); + return get(); + } + + auto operator->() const -> T const* + { + NES_ASSERT(has_value() && "expected box to be non-empty"); + return get(); + } + + operator bool() const { return has_value(); } + + auto has_value() const -> bool { return initialized_; } + auto get() -> T* { return has_value() ? std::launder(reinterpret_cast(buffer_)) : nullptr; } + auto get() const -> T const* { return has_value() ? std::launder(reinterpret_cast(buffer_)) : nullptr; } + + /// Construct a new value in-place, potentially replacing the old value. + template + auto emplace(Args&&... args) -> void + { + clear(); + new (buffer_) T(std::forward(args)...); + initialized_ = true; + } + + /// Clear the boxed value. + auto clear() -> void + { + if (initialized_) { (*this)->~T(); } + initialized_ = false; + } + }; +} // namespace nes \ No newline at end of file -- cgit v1.3.1