dune-common  2.7.1
optional.hh
Go to the documentation of this file.
1 #ifndef DUNE_COMMON_STD_OPTIONAL_HH
2 #define DUNE_COMMON_STD_OPTIONAL_HH
3 
4 #include <cassert>
5 #include <functional>
6 #include <stdexcept>
7 #include <type_traits>
8 #include <utility>
9 
10 #ifdef DUNE_HAVE_CXX_OPTIONAL
11 #include <optional>
12 #endif // #ifdef DUNE_HAVE_CXX_OPTIONAL
13 
14 
15 namespace Dune
16 {
17 
18  namespace Std
19  {
20 
21 #ifdef DUNE_HAVE_CXX_OPTIONAL
22  // In case of C++ standard >= 17 we forward optionals into our namespace
23  template< class T >
24  using optional = std::optional< T >;
25 
26  using nullopt_t = std::nullopt_t;
27  using in_place_t = std::in_place_t;
28 
29  namespace
30  {
31  const std::nullopt_t nullopt = std::nullopt;
32  const std::in_place_t in_place = std::in_place;
33  } // anonymous namespace
34 
35  using bad_optional_access = std::bad_optional_access;
36 
37 #else
38  // In case of C++ standard < 17 we take the fallback implementation
39 
40  // nullopt
41  // -------
42 
43  struct nullopt_t {};
44 
45  namespace
46  {
47 
48  const nullopt_t nullopt = {};
49 
50  } // anonymous namespace
51 
52 
53 
54  // in_place
55  // --------
56 
57  struct in_place_t {};
58 
59  namespace
60  {
61 
62  const in_place_t in_place = {};
63 
64  } // anonymous namespace
65 
66 
67 
68 
69  // bad_optional_access
70  // -------------------
71 
73  : public std::logic_error
74  {
75  public:
76  explicit bad_optional_access ( const std::string &what ) : std::logic_error( what ) {}
77  explicit bad_optional_access ( const char *what ) : std::logic_error( what ) {}
78  };
79 
80 
81 
82 
83  // optional
84  // --------
85 
89  template< class T >
90  class optional
91  {
92  public:
94  typedef T value_type;
95 
101  constexpr optional () noexcept : engaged_( false ) {}
102 
103  constexpr optional ( nullopt_t ) noexcept : engaged_( false ) {}
104 
105  template< class U = value_type,
106  std::enable_if_t< std::is_constructible< value_type, U&& >::value, int > = 0,
107  std::enable_if_t< !std::is_convertible< U&&, value_type >::value, int > = 0 >
108  explicit constexpr optional ( U && value )
109  : engaged_( true ), value_( std::forward< U >( value ) )
110  {}
111 
112  template< class U = value_type,
113  std::enable_if_t< std::is_constructible< value_type, U&& >::value, int > = 0,
114  std::enable_if_t< not(std::is_same<std::decay_t<U>, optional<value_type>>::value), int > = 0,
115  std::enable_if_t< not(std::is_same<std::decay_t<U>, in_place_t>::value), int > = 0
116  >
117  constexpr optional ( U && value )
118  : engaged_( true ), value_( std::forward< U >( value ) )
119  {}
120 
121  optional ( const value_type &value ) : engaged_( true ), value_( value ) {}
122  optional ( value_type &&value ) : engaged_( true ), value_( std::move( value ) ) {}
123 
124  template< class... Args >
125  explicit constexpr optional ( in_place_t, Args &&... args )
126  : engaged_( true ), value_( std::forward< Args >( args )... )
127  {}
128 
136  optional ( const optional &other ) noexcept( std::is_nothrow_copy_constructible< T >::value )
137  : engaged_( other.engaged_ )
138  {
139  if( engaged_ )
140  rawEmplace(other.value_);
141  }
142 
143  optional ( optional &&other ) noexcept( std::is_nothrow_move_constructible< T >::value )
144  : engaged_( other.engaged_ )
145  {
146  if( engaged_ )
147  rawEmplace(std::move( other.value_ ));
148  }
149 
150  template< class U,
151  std::enable_if_t< std::is_constructible< value_type, const U& >::value, int > = 0,
152  std::enable_if_t< !std::is_constructible< value_type, optional< U >& >::value, int > = 0,
153  std::enable_if_t< !std::is_constructible< value_type, const optional< U >& >::value, int > = 0,
154  std::enable_if_t< !std::is_constructible< value_type, optional< U >&& >::value, int > = 0,
155  std::enable_if_t< !std::is_constructible< optional< U >&, value_type >::value, int > = 0,
156  std::enable_if_t< !std::is_constructible< const optional< U >&, value_type >::value, int > = 0,
157  std::enable_if_t< !std::is_constructible< optional< U >&&, value_type >::value, int > = 0,
158  std::enable_if_t< !std::is_convertible< const U&, value_type >::value, int > = 0 >
159  explicit optional ( const optional< U > &other )
160  : engaged_( other.engaged_ )
161  {
162  if( engaged_ )
163  rawEmplace(other.value_);
164  }
165 
166  template< class U,
167  std::enable_if_t< std::is_constructible< value_type, const U& >::value, int > = 0,
168  std::enable_if_t< !std::is_constructible< value_type, optional< U >& >::value, int > = 0,
169  std::enable_if_t< !std::is_constructible< value_type, const optional< U >& >::value, int > = 0,
170  std::enable_if_t< !std::is_constructible< value_type, optional< U >&& >::value, int > = 0,
171  std::enable_if_t< !std::is_constructible< optional< U >&, value_type >::value, int > = 0,
172  std::enable_if_t< !std::is_constructible< const optional< U >&, value_type >::value, int > = 0,
173  std::enable_if_t< !std::is_constructible< optional< U >&&, value_type >::value, int > = 0,
174  std::enable_if_t< std::is_convertible< const U&, value_type >::value, int > = 0 >
175  optional ( const optional< U > &other )
176  : engaged_( other.engaged_ )
177  {
178  if( engaged_ )
179  rawEmplace(other.value_);
180  }
181 
182  template< class U,
183  std::enable_if_t< std::is_constructible< value_type, const U& >::value, int > = 0,
184  std::enable_if_t< !std::is_constructible< value_type, optional< U >& >::value, int > = 0,
185  std::enable_if_t< !std::is_constructible< value_type, const optional< U >& >::value, int > = 0,
186  std::enable_if_t< !std::is_constructible< value_type, optional< U >&& >::value, int > = 0,
187  std::enable_if_t< !std::is_constructible< optional< U >&, value_type >::value, int > = 0,
188  std::enable_if_t< !std::is_constructible< const optional< U >&, value_type >::value, int > = 0,
189  std::enable_if_t< !std::is_constructible< optional< U >&&, value_type >::value, int > = 0,
190  std::enable_if_t< !std::is_convertible< const U&, value_type >::value, int > = 0 >
191  explicit optional ( optional< U > &&other )
192  : engaged_( other.engaged_ )
193  {
194  if( engaged_ )
195  rawEmplace(std::move(other.value_));
196  }
197 
198  template< class U,
199  std::enable_if_t< std::is_constructible< value_type, const U& >::value, int > = 0,
200  std::enable_if_t< !std::is_constructible< value_type, optional< U >& >::value, int > = 0,
201  std::enable_if_t< !std::is_constructible< value_type, const optional< U >& >::value, int > = 0,
202  std::enable_if_t< !std::is_constructible< value_type, optional< U >&& >::value, int > = 0,
203  std::enable_if_t< !std::is_constructible< optional< U >&, value_type >::value, int > = 0,
204  std::enable_if_t< !std::is_constructible< const optional< U >&, value_type >::value, int > = 0,
205  std::enable_if_t< !std::is_constructible< optional< U >&&, value_type >::value, int > = 0,
206  std::enable_if_t< std::is_convertible< const U&, value_type >::value, int > = 0 >
208  : engaged_( other.engaged_ )
209  {
210  if( engaged_ )
211  rawEmplace(std::move(other.value_));
212  }
213 
215  {
216  if( engaged_ )
217  value_.~value_type();
218  engaged_ = false;
219  return *this;
220  }
221 
222  optional &operator= ( const optional &other ) noexcept( std::is_nothrow_copy_constructible< T >::value && std::is_nothrow_copy_assignable< T >::value )
223  {
224  if( engaged_ )
225  {
226  if( other.engaged_ )
227  value_ = other.value_;
228  else
229  value_.~value_type();
230  }
231  else if( other.engaged_ )
232  rawEmplace(other.value_);
233  engaged_ = other.engaged_;
234  return *this;
235  }
236 
237  optional &operator= ( optional &&other ) noexcept( std::is_nothrow_move_constructible< T >::value && std::is_nothrow_move_assignable< T >::value )
238  {
239  if( engaged_ )
240  {
241  if( other.engaged_ )
242  value_ = std::move( other.value_ );
243  else
244  value_.~value_type();
245  }
246  else if( other.engaged_ )
247  rawEmplace(std::move(other.value_));
248  engaged_ = other.engaged_;
249  return *this;
250  }
251 
252  template< class U = value_type >
253  typename std::enable_if< std::is_constructible< value_type, U >::value && std::is_assignable< value_type, U >::value, optional & >::type
255  {
256  if( engaged_ )
257  value_ = std::forward<U>( value );
258  else
259  rawEmplace(std::forward<U>(value));
260  engaged_ = true;
261  return *this;
262  }
263 
267  {
268  if( engaged_ )
269  value_.~value_type();
270  }
271 
278  explicit constexpr operator bool () const noexcept { return engaged_; }
279 
281  const value_type &operator* () const noexcept { assert( engaged_ ); return value_; }
283  value_type &operator* () noexcept { assert( engaged_ ); return value_; }
284 
286  const value_type *operator->() const noexcept { assert( engaged_ ); return &value_; }
288  value_type *operator->() noexcept { assert( engaged_ ); return &value_; }
289 
290  const value_type &value () const
291  {
292  if( engaged_ )
293  return value_;
294  else
295  throw bad_optional_access( "Cannot access value of disengaged optional." );
296  }
297 
299  {
300  if( engaged_ )
301  return value_;
302  else
303  throw bad_optional_access( "Cannot access value of disengaged optional." );
304  }
305 
306  template< class U >
307  value_type value_or ( U &&value ) const
308  {
309  return (engaged_ ? value_ : static_cast< value_type >( std::forward< U >( value ) ));
310  }
311 
319  template< class... Args >
320  void emplace ( Args &&... args )
321  {
322  *this = nullopt;
323  // note: At this point, the optional is disengaged. If the following
324  // constructor throws, the object is left in a disengaged state.
325  rawEmplace(std::forward<Args>(args)...);
326  engaged_ = true;
327  }
328 
329  void reset () noexcept
330  {
331  if( engaged_)
332  {
333  value_.~value_type();
334  engaged_ = false;
335  }
336  }
337 
338  void swap ( optional &other ) noexcept( std::is_nothrow_move_constructible< T >::value && noexcept( std::swap( std::declval< T & >(), std::declval< T & >() ) ) )
339  {
340  std::swap( engaged_, other.engaged_ );
341  if( engaged_)
342  {
343  if( other.engaged_ )
344  std::swap( value_, other.value_ );
345  else
346  {
347  rawEmplace( std::move( other.value_ ) );
348  other.value_.~value_type();
349  }
350  }
351  else if( other.engaged_ )
352  {
353  other.rawEmplace( std::move( value_ ) );
354  value_.~value_type();
355  }
356  }
357 
360  private:
361 
362  // Construct value using placement new. This is needed
363  // for all assignments and conditional constructions
364  // whenever the original object cannot be assigned.
365  template<class... Args>
366  void rawEmplace(Args&&... args)
367  {
368  // To access the raw storage we need to cast away constness first.
369  // Otherwise placement new is not allowed.
370  new( const_cast<std::remove_const_t<value_type>*>(&value_) ) value_type( std::forward< Args >( args )... );
371  }
372 
373  bool engaged_;
374  union { value_type value_; };
375  };
376 
377 
378 
379  // Relatonal Operators for optional
380  // --------------------------------
381 
382  template< class T >
383  inline static constexpr bool operator== ( const optional< T > &lhs, const optional< T > &rhs )
384  {
385  return (lhs && rhs ? *lhs == *rhs : static_cast< bool >( lhs ) == static_cast< bool >( rhs ));
386  }
387 
388 
389  template< class T >
390  inline static constexpr bool operator< ( const optional< T > &lhs, const optional< T > &rhs )
391  {
392  return (rhs && (lhs ? std::less< T >()( *lhs, *rhs ) : true));
393  }
394 
395 
396  template< class T >
397  inline static constexpr bool operator== ( const optional< T > &lhs, nullopt_t ) noexcept
398  {
399  return !lhs;
400  }
401 
402  template< class T >
403  inline static constexpr bool operator== ( nullopt_t, const optional< T > &rhs ) noexcept
404  {
405  return !rhs;
406  }
407 
408  template< class T >
409  inline static constexpr bool operator< ( const optional< T > &lhs, nullopt_t ) noexcept
410  {
411  return false;
412  }
413 
414  template< class T >
415  inline static constexpr bool operator< ( nullopt_t, const optional< T > &rhs ) noexcept
416  {
417  return static_cast< bool >( rhs );
418  }
419 
420  template< class T >
421  inline static constexpr bool operator== ( const optional< T > &lhs, const T &rhs )
422  {
423  return (lhs && (*lhs == rhs));
424  }
425 
426  template< class T >
427  inline static constexpr bool operator== ( const T &lhs, const optional< T > &rhs )
428  {
429  return (rhs && (lhs == *rhs));
430  }
431 
432  template< class T >
433  inline static constexpr bool operator< ( const optional< T > &lhs, const T &rhs )
434  {
435  return (lhs ? std::less< T >()( *lhs, rhs ) : true);
436  }
437 
438  template< class T >
439  inline static constexpr bool operator< ( const T &lhs, const optional< T > &rhs )
440  {
441  return (rhs ? std::less< T >()( lhs, *rhs ) : false);
442  }
443 
444 
445 
446  // make_optional
447  // -------------
448 
449  template< class T >
450  inline static constexpr optional< typename std::decay< T >::type > make_optional ( T &&value )
451  {
452  return optional< typename std::decay< T >::type >( std::forward< T >( value ) );
453  }
454 
455 #endif //#ifdef DUNE_HAVE_CXX_OPTIONAL
456 
457  } // namespace Std
458 
459 } // namespace Dune
460 
461 
462 #ifndef DUNE_HAVE_CXX_OPTIONAL
463 namespace std
464 {
465 
466  // swap for optional
467  // -----------------
468 
469  template< class T >
470  inline static void swap ( Dune::Std::optional< T > &lhs, Dune::Std::optional< T > &rhs ) noexcept( noexcept( lhs.swap( rhs ) ) )
471  {
472  lhs.swap( rhs );
473  }
474 
475 
476 
477  // hash for optional
478  // -----------------
479 
480  template< class T >
481  struct hash< Dune::Std::optional< T > >
482  {
483  std::size_t operator() ( const Dune::Std::optional< T > &arg ) const
484  {
485  return (arg ? std::hash< T >()( arg ) : 0);
486  }
487  };
488 
489 } // namespace std
490 
491 #endif //#ifndef DUNE_HAVE_CXX_OPTIONAL
492 
493 #endif // #ifndef DUNE_COMMON_STD_OPTIONAL_HH
Dune namespace.
Definition: alignedallocator.hh:14
static constexpr bool operator<(const optional< T > &lhs, const optional< T > &rhs)
Definition: optional.hh:390
static constexpr bool operator==(const optional< T > &lhs, const optional< T > &rhs)
Definition: optional.hh:383
static constexpr optional< typename std::decay< T >::type > make_optional(T &&value)
Definition: optional.hh:450
Definition: optional.hh:43
Definition: optional.hh:57
Definition: optional.hh:74
bad_optional_access(const char *what)
Definition: optional.hh:77
bad_optional_access(const std::string &what)
Definition: optional.hh:76
Definition: optional.hh:91
void emplace(Args &&... args)
Definition: optional.hh:320
constexpr optional(U &&value)
Definition: optional.hh:108
const value_type * operator->() const noexcept
pointer operator
Definition: optional.hh:286
optional(value_type &&value)
Definition: optional.hh:122
optional(const optional &other) noexcept(std::is_nothrow_copy_constructible< T >::value)
Definition: optional.hh:136
constexpr optional(nullopt_t) noexcept
Definition: optional.hh:103
value_type value_
Definition: optional.hh:374
optional & operator=(nullopt_t) noexcept
Definition: optional.hh:214
optional(const value_type &value)
Definition: optional.hh:121
constexpr optional(in_place_t, Args &&... args)
Definition: optional.hh:125
value_type & value()
Definition: optional.hh:298
optional(optional &&other) noexcept(std::is_nothrow_move_constructible< T >::value)
Definition: optional.hh:143
value_type * operator->() noexcept
pointer operator
Definition: optional.hh:288
~optional()
Definition: optional.hh:266
void reset() noexcept
Definition: optional.hh:329
value_type value_or(U &&value) const
Definition: optional.hh:307
T value_type
type of value
Definition: optional.hh:94
const value_type & value() const
Definition: optional.hh:290
void swap(optional &other) noexcept(std::is_nothrow_move_constructible< T >::value &&noexcept(std::swap(std::declval< T & >(), std::declval< T & >())))
Definition: optional.hh:338
const value_type & operator*() const noexcept
dereference pointer
Definition: optional.hh:281
constexpr optional(U &&value)
Definition: optional.hh:117
optional(optional< U > &&other)
Definition: optional.hh:191
constexpr optional() noexcept
Definition: optional.hh:101
optional(const optional< U > &other)
Definition: optional.hh:159