blob: 7bf2848abb182338f29447b4c5209bed60f5b5e5 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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<typename T>
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<T*>(buffer_)) : nullptr; }
auto get() const -> T const* { return has_value() ? std::launder(reinterpret_cast<T const *>(buffer_)) : nullptr; }
/// Construct a new value in-place, potentially replacing the old value.
template<typename... Args>
auto emplace(Args&&... args) -> void
{
clear();
new (buffer_) T(std::forward<Args>(args)...);
initialized_ = true;
}
/// Clear the boxed value.
auto clear() -> void
{
if (initialized_) { (*this)->~T(); }
initialized_ = false;
}
};
} // namespace nes
|