Optional.hpp
Go to the documentation of this file.
1 //
3 // Aurora C++ Library
4 // Copyright (c) 2012-2016 Jan Haller
5 //
6 // This software is provided 'as-is', without any express or implied
7 // warranty. In no event will the authors be held liable for any damages
8 // arising from the use of this software.
9 //
10 // Permission is granted to anyone to use this software for any purpose,
11 // including commercial applications, and to alter it and redistribute it
12 // freely, subject to the following restrictions:
13 //
14 // 1. The origin of this software must not be misrepresented; you must not
15 // claim that you wrote the original software. If you use this software
16 // in a product, an acknowledgment in the product documentation would be
17 // appreciated but is not required.
18 //
19 // 2. Altered source versions must be plainly marked as such, and must not be
20 // misrepresented as being the original software.
21 //
22 // 3. This notice may not be removed or altered from any source distribution.
23 //
25 
28 
29 #ifndef AURORA_OPTIONAL_HPP
30 #define AURORA_OPTIONAL_HPP
31 
32 #include <Aurora/Config.hpp>
34 #include <Aurora/Tools/Swap.hpp>
35 
36 #include <type_traits> // std::aligned_storage
37 #include <cassert>
38 #include <new> // placement new (g++ non-conformance, not required by C++ standard)
39 
40 
41 namespace aurora
42 {
43 
46 
60 const struct NulloptType {} nullopt;
61 
66 const struct InplaceType {} inplace;
67 
97 template <typename T>
98 class Optional
99 {
100  // ---------------------------------------------------------------------------------------------------------------------------
101  // Public member functions
102  public:
106  : mFilled(false)
107  {
108  }
109 
113  : mFilled(false)
114  {
115  }
116 
117 #ifdef AURORA_HAS_VARIADIC_TEMPLATES
118 
121  template <typename... Args>
122  explicit Optional(InplaceType, Args&&... args)
123  : mFilled(false)
124  {
125  construct(std::forward<Args>(args)...);
126  }
127 
128 #endif // AURORA_HAS_VARIADIC_TEMPLATES
129 
132  Optional(T object)
133  : mFilled(false)
134  {
135  construct(std::move(object));
136  }
137 
140  Optional(const Optional& origin)
141  : mFilled(false)
142  {
143  if (origin.mFilled)
144  construct(origin.content());
145  }
146 
149  Optional(Optional&& source)
150  : mFilled(false)
151  {
152  if (source.mFilled)
153  {
154  construct(std::move(source.content()));
155  source.destroy();
156  }
157  }
158 
161  Optional& operator= (T object)
162  {
163  Optional(std::move(object)).swap(*this);
164  return *this;
165  }
166 
169  Optional& operator= (const Optional& origin)
170  {
171  Optional(origin).swap(*this);
172  return *this;
173  }
174 
178  {
179  Optional(std::move(source)).swap(*this);
180  return *this;
181  }
182 
186  {
187  if (mFilled)
188  destroy();
189  }
190 
193  void swap(Optional& other)
194  {
195  // TODO: Exception safety in 2nd and 3rd case
196 
197  if (mFilled && other.mFilled)
198  {
199  adlSwap(content(), other.content());
200  }
201  else if (mFilled)
202  {
203  other.construct(std::move(content()));
204  this->destroy();
205  }
206  else if (other.mFilled)
207  {
208  this->construct(std::move(other.content()));
209  other.destroy();
210  }
211  }
212 
216  {
217  return content();
218  }
219 
222  const T& operator* () const
223  {
224  return content();
225  }
226 
230  {
231  return &content();
232  }
233 
236  const T* operator-> () const
237  {
238  return &content();
239  }
240 
243  operator SafeBool() const
244  {
245  return toSafeBool(mFilled);
246  }
247 
248 
249  // ---------------------------------------------------------------------------------------------------------------------------
250  // Private member functions
251  private:
252  T& content()
253  {
254  assert(mFilled);
255  return reinterpret_cast<T&>(mStorage);
256  }
257 
258  const T& content() const
259  {
260  assert(mFilled);
261  return reinterpret_cast<const T&>(mStorage);
262  }
263 
264 #ifdef AURORA_HAS_VARIADIC_TEMPLATES
265 
266  template <typename... Args>
267  void construct(Args&&... args)
268  {
269  // Exception safety: set mFilled only to true after successful construction
270 
271  assert(!mFilled);
272  new (&content()) T(std::forward<Args>(args)...);
273  mFilled = true;
274  }
275 
276 #else
277 
278  void construct(T& source)
279  {
280  assert(!mFilled);
281  new (&content()) T(std::move(source));
282  mFilled = true;
283  }
284 
285 #endif // AURORA_HAS_VARIADIC_TEMPLATES
286 
287  void destroy()
288  {
289  assert(mFilled);
290  content().~T();
291  mFilled = false;
292  }
293 
294  // ---------------------------------------------------------------------------------------------------------------------------
295  // Private variables
296  private:
297  typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type mStorage;
298  bool mFilled;
299 };
300 
303 template <typename T>
304 void swap(Optional<T>& lhs, Optional<T>& rhs)
305 {
306  lhs.swap(rhs);
307 }
308 
309 #ifdef AURORA_HAS_VARIADIC_TEMPLATES
310 
322 template <typename T, typename... Args>
323 Optional<T> makeOptional(Args&&... args)
324 {
325  return Optional<T>(inplace, std::forward<Args>(args)...);
326 }
327 
328 #endif // AURORA_HAS_VARIADIC_TEMPLATES
329 
334 template <typename T>
335 bool operator== (const Optional<T>& lhs, const Optional<T>& rhs)
336 {
337  return !lhs && !rhs
338  || lhs && rhs && *lhs == *rhs;
339 }
340 
344 template <typename T>
345 bool operator!= (const Optional<T>& lhs, const Optional<T>& rhs)
346 {
347  return !(lhs == rhs);
348 }
349 
351 
352 } // namespace aurora
353 
354 #endif // AURORA_OPTIONAL_HPP
T & operator*()
Returns the contained object.
Definition: Optional.hpp:215
Optional(T object)
Construct implicitly from T object (move or copy)
Definition: Optional.hpp:132
Optional(InplaceType, Args &&...args)
Construct object in-place, forwarding arguments.
Definition: Optional.hpp:122
Optional(NulloptType)
Construct empty optional from aurora::nullopt.
Definition: Optional.hpp:112
void(detail::SafeBoolHolder::* SafeBool)()
SafeBool type.
Definition: SafeBool.hpp:55
Optional(const Optional &origin)
Copy constructor.
Definition: Optional.hpp:140
~Optional()
Destructor.
Definition: Optional.hpp:185
Configuration header of the library.
void swap(Optional< T > &lhs, Optional< T > &rhs)
Swaps two optionals.
Definition: Optional.hpp:304
Null literal for optional objects.
Definition: Optional.hpp:60
Optional()
Construct empty optional with default constructor.
Definition: Optional.hpp:105
Tag to construct optional objects in-place.
Definition: Optional.hpp:66
T * operator->()
Returns the contained object for member access.
Definition: Optional.hpp:229
Type aurora::SafeBool and corresponding functionality.
Helpers to declare and invoke swap() functions.
SafeBool toSafeBool(bool condition)
Conversion function from bool to SafeBool.
Definition: SafeBool.hpp:67
void adlSwap(T &lhs, T &rhs)
swap() function with argument-dependent lookup
Definition: Swap.hpp:49
Represents optional values.
Definition: Optional.hpp:98
Optional(Optional &&source)
Move constructor.
Definition: Optional.hpp:149
Optional< T > makeOptional(Args &&...args)
Emplaces an object directly inside the aurora::Optional object.
Definition: Optional.hpp:323
Optional & operator=(T object)
Assign from T object (move or copy)
Definition: Optional.hpp:161
Definition: DispatchTraits.hpp:39
void swap(Optional &other)
Swaps two optional objects.
Definition: Optional.hpp:193