Skip to content

Commit 98b707d

Browse files
committed
Runtime: Separate DeferredHolder into a detail object
should have done this earlier Adds an Optional<T> class which isn't being used quite yet
1 parent 1ae30c1 commit 98b707d

File tree

3 files changed

+206
-103
lines changed

3 files changed

+206
-103
lines changed

include/runtime/Expected.h

+25-103
Original file line numberDiff line numberDiff line change
@@ -9,90 +9,12 @@
99
#define ELFLDR_EXPECTED_H
1010

1111
#include <runtime/Assert.h>
12+
#include <runtime/detail/DeferredHolder.h>
1213
#include <runtime/Utility.h>
1314
#include <stdint.h>
1415

1516
namespace elfldr {
1617

17-
// MAYBE: Move this to a shared spot, so we can do
18-
// Maybe<T> (or Optional<T>)
19-
namespace detail {
20-
21-
/**
22-
* A safe deferred container for class types.
23-
* Performs no heap allocations.
24-
*/
25-
template <class T>
26-
struct DeferredHolderFor {
27-
constexpr ~DeferredHolderFor() {
28-
if(constructed)
29-
Get()->~T();
30-
}
31-
32-
constexpr DeferredHolderFor() = default; // do not initalize anything
33-
34-
explicit DeferredHolderFor(const T& t) {
35-
// call the copy constructor
36-
Construct(t);
37-
}
38-
39-
constexpr DeferredHolderFor& operator=(const DeferredHolderFor& df) {
40-
if(this == &df)
41-
return *this;
42-
43-
(*this->Get()) = (*df->Get());
44-
}
45-
46-
constexpr DeferredHolderFor& operator=(const T& t) {
47-
Construct(t);
48-
}
49-
50-
template <class... Args>
51-
constexpr void Construct(Args&&... args) {
52-
if(constructed)
53-
Destruct();
54-
55-
// construct new T
56-
constructed = true;
57-
new(Get()) T(Forward<Args>(args)...);
58-
}
59-
60-
constexpr void Destruct() {
61-
if(constructed) {
62-
constructed = false;
63-
Get()->~T();
64-
}
65-
}
66-
67-
[[nodiscard]] constexpr bool IsConstructed() const {
68-
return constructed;
69-
}
70-
71-
constexpr T& GetConstructed() {
72-
ELFLDR_ASSERT(constructed);
73-
return *Get();
74-
}
75-
76-
constexpr const T& GetConstructed() const {
77-
ELFLDR_ASSERT(constructed);
78-
return *Get();
79-
}
80-
81-
private:
82-
constexpr T* Get() {
83-
return UBCast<T*>(&storage[0]);
84-
}
85-
86-
constexpr const T* Get() const {
87-
return UBCast<const T*>(&storage[0]);
88-
}
89-
90-
bool constructed { false };
91-
alignas(T) uint8_t storage[sizeof(T)] {};
92-
};
93-
94-
} // namespace detail
95-
9618
/**
9719
* A class template for working with deterministic errors.
9820
* \tparam T Return type. Can be void
@@ -103,26 +25,26 @@ namespace elfldr {
10325
constexpr Expected() = default;
10426

10527
constexpr Expected(const T& t) // NOLINT
106-
: t(t) {
28+
: value(t) {
10729
}
10830

10931
constexpr Expected(const E& e) // NOLINT
110-
: e(e) {
32+
: error(e) {
11133
}
11234

11335
constexpr Expected& operator=(const T& t) {
114-
if(e.IsConstructed())
115-
e.Destruct();
36+
if(error.IsConstructed())
37+
error.Destruct();
11638

117-
this->t = t;
39+
this->value = t;
11840
return *this;
11941
}
12042

12143
constexpr Expected& operator=(const E& e) {
122-
if(t.IsConstructed())
123-
t.Destruct();
44+
if(value.IsConstructed())
45+
value.Destruct();
12446

125-
this->e = e;
47+
this->error = e;
12648
return *this;
12749
}
12850

@@ -134,37 +56,37 @@ namespace elfldr {
13456
this->t = e.Value();
13557

13658
if(e.HasError())
137-
this->e = e.Error();
59+
this->error = e.Error();
13860

13961
return *this;
14062
}
14163

14264
[[nodiscard]] constexpr bool HasError() const {
143-
return e.IsConstructed();
65+
return error.IsConstructed();
14466
}
14567

14668
[[nodiscard]] constexpr bool HasValue() const {
147-
return t.IsConstructed();
69+
return value.IsConstructed();
14870
}
14971

15072
constexpr T& Value() {
15173
ELFLDR_VERIFY(HasValue() && !HasError());
152-
return t.GetConstructed();
74+
return value.GetConstructed();
15375
}
15476

15577
constexpr E& Error() {
15678
ELFLDR_VERIFY(!HasValue() && HasError());
157-
return e.GetConstructed();
79+
return error.GetConstructed();
15880
}
15981

16082
constexpr const T& Value() const {
16183
ELFLDR_VERIFY(HasValue() && !HasError());
162-
return t.GetConstructed();
84+
return value.GetConstructed();
16385
}
16486

16587
constexpr const E& Error() const {
16688
ELFLDR_VERIFY(!HasValue() && HasError());
167-
return e.GetConstructed();
89+
return error.GetConstructed();
16890
}
16991

17092
// Dereference operators.
@@ -187,20 +109,20 @@ namespace elfldr {
187109
}
188110

189111
private:
190-
detail::DeferredHolderFor<T> t;
191-
detail::DeferredHolderFor<E> e;
112+
detail::DeferredHolder<T> value;
113+
detail::DeferredHolder<E> error;
192114
};
193115

194116
template <class E>
195117
struct Expected<void, E> {
196118
constexpr Expected() = default;
197119

198120
constexpr Expected(const E& e) // NOLINT
199-
: e(e) {
121+
: error(e) {
200122
}
201123

202124
constexpr Expected& operator=(const E& e) {
203-
this->e = e;
125+
this->error = e;
204126
return *this;
205127
}
206128

@@ -209,27 +131,27 @@ namespace elfldr {
209131
return *this;
210132

211133
if(e.HasError())
212-
this->e = e.Error();
134+
this->error = e.Error();
213135

214136
return *this;
215137
}
216138

217139
[[nodiscard]] constexpr bool HasError() const {
218-
return e.IsConstructed();
140+
return error.IsConstructed();
219141
}
220142

221143
constexpr E& Error() {
222144
ELFLDR_ASSERT(HasError());
223-
return e.GetConstructed();
145+
return error.GetConstructed();
224146
}
225147

226148
constexpr const E& Error() const {
227149
ELFLDR_ASSERT(HasError());
228-
return e.GetConstructed();
150+
return error.GetConstructed();
229151
}
230152

231153
private:
232-
detail::DeferredHolderFor<E> e;
154+
detail::DeferredHolder<E> error;
233155
};
234156

235157
template <class E>

include/runtime/Optional.h

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* SSX-Elfldr
3+
*
4+
* (C) 2021-2022 Lily/modeco80 <[email protected]>
5+
* under the terms of the MIT license.
6+
*/
7+
8+
#ifndef ELFLDR_OPTIONAL_H
9+
#define ELFLDR_OPTIONAL_H
10+
11+
#include <runtime/detail/DeferredHolder.h>
12+
13+
namespace elfldr {
14+
15+
/**
16+
* Safe optional object.
17+
*/
18+
template<class T>
19+
struct Optional {
20+
using ValueType = T;
21+
using Reference = T&;
22+
using ConstReference = const T&;
23+
24+
constexpr Optional() = default;
25+
26+
constexpr Optional(const T& t) // NOLINT
27+
: value(t) {
28+
}
29+
30+
constexpr Optional& operator=(const T& t) {
31+
value = t;
32+
return *this;
33+
}
34+
35+
inline Optional& operator=(const Optional& optional) {
36+
if(this == &optional)
37+
return *this;
38+
39+
value = optional.value;
40+
return *this;
41+
}
42+
43+
constexpr bool HasValue() const {
44+
return value.IsConstructed();
45+
}
46+
47+
constexpr T& Value() {
48+
ELFLDR_VERIFY(HasValue());
49+
return value.GetConstructed();
50+
}
51+
52+
constexpr const T& Value() const {
53+
ELFLDR_VERIFY(HasValue());
54+
return value.GetConstructed();
55+
}
56+
57+
T& operator*() {
58+
return Value();
59+
}
60+
61+
const T& operator*() const {
62+
return Value();
63+
}
64+
65+
T* operator->() {
66+
return &Value();
67+
}
68+
69+
const T* operator->() const {
70+
return &Value();
71+
}
72+
73+
private:
74+
detail::DeferredHolder<T> value;
75+
};
76+
77+
}
78+
79+
#endif // ELFLDR_OPTIONAL_H

0 commit comments

Comments
 (0)