SPH
Optional.h
Go to the documentation of this file.
1 #pragma once
2 
6 
7 #include "common/Assert.h"
8 #include "common/Traits.h"
10 #include <type_traits>
11 
13 
14 struct NothingType {};
15 
17 
18 
22 template <typename Type>
23 class Optional {
24 private:
25  using RawType = std::remove_reference_t<Type>;
26  using StorageType = typename WrapReferenceType<Type>::Type;
27 
28  AlignedStorage<Type> storage;
29  bool used = false;
30 
31  void destroy() {
32  if (used) {
33  storage.destroy();
34  used = false;
35  }
36  }
37 
38 public:
40  Optional() = default;
41 
45  template <typename T, typename = std::enable_if_t<std::is_copy_assignable<T>::value>>
46  Optional(const T& t) {
47  storage.emplace(t);
48  used = true;
49  }
50 
54  Optional(Type&& t) {
55  // intentionally using forward instead of move
56  storage.emplace(std::forward<Type>(t));
57  used = true;
58  }
59 
63  Optional(const Optional& other) {
64  used = other.used;
65  if (used) {
66  storage.emplace(other.value());
67  }
68  }
69 
74  Optional(Optional&& other) {
75  used = other.used;
76  if (used) {
77  storage.emplace(std::forward<Type>(other.value()));
78  }
79  other.used = false;
80  }
81 
84  used = false;
85  }
86 
88  destroy();
89  }
90 
94  template <typename... TArgs>
95  void emplace(TArgs&&... args) {
96  if (used) {
97  destroy();
98  }
99  storage.emplace(std::forward<TArgs>(args)...);
100  used = true;
101  }
102 
104  template <typename T, typename = std::enable_if_t<std::is_assignable<Type, T>::value>>
105  Optional& operator=(const T& t) {
106  if (!used) {
107  storage.emplace(t);
108  used = true;
109  } else {
110  value() = t;
111  }
112  return *this;
113  }
114 
116  Optional& operator=(Type&& t) {
117  if (!used) {
118  storage.emplace(std::forward<Type>(t));
119  used = true;
120  } else {
121  value() = std::forward<Type>(t);
122  }
123  return *this;
124  }
125 
129  Optional& operator=(const Optional& other) {
130  if (!other) {
131  destroy();
132  } else {
133  if (!used) {
134  storage.emplace(other.value());
135  used = true;
136  } else {
137  value() = other.value();
138  }
139  }
140  return *this;
141  }
142 
147  if (!other.used) {
148  destroy();
149  } else {
150  if (!used) {
151  storage.emplace(std::move(other.value()));
152  used = true;
153  } else {
154  value() = std::move(other.value());
155  }
156  }
157  return *this;
158  }
159 
162  if (used) {
163  destroy();
164  }
165  used = false;
166  return *this;
167  }
168 
172  INLINE Type& value() {
173  SPH_ASSERT(used);
174  return storage;
175  }
176 
180  INLINE const Type& value() const {
181  SPH_ASSERT(used);
182  return storage;
183  }
184 
187  template <typename TOther>
188  INLINE Type valueOr(const TOther& other) const {
189  if (used) {
190  return storage;
191  } else {
192  return other;
193  }
194  }
195 
198  template <typename TException, typename... TArgs>
199  INLINE Type valueOrThrow(TArgs&&... args) {
200  if (used) {
201  return storage;
202  } else {
203  throw TException(std::forward<TArgs>(args)...);
204  }
205  }
206 
210  INLINE const RawType* operator->() const {
211  SPH_ASSERT(used);
212  return std::addressof(value());
213  }
214 
218  INLINE RawType* operator->() {
219  SPH_ASSERT(used);
220  return std::addressof(value());
221  }
222 
224  INLINE explicit operator bool() const {
225  return used;
226  }
227 
229  INLINE bool operator!() const {
230  return !used;
231  }
232 };
233 
234 template <typename T1, typename T2>
236  if (!opt) {
237  return NOTHING;
238  }
239  return Optional<T1>(T1(opt.value()));
240 }
241 
242 template <typename T>
243 bool operator==(const Optional<T>& opt, const T& t) {
244  if (!opt) {
245  return false;
246  }
247  return opt.value() == t;
248 }
249 
250 template <typename T>
251 bool operator==(const T& t, const Optional<T>& opt) {
252  if (!opt) {
253  return false;
254  }
255  return opt.value() == t;
256 }
257 
259 template <typename T>
260 bool operator==(const Optional<T>& opt1, const Optional<T>& opt2) {
261  if (!opt1 || !opt2) {
262  return false;
263  }
264  return opt1.value() == opt2.value();
265 }
266 
267 
268 template <typename T>
269 bool operator==(const Optional<T>& opt, const NothingType&) {
270  return !opt;
271 }
272 
273 
Base class for utility wrappers (Optional, Variant, ...)
Custom assertions.
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
#define INLINE
Macros for conditional compilation based on selected compiler.
Definition: Object.h:31
#define NAMESPACE_SPH_END
Definition: Object.h:12
bool operator==(const Optional< T > &opt, const T &t)
Definition: Optional.h:243
const NothingType NOTHING
Definition: Optional.h:16
Optional< T1 > optionalCast(const Optional< T2 > &opt)
Definition: Optional.h:235
Few non-standard type traits.
Simple block of memory on stack with size and alignment given by template type.
INLINE void emplace(TArgs &&... rest)
INLINE void destroy()
Wrapper of type value of which may or may not be present.
Definition: Optional.h:23
Optional & operator=(const Optional &other)
Copies the value of another optional object.
Definition: Optional.h:129
INLINE Type & value()
Returns the reference to the stored value.
Definition: Optional.h:172
Optional & operator=(Type &&t)
Moves the value on right-hand side, initializing the optional if necessary.
Definition: Optional.h:116
Optional(const Optional &other)
Copy constructor from other optional.
Definition: Optional.h:63
Optional & operator=(const NothingType &)
Destroys the stored value, provided the object has been initialized.
Definition: Optional.h:161
INLINE const RawType * operator->() const
Used to access members of the stored value.
Definition: Optional.h:210
INLINE RawType * operator->()
Used to access members of the stored value.
Definition: Optional.h:218
Optional(const NothingType &)
Construct uninitialized value.
Definition: Optional.h:83
Optional()=default
Creates an uninitialized value.
Optional(Optional &&other)
Move constructor from other optional.
Definition: Optional.h:74
INLINE Type valueOr(const TOther &other) const
Returns the stored value if the object has been initialized, otherwise returns provided parameter.
Definition: Optional.h:188
Optional & operator=(const T &t)
Copies the value on right-hand side, initializing the optional if necessary.
Definition: Optional.h:105
~Optional()
Definition: Optional.h:87
INLINE bool operator!() const
Returns true if the object is uninitialized.
Definition: Optional.h:229
INLINE const Type & value() const
Returns the const reference to the stored value.
Definition: Optional.h:180
Optional & operator=(Optional &&other)
Moves the value of another optional object.
Definition: Optional.h:146
Optional(const T &t)
Copy constuctor from stored value.
Definition: Optional.h:46
Optional(Type &&t)
Move constuctor from stored value.
Definition: Optional.h:54
void emplace(TArgs &&... args)
Constructs the uninitialized object from a list of arguments.
Definition: Optional.h:95
INLINE Type valueOrThrow(TArgs &&... args)
Returns the stored value if the object has been initialized, otherwise throws an exception,...
Definition: Optional.h:199