ROSE  0.11.96.11
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://github.com/matzke1/sawyer.
4 
5 
6 
7 
8 #ifndef Sawyer_Optional_H
9 #define Sawyer_Optional_H
10 
11 #include <Sawyer/Sawyer.h>
12 #include <boost/serialization/access.hpp>
13 #include <boost/serialization/nvp.hpp>
14 #include <boost/serialization/split_member.hpp>
15 #include <boost/type_traits/aligned_storage.hpp>
16 #include <boost/type_traits/type_with_alignment.hpp>
17 
18 #include <stdexcept>
19 
20 namespace Sawyer {
21 
32 class Nothing { // final
33 public:
34  bool operator==(const Nothing&) const { return true; }
35  bool operator!=(const Nothing&) const { return false; }
36  bool operator>(const Nothing&) const { return false; }
37  bool operator>=(const Nothing&) const { return true; }
38  bool operator<(const Nothing&) const { return false; }
39  bool operator<=(const Nothing&) const { return true; }
40 };
41 
48 template<typename T>
49 class Optional {
50 
51  // Done as a union to avoid aliasing warnings from GCC
52  union SAWYER_MAY_ALIAS MayAlias {
53  unsigned char data_[sizeof(T)];
54  BOOST_DEDUCED_TYPENAME boost::type_with_alignment<boost::alignment_of<T>::value >::type aligner_;
55  } mayAlias_;
56 
57  bool isEmpty_;
58 
59  void *address() { return &mayAlias_; }
60  const void*address() const { return &mayAlias_; }
61 
62 private:
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 
85 public:
87  typedef T Value;
88 
92  Optional(): isEmpty_(true) {}
93 
97  Optional(const Value &v): isEmpty_(false) { // implicit
98  new (address()) Value(v); // copy constructed in place
99  }
100 
104  Optional(const Nothing&): isEmpty_(true) {}
105 
110  Optional(const Optional &other) {
111  isEmpty_ = other.isEmpty_;
112  if (!isEmpty_) {
113  const Value &otherValue = *other;
114  new (address()) Value(otherValue);
115  }
116  }
117 
122  if (!isEmpty_) {
123  Value &thisValue = **this;
124  thisValue.~Value();
125  }
126  }
127 
132  Optional& operator=(const Value &value) {
133  if (isEmpty_) {
134  new (address()) Value(value);
135  } else {
136  Value &thisValue = **this;
137  thisValue = value;
138  }
139  isEmpty_ = false;
140  return *this;
141  }
142 
148  if (!isEmpty_) {
149  Value &thisValue = **this;
150  thisValue.~Value();
151  }
152  isEmpty_ = true;
153  return *this;
154  }
155 
162  Optional& operator=(const Optional &other) {
163  if (isEmpty_ && !other.isEmpty_) {
164  const Value &otherValue = *other;
165  new (address()) Value(otherValue);
166  } else if (!isEmpty_) {
167  if (other.isEmpty_) {
168  Value &thisValue = **this;
169  thisValue.~Value();
170  } else {
171  Value &thisValue = **this;
172  const Value &otherValue = *other;
173  thisValue = otherValue;
174  }
175  }
176  isEmpty_ = other.isEmpty_;
177  return *this;
178  }
179 
181  void reset() {
182  *this = Nothing();
183  }
184 
191  const Value& operator*() const {
192  return get();
193  }
195  return get();
196  }
197  const Value& get() const {
198  if (isEmpty_)
199  throw std::domain_error("dereferenced nothing");
200  return *reinterpret_cast<const Value*>(address());
201  }
202  Value& get() {
203  if (isEmpty_)
204  throw std::domain_error("dereferenced nothing");
205  return *reinterpret_cast<Value*>(address());
206  }
215  const Value* operator->() const {
216  return &get();
217  }
219  return &get();
220  }
235  const Value& orElse(const Value &dflt) const {
236  return isEmpty_ ? dflt : **this;
237  }
238  const Value& orElse(Value &dflt) {
239  return isEmpty_ ? dflt : **this;
240  }
241  const Optional orElse(const Optional &other) const {
242  return isEmpty_ ? other : *this;
243  }
257  Value orDefault() const {
258  return isEmpty_ ? Value() : **this;
259  }
260 
282  template<class U>
283  bool assignTo(U &out) const {
284  if (isEmpty_) {
285  return false;
286  } else {
287  out = **this;
288  return true;
289  }
290  }
291 
299  bool isEqual(const Optional &other) const {
300  return (isEmpty_ && other.isEmpty_) || (!isEmpty_ && !other.isEmpty_ && get()==other.get());
301  }
302  bool isEqual(const Value &other) const {
303  return !isEmpty_ && get()==other;
304  }
305  bool isEqual(const Nothing&) const {
306  return isEmpty_;
307  }
310  // The following trickery is to allow things like "if (x)" to work but without having an implicit
311  // conversion to bool which would cause no end of other problems. This is fixed in C++11.
312 private:
313  typedef void(Optional::*unspecified_bool)() const;
314  void this_type_does_not_support_comparisons() const {}
315 public:
327  operator unspecified_bool() const {
328  return isEmpty_ ? 0 : &Optional::this_type_does_not_support_comparisons;
329  }
330 };
331 
332 
333 // These functions intentionally do not compile. They are to prevent comparisons and thus save users from making
334 // mistakes like this:
335 // Optional<int> x = 0;
336 // int y = 1;
337 // if (x == y) // won't compile
338 // if (x && *x == y) // what they really meant
339 // if (x.isEqual(y)) // another valid way to write it
340 template<typename T, typename U>
341 bool operator==(const Optional<T> &lhs, const U &rhs) {
342  lhs.this_type_does_not_support_comparisons();
343  return false;
344 }
345 
346 template<typename T, typename U>
347 bool operator!=(const Optional<T> &lhs, const U &rhs) {
348  lhs.this_type_does_not_support_comparisons();
349  return false;
350 }
351 
352 } // namespace
353 #endif
Sawyer::Optional::isEqual
bool isEqual(const Optional &other) const
Compare two values.
Definition: Optional.h:299
Sawyer::Optional::operator*
const Value & operator*() const
Dereference to obtain value.
Definition: Optional.h:191
Sawyer::Optional
Holds a value or nothing.
Definition: Optional.h:49
Sawyer::Nothing
Represents no value.
Definition: Optional.h:32
Sawyer::Optional::orElse
const Optional orElse(const Optional &other) const
Obtain value or something else.
Definition: Optional.h:241
Sawyer::Optional::isEqual
bool isEqual(const Nothing &) const
Compare two values.
Definition: Optional.h:305
Sawyer::Optional::operator*
Value & operator*()
Dereference to obtain value.
Definition: Optional.h:194
Sawyer::Optional::operator->
Value * operator->()
Obtain a pointer to the value.
Definition: Optional.h:218
Sawyer::Optional::Value
T Value
Type of stored value.
Definition: Optional.h:87
Sawyer::Optional::operator=
Optional & operator=(const Optional &other)
Optional assignment.
Definition: Optional.h:162
Sawyer::Optional::Optional
Optional(const Optional &other)
Copy constructor.
Definition: Optional.h:110
Sawyer::Optional::isEqual
bool isEqual(const Value &other) const
Compare two values.
Definition: Optional.h:302
Sawyer::Optional::operator=
Optional & operator=(const Value &value)
Value assignment.
Definition: Optional.h:132
Sawyer::Optional::Optional
Optional(const Nothing &)
Construct from nothing.
Definition: Optional.h:104
Sawyer::Optional::orDefault
Value orDefault() const
Obtain a value or a default.
Definition: Optional.h:257
Sawyer::Optional::operator=
Optional & operator=(const Nothing &)
Nothing assignment.
Definition: Optional.h:147
Sawyer::Optional::Optional
Optional()
Default constructs nothing.
Definition: Optional.h:92
Sawyer::Optional::orElse
const Value & orElse(const Value &dflt) const
Obtain value or something else.
Definition: Optional.h:235
Sawyer::Optional::orElse
const Value & orElse(Value &dflt)
Obtain value or something else.
Definition: Optional.h:238
Sawyer
Name space for the entire library.
Definition: Access.h:13
Sawyer::Optional::operator->
const Value * operator->() const
Obtain a pointer to the value.
Definition: Optional.h:215
Sawyer::Optional::reset
void reset()
Reset as if default-constructed.
Definition: Optional.h:181
Sawyer::Optional::get
const Value & get() const
Dereference to obtain value.
Definition: Optional.h:197
Sawyer::Optional::Optional
Optional(const Value &v)
Construct from value.
Definition: Optional.h:97
Sawyer::Optional::~Optional
~Optional()
Destructor.
Definition: Optional.h:121
Sawyer::Optional::assignTo
bool assignTo(U &out) const
Conditionally save a value.
Definition: Optional.h:283
Sawyer::Optional::get
Value & get()
Dereference to obtain value.
Definition: Optional.h:202