ROSE 0.11.145.297
Optional.h
1// WARNING: Changes to this file must be contributed back to Sawyer or else they will
2// be clobbered by the next update from Sawyer. The Sawyer repository is at
3// https://gitlab.com/charger7534/sawyer.git.
4
5
6
7
8#ifndef Sawyer_Optional_H
9#define Sawyer_Optional_H
10
11#include <Sawyer/Sawyer.h>
12
13#include <stdexcept>
14
15namespace Sawyer {
16
34class Nothing { // final
35public:
36 Nothing() {}
37 template<class T> explicit Nothing(T) {}
38 template<class T> Nothing& operator=(T) { return *this; }
39 bool operator==(const Nothing&) const { return true; }
40 bool operator!=(const Nothing&) const { return false; }
41 bool operator>(const Nothing&) const { return false; }
42 bool operator>=(const Nothing&) const { return true; }
43 bool operator<(const Nothing&) const { return false; }
44 bool operator<=(const Nothing&) const { return true; }
45};
46
53template<typename T>
54class Optional {
55 alignas(alignof(T)) unsigned char data_[sizeof(T)]; // storage for the value
56 bool isEmpty_;
57
58 void *address() { return data_; }
59 const void*address() const { return &data_; }
60
61#ifdef SAWYER_HAVE_BOOST_SERIALIZATION
62private:
63 friend class boost::serialization::access;
64
65 template<class S>
66 void save(S &s, const unsigned /*version*/) const {
67 s <<BOOST_SERIALIZATION_NVP(isEmpty_);
68 if (!isEmpty_)
69 s <<boost::serialization::make_nvp("value", get());
70 }
71
72 template<class S>
73 void load(S &s, const unsigned /*version*/) {
74 *this = Nothing();
75 bool skip = false;
76 s >>boost::serialization::make_nvp("isEmpty_", skip);
77 if (!skip) {
78 *this = T();
79 s >>boost::serialization::make_nvp("value", get());
80 }
81 }
82
83 BOOST_SERIALIZATION_SPLIT_MEMBER();
84#endif
85
86#ifdef SAWYER_HAVE_CEREAL
87private:
88 friend class cereal::access;
89
90 template<class Archive>
91 void CEREAL_SAVE_FUNCTION_NAME(Archive &archive) const {
92 archive(cereal::make_nvp("isEmpty", isEmpty_));
93 if (!isEmpty_)
94 archive(cereal::make_nvp("value", get()));
95 }
96
97 template<class Archive>
98 void CEREAL_LOAD_FUNCTION_NAME(Archive &archive) {
99 *this = Nothing();
100 bool isEmpty = false;
101 archive(CEREAL_NVP(isEmpty));
102 if (!isEmpty) {
103 *this = T{};
104 archive(cereal::make_nvp("value", get()));
105 }
106 }
107#endif
108
109public:
111 typedef T Value;
112
116 Optional(): isEmpty_(true) {}
117
121 Optional(const Value &v): isEmpty_(false) { // implicit
122 new (address()) Value(v); // copy constructed in place
123 }
124
128 Optional(const Nothing&): isEmpty_(true) {}
129
134 Optional(const Optional &other) {
135 isEmpty_ = other.isEmpty_;
136 if (!isEmpty_) {
137 const Value &otherValue = *other;
138 new (address()) Value(otherValue);
139 }
140 }
141
146 if (!isEmpty_) {
147 Value &thisValue = **this;
148 thisValue.~Value();
149 }
150 }
151
156 Optional& operator=(const Value &value) {
157 if (isEmpty_) {
158 new (address()) Value(value);
159 } else {
160 Value &thisValue = **this;
161 thisValue = value;
162 }
163 isEmpty_ = false;
164 return *this;
165 }
166
172 if (!isEmpty_) {
173 Value &thisValue = **this;
174 thisValue.~Value();
175 }
176 isEmpty_ = true;
177 return *this;
178 }
179
186 Optional& operator=(const Optional &other) {
187 if (isEmpty_ && !other.isEmpty_) {
188 const Value &otherValue = *other;
189 new (address()) Value(otherValue);
190 } else if (!isEmpty_) {
191 if (other.isEmpty_) {
192 Value &thisValue = **this;
193 thisValue.~Value();
194 } else {
195 Value &thisValue = **this;
196 const Value &otherValue = *other;
197 thisValue = otherValue;
198 }
199 }
200 isEmpty_ = other.isEmpty_;
201 return *this;
202 }
203
205 void reset() {
206 *this = Nothing();
207 }
208
215 const Value& operator*() const {
216 return get();
217 }
219 return get();
220 }
221 const Value& get() const {
222 if (isEmpty_)
223 throw std::domain_error("dereferenced nothing");
224 return *reinterpret_cast<const Value*>(address());
225 }
227 if (isEmpty_)
228 throw std::domain_error("dereferenced nothing");
229 return *reinterpret_cast<Value*>(address());
230 }
239 const Value* operator->() const {
240 return &get();
241 }
243 return &get();
244 }
259 const Value& orElse(const Value &dflt) const {
260 return isEmpty_ ? dflt : **this;
261 }
262 const Value& orElse(Value &dflt) {
263 return isEmpty_ ? dflt : **this;
264 }
265 const Optional orElse(const Optional &other) const {
266 return isEmpty_ ? other : *this;
267 }
275 Optional andThen(const Value &value) const {
276 return isEmpty_ ? *this : Optional(value);
277 }
278 Optional andTHen(Value &value) const {
279 return isEmpty_ ? *this : Optional(value);
280 }
281 const Optional& andThen(const Optional &other) const {
282 return isEmpty_ ? *this : other;
283 }
297 Value orDefault() const {
298 return isEmpty_ ? Value() : **this;
299 }
300
322 template<class U>
323 bool assignTo(U &out) const {
324 if (isEmpty_) {
325 return false;
326 } else {
327 out = **this;
328 return true;
329 }
330 }
331
339 bool isEqual(const Optional &other) const {
340 return (isEmpty_ && other.isEmpty_) || (!isEmpty_ && !other.isEmpty_ && get()==other.get());
341 }
342 bool isEqual(const Value &other) const {
343 return !isEmpty_ && get()==other;
344 }
345 bool isEqual(const Nothing&) const {
346 return isEmpty_;
347 }
355 template <typename F>
356 auto
357 fmap(F&& f) -> Optional<decltype(f(get()))> {
358 if (isEmpty_)
361 }
362
363
364 // The following trickery is to allow things like "if (x)" to work but without having an implicit
365 // conversion to bool which would cause no end of other problems. This is fixed in C++11.
366private:
367 typedef void(Optional::*unspecified_bool)() const;
368 void this_type_does_not_support_comparisons() const {}
369public:
381 operator unspecified_bool() const {
382 return isEmpty_ ? 0 : &Optional::this_type_does_not_support_comparisons;
383 }
384};
385
386
387// These functions intentionally do not compile. They are to prevent comparisons and thus save users from making
388// mistakes like this:
389// Optional<int> x = 0;
390// int y = 1;
391// if (x == y) // won't compile
392// if (x && *x == y) // what they really meant
393// if (x.isEqual(y)) // another valid way to write it
394template<typename T, typename U>
395bool operator==(const Optional<T> &lhs, const U&) {
396 lhs.this_type_does_not_support_comparisons();
397 return false;
398}
399
400template<typename T, typename U>
401bool operator!=(const Optional<T> &lhs, const U&) {
402 lhs.this_type_does_not_support_comparisons();
403 return false;
404}
405
406} // namespace
407#endif
Represents no value.
Definition Optional.h:34
Holds a value or nothing.
Definition Optional.h:54
Optional & operator=(const Nothing &)
Nothing assignment.
Definition Optional.h:171
const Value & orElse(Value &dflt)
Obtain value or something else.
Definition Optional.h:262
const Value & operator*() const
Dereference to obtain value.
Definition Optional.h:215
auto fmap(F &&f) -> Optional< decltype(f(get()))>
Conditionally apply a functor f to the contents of an Optional.
Definition Optional.h:357
T Value
Type of stored value.
Definition Optional.h:111
const Optional & andThen(const Optional &other) const
If a value is present, return something else.
Definition Optional.h:281
const Value * operator->() const
Obtain a pointer to the value.
Definition Optional.h:239
Value orDefault() const
Obtain a value or a default.
Definition Optional.h:297
Optional(const Value &v)
Construct from value.
Definition Optional.h:121
Optional & operator=(const Value &value)
Value assignment.
Definition Optional.h:156
const Optional orElse(const Optional &other) const
Obtain value or something else.
Definition Optional.h:265
Optional & operator=(const Optional &other)
Optional assignment.
Definition Optional.h:186
Optional(const Nothing &)
Construct from nothing.
Definition Optional.h:128
Value * operator->()
Obtain a pointer to the value.
Definition Optional.h:242
~Optional()
Destructor.
Definition Optional.h:145
Optional andTHen(Value &value) const
If a value is present, return something else.
Definition Optional.h:278
bool isEqual(const Nothing &) const
Compare two values.
Definition Optional.h:345
Value & operator*()
Dereference to obtain value.
Definition Optional.h:218
void reset()
Reset as if default-constructed.
Definition Optional.h:205
const Value & orElse(const Value &dflt) const
Obtain value or something else.
Definition Optional.h:259
const Value & get() const
Dereference to obtain value.
Definition Optional.h:221
Optional()
Default constructs nothing.
Definition Optional.h:116
Value & get()
Dereference to obtain value.
Definition Optional.h:226
bool assignTo(U &out) const
Conditionally save a value.
Definition Optional.h:323
bool isEqual(const Optional &other) const
Compare two values.
Definition Optional.h:339
Optional(const Optional &other)
Copy constructor.
Definition Optional.h:134
Optional andThen(const Value &value) const
If a value is present, return something else.
Definition Optional.h:275
bool isEqual(const Value &other) const
Compare two values.
Definition Optional.h:342
Sawyer support library.