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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
#pragma once
#include "deimos/core/base.h"
#include "deimos/core/format.h"
namespace deimos
{
// NOLINTNEXTLINE(performance-enum-size)
enum class StatusCode : uint32_t
{
kOk = 0,
kUnknown,
kInvalidArgument,
kUnimplemented,
kInternal,
};
StringView StatusCodeToString(StatusCode code);
class Status
{
uintptr_t m_rep;
constexpr bool IsInline() const
{
return (m_rep & 1U) == 1U;
}
static constexpr uintptr_t CodeToRep(StatusCode code)
{
return ((uint32_t)code << 1U) | 1U;
}
void Ref() const;
void Unref() const;
StatusCode RepCode() const;
public:
constexpr Status() : Status(StatusCode::kOk) {}
constexpr explicit Status(StatusCode code) : m_rep{CodeToRep(code)} {}
Status(StatusCode code, StringView message);
Status(const Status& other) : m_rep{other.m_rep}
{
Ref();
}
Status(Status&& other) : m_rep{std::exchange(other.m_rep, CodeToRep(StatusCode::kOk))} {}
Status& operator=(const Status& other)
{
if (this != &other)
{
Unref();
this->m_rep = other.m_rep;
Ref();
}
return *this;
}
Status& operator=(Status&& other)
{
if (this != &other)
{
Unref();
this->m_rep = std::exchange(other.m_rep, CodeToRep(StatusCode::kOk));
}
return *this;
}
~Status()
{
Unref();
}
constexpr bool ok() const { return m_rep == CodeToRep(StatusCode::kOk); }
StatusCode code() const
{
if (IsInline()) { return (StatusCode)(m_rep >> 1U); }
return RepCode();
}
friend void DeimosFormat(IWriter*, const Status&);
};
inline Status UnknownError(StringView message = {})
{
return Status(StatusCode::kUnknown, message);
}
inline Status InvalidArgumentError(StringView message = {})
{
return Status(StatusCode::kInvalidArgument, message);
}
inline Status UnimplementedError(StringView message = {})
{
return Status(StatusCode::kUnimplemented, message);
}
inline Status InternalError(StringView message = {})
{
return Status(StatusCode::kInternal, message);
}
namespace statusor_internals
{
};
template<typename T>
class StatusOr
{
deimos_StaticAssert(!std::is_constructible_v<T, Status>);
struct Dummy{};
Status m_status;
union {
Dummy m_dummy;
T m_value;
};
void Clear()
{
if constexpr (!std::is_trivially_destructible_v<T>)
{
if (m_status.ok())
{
(&m_value)->~T();
}
}
}
public:
explicit StatusOr() requires std::is_default_constructible_v<T> :
m_value{}
{}
template<typename... Args>
StatusOr(Args&&... args) requires std::is_constructible_v<T, Args...> : // NOLINT
m_value{std::forward<Args>(args)...}
{}
StatusOr(const Status& status) : m_status{status} // NOLINT
{
if (m_status.ok())
{
deimos_Panic("Cannot construct a StatusOr from OK");
m_status = InternalError("StatusOr constructed from OK");
}
}
StatusOr(Status&& status) : m_status{std::move(status)} // NOLINT
{
if (m_status.ok())
{
deimos_Panic("Cannot construct a StatusOr from OK");
m_status = InternalError("StatusOr constructed from OK");
}
}
StatusOr(const StatusOr& other) requires std::is_copy_constructible_v<T> :
m_status{other.m_status}
{
if (m_status.ok())
{
new (&m_value) T(other.m_value);
}
}
StatusOr(StatusOr&& other) requires std::is_move_constructible_v<T> :
m_status{std::move(other.m_status)}
{
if (m_status.ok())
{
new (&m_value) T(std::move(other.m_value));
}
}
~StatusOr()
{
Clear();
}
StatusOr& operator=(const StatusOr& other) requires std::is_copy_assignable_v<T>
{
if (this != &other)
{
if (m_status.ok() && other.m_status.ok())
{
m_value = other.m_value;
}
else if (!m_status.ok() && other.m_status.ok())
{
new (&m_value) T(other.m_value);
}
else if (m_status.ok() && !other.m_status.ok())
{
Clear();
}
m_status = other.m_status;
}
return *this;
}
StatusOr& operator=(StatusOr&& other) requires std::is_move_assignable_v<T>
{
if (this != &other)
{
if (m_status.ok() && other.m_status.ok())
{
m_value = std::move(other.m_value);
}
else if (!m_status.ok() && other.m_status.ok())
{
new (&m_value) T(std::move(other.m_value));
}
else if (m_status.ok() && !other.m_status.ok())
{
Clear();
}
m_status = other.m_status;
}
return *this;
}
constexpr bool ok() const { return m_status.ok(); }
friend void DeimosFormat(IWriter* writer, const StatusOr<T>& status)
{
DeimosFormat(writer, status.m_status);
}
};
} // namespace deimos
|