dune-common  2.6-git
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 #else
26  // In case of C++ standard < 17 we take the fallback implementation
27 
28  // nullopt
29  // -------
30 
31  struct nullopt_t {};
32 
33  namespace
34  {
35 
36  const nullopt_t nullopt = {};
37 
38  } // anonymous namespace
39 
40 
41 
42  // in_place
43  // --------
44 
45  struct in_place_t {};
46 
47  namespace
48  {
49 
50  const in_place_t in_place = {};
51 
52  } // anonymous namespace
53 
54 
55 
56 
57  // bad_optional_access
58  // -------------------
59 
61  : public std::logic_error
62  {
63  public:
64  explicit bad_optional_access ( const std::string &what ) : std::logic_error( what ) {}
65  explicit bad_optional_access ( const char *what ) : std::logic_error( what ) {}
66  };
67 
68 
69 
70 
71  // optional
72  // --------
73 
77  template< class T >
78  class optional
79  {
80  public:
82  typedef T value_type;
83 
89  constexpr optional () noexcept : engaged_( false ) {}
90 
91  constexpr optional ( nullopt_t ) noexcept : engaged_( false ) {}
92 
93  template< class U = value_type,
94  std::enable_if_t< std::is_constructible< value_type, U&& >::value, int > = 0,
95  std::enable_if_t< !std::is_convertible< U&&, value_type >::value, int > = 0 >
96  explicit constexpr optional ( U && value )
97  : engaged_( true ), value_( std::forward< U >( value ) )
98  {}
99 
100  template< class U = value_type,
101  std::enable_if_t< std::is_constructible< value_type, U&& >::value, int > = 0,
102  std::enable_if_t< std::is_convertible< U&&, value_type >::value, int > = 0 >
103  constexpr optional ( U && value )
104  : engaged_( true ), value_( std::forward< U >( value ) )
105  {}
106 
107  optional ( const value_type &value ) : engaged_( true ), value_( value ) {}
108  optional ( value_type &&value ) : engaged_( true ), value_( std::move( value ) ) {}
109 
110  template< class... Args >
111  explicit constexpr optional ( in_place_t, Args &&... args )
112  : engaged_( true ), value_( std::forward< Args >( args )... )
113  {}
114 
122  optional ( const optional &other ) noexcept( std::is_nothrow_copy_constructible< T >::value )
123  : engaged_( other.engaged_ )
124  {
125  if( engaged_ )
126  new( &value_ ) value_type( other.value_ );
127  }
128 
129  optional ( optional &&other ) noexcept( std::is_nothrow_move_constructible< T >::value )
130  : engaged_( other.engaged_ )
131  {
132  if( engaged_ )
133  new( &value_ ) value_type( std::move( other.value_ ) );
134  }
135 
136  template< class U,
137  std::enable_if_t< std::is_constructible< value_type, const U& >::value, int > = 0,
138  std::enable_if_t< !std::is_constructible< value_type, optional< U >& >::value, int > = 0,
139  std::enable_if_t< !std::is_constructible< value_type, const optional< U >& >::value, int > = 0,
140  std::enable_if_t< !std::is_constructible< value_type, optional< U >&& >::value, int > = 0,
141  std::enable_if_t< !std::is_constructible< optional< U >&, value_type >::value, int > = 0,
142  std::enable_if_t< !std::is_constructible< const optional< U >&, value_type >::value, int > = 0,
143  std::enable_if_t< !std::is_constructible< optional< U >&&, value_type >::value, int > = 0,
144  std::enable_if_t< !std::is_convertible< const U&, value_type >::value, int > = 0 >
145  explicit optional ( const optional< U > &other )
146  : engaged_( other.engaged_ )
147  {
148  if( engaged_ )
149  new( &value_ ) value_type( other.value_ );
150  }
151 
152  template< class U,
153  std::enable_if_t< std::is_constructible< value_type, const 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< value_type, const optional< U >& >::value, int > = 0,
156  std::enable_if_t< !std::is_constructible< value_type, optional< U >&& >::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_constructible< const optional< U >&, value_type >::value, int > = 0,
159  std::enable_if_t< !std::is_constructible< optional< U >&&, value_type >::value, int > = 0,
160  std::enable_if_t< std::is_convertible< const U&, value_type >::value, int > = 0 >
161  optional ( const optional< U > &other )
162  : engaged_( other.engaged_ )
163  {
164  if( engaged_ )
165  new( &value_ ) value_type( other.value_ );
166  }
167 
168  template< class U,
169  std::enable_if_t< std::is_constructible< value_type, const 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< value_type, const optional< U >& >::value, int > = 0,
172  std::enable_if_t< !std::is_constructible< value_type, optional< U >&& >::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_constructible< const optional< U >&, value_type >::value, int > = 0,
175  std::enable_if_t< !std::is_constructible< optional< U >&&, value_type >::value, int > = 0,
176  std::enable_if_t< !std::is_convertible< const U&, value_type >::value, int > = 0 >
177  explicit optional ( optional< U > &&other )
178  : engaged_( other.engaged_ )
179  {
180  if( engaged_ )
181  new( &value_ ) value_type( std::move( other.value_ ) );
182  }
183 
184  template< class U,
185  std::enable_if_t< std::is_constructible< value_type, const 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< value_type, const optional< U >& >::value, int > = 0,
188  std::enable_if_t< !std::is_constructible< value_type, optional< U >&& >::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_constructible< const optional< U >&, value_type >::value, int > = 0,
191  std::enable_if_t< !std::is_constructible< optional< U >&&, value_type >::value, int > = 0,
192  std::enable_if_t< std::is_convertible< const U&, value_type >::value, int > = 0 >
194  : engaged_( other.engaged_ )
195  {
196  if( engaged_ )
197  new( &value_ ) value_type( std::move( other.value_ ) );
198  }
199 
200  optional &operator= ( nullopt_t ) noexcept
201  {
202  if( engaged_ )
203  value_.~value_type();
204  engaged_ = false;
205  return *this;
206  }
207 
208  optional &operator= ( const optional &other ) noexcept( std::is_nothrow_copy_constructible< T >::value && std::is_nothrow_copy_assignable< T >::value )
209  {
210  if( engaged_ )
211  {
212  if( other.engaged_ )
213  value_ = other.value_;
214  else
215  value_.~value_type();
216  }
217  else if( other.engaged_ )
218  new( &value_ ) value_type( other.value_ );
219  engaged_ = other.engaged_;
220  return *this;
221  }
222 
223  optional &operator= ( optional &&other ) noexcept( std::is_nothrow_move_constructible< T >::value && std::is_nothrow_move_assignable< T >::value )
224  {
225  if( engaged_ )
226  {
227  if( other.engaged_ )
228  value_ = std::move( other.value_ );
229  else
230  value_.~value_type();
231  }
232  else if( other.engaged_ )
233  new( &value_ ) value_type( std::move( other.value_ ) );
234  engaged_ = other.engaged_;
235  return *this;
236  }
237 
238  template< class U = value_type >
239  typename std::enable_if< std::is_constructible< value_type, U >::value && std::is_assignable< value_type, U >::value, optional & >::type
240  operator= ( U &&value )
241  {
242  if( engaged_ )
243  value_ = std::move( value );
244  else
245  new( &value_ ) value_type( std::forward< U >( value ) );
246  engaged_ = true;
247  return *this;
248  }
249 
253  {
254  if( engaged_ )
255  value_.~value_type();
256  }
257 
264  explicit constexpr operator bool () const noexcept { return engaged_; }
265 
267  const value_type &operator* () const noexcept { assert( engaged_ ); return value_; }
269  value_type &operator* () noexcept { assert( engaged_ ); return value_; }
270 
272  const value_type *operator->() const noexcept { assert( engaged_ ); return &value_; }
274  value_type *operator->() noexcept { assert( engaged_ ); return &value_; }
275 
276  const value_type &value () const
277  {
278  if( engaged_ )
279  return value_;
280  else
281  throw bad_optional_access( "Cannot access value of disengaged optional." );
282  }
283 
284  value_type &value ()
285  {
286  if( engaged_ )
287  return value_;
288  else
289  throw bad_optional_access( "Cannot access value of disengaged optional." );
290  }
291 
292  template< class U >
293  value_type value_or ( U &&value ) const
294  {
295  return (engaged_ ? value_ : static_cast< value_type >( std::forward< U >( value ) ));
296  }
297 
305  template< class... Args >
306  void emplace ( Args &&... args )
307  {
308  *this = nullopt;
309  // note: At this point, the optional is disengaged. If the following
310  // constructor throws, the object is left in a disengaged state.
311  new( &value_ ) value_type( std::forward< Args >( args )... );
312  engaged_ = true;
313  }
314 
315  void reset () noexcept
316  {
317  if( engaged_)
318  {
319  value_.~value_type();
320  engaged_ = false;
321  }
322  }
323 
324  void swap ( optional &other ) noexcept( std::is_nothrow_move_constructible< T >::value && noexcept( std::swap( std::declval< T & >(), std::declval< T & >() ) ) )
325  {
326  std::swap( engaged_, other.engaged_ );
327  if( engaged_)
328  {
329  if( other.engaged_ )
330  std::swap( value_, other.value_ );
331  else
332  {
333  new( &value_ ) value_type( std::move( other.value_ ) );
334  other.value_.~value_type();
335  }
336  }
337  else if( other.engaged_ )
338  {
339  new( &other.value_ ) value_type( std::move( value_ ) );
340  value_.~value_type();
341  }
342  }
343 
346  private:
347  bool engaged_;
348  union { value_type value_; };
349  };
350 
351 
352 
353  // Relatonal Operators for optional
354  // --------------------------------
355 
356  template< class T >
357  inline static constexpr bool operator== ( const optional< T > &lhs, const optional< T > &rhs )
358  {
359  return (lhs && rhs ? *lhs == *rhs : static_cast< bool >( lhs ) == static_cast< bool >( rhs ));
360  }
361 
362 
363  template< class T >
364  inline static constexpr bool operator< ( const optional< T > &lhs, const optional< T > &rhs )
365  {
366  return (rhs && (lhs ? std::less< T >()( *lhs, *rhs ) : true));
367  }
368 
369 
370  template< class T >
371  inline static constexpr bool operator== ( const optional< T > &lhs, nullopt_t ) noexcept
372  {
373  return !lhs;
374  }
375 
376  template< class T >
377  inline static constexpr bool operator== ( nullopt_t, const optional< T > &rhs ) noexcept
378  {
379  return !rhs;
380  }
381 
382  template< class T >
383  inline static constexpr bool operator< ( const optional< T > &lhs, nullopt_t ) noexcept
384  {
385  return false;
386  }
387 
388  template< class T >
389  inline static constexpr bool operator< ( nullopt_t, const optional< T > &rhs ) noexcept
390  {
391  return static_cast< bool >( rhs );
392  }
393 
394  template< class T >
395  inline static constexpr bool operator== ( const optional< T > &lhs, const T &rhs )
396  {
397  return (lhs && (*lhs == rhs));
398  }
399 
400  template< class T >
401  inline static constexpr bool operator== ( const T &lhs, const optional< T > &rhs )
402  {
403  return (rhs && (lhs == *rhs));
404  }
405 
406  template< class T >
407  inline static constexpr bool operator< ( const optional< T > &lhs, const T &rhs )
408  {
409  return (lhs ? std::less< T >()( *lhs, rhs ) : true);
410  }
411 
412  template< class T >
413  inline static constexpr bool operator< ( const T &lhs, const optional< T > &rhs )
414  {
415  return (rhs ? std::less< T >()( lhs, *rhs ) : false);
416  }
417 
418 
419 
420  // make_optional
421  // -------------
422 
423  template< class T >
424  inline static constexpr optional< typename std::decay< T >::type > make_optional ( T &&value )
425  {
426  return optional< typename std::decay< T >::type >( std::forward< T >( value ) );
427  }
428 
429 #endif //#ifdef DUNE_HAVE_CXX_OPTIONAL
430 
431  } // namespace Std
432 
433 } // namespace Dune
434 
435 
436 #ifndef DUNE_HAVE_CXX_OPTIONAL
437 namespace std
438 {
439 
440  // swap for optional
441  // -----------------
442 
443  template< class T >
444  inline static void swap ( Dune::Std::optional< T > &lhs, Dune::Std::optional< T > &rhs ) noexcept( noexcept( lhs.swap( rhs ) ) )
445  {
446  lhs.swap( rhs );
447  }
448 
449 
450 
451  // hash for optional
452  // -----------------
453 
454  template< class T >
455  struct hash< Dune::Std::optional< T > >
456  {
457  std::size_t operator() ( const Dune::Std::optional< T > &arg ) const
458  {
459  return (arg ? std::hash< T >()( arg ) : 0);
460  }
461  };
462 
463 } // namespace std
464 
465 #endif //#ifndef DUNE_HAVE_CXX_OPTIONAL
466 
467 #endif // #ifndef DUNE_COMMON_STD_OPTIONAL_HH
const value_type * operator->() const noexcept
pointer operator
Definition: optional.hh:272
void swap(T &v1, T &v2, bool mask)
Definition: simd.hh:446
~optional()
Definition: optional.hh:252
constexpr optional(U &&value)
Definition: optional.hh:96
optional(const optional< U > &other)
Definition: optional.hh:145
void swap(optional &other) noexcept(std::is_nothrow_move_constructible< T >::value &&noexcept(std::swap(std::declval< T & >(), std::declval< T & >())))
Definition: optional.hh:324
constexpr optional() noexcept
Definition: optional.hh:89
optional(const value_type &value)
Definition: optional.hh:107
value_type * operator->() noexcept
pointer operator
Definition: optional.hh:274
Definition: optional.hh:60
optional(const optional &other) noexcept(std::is_nothrow_copy_constructible< T >::value)
Definition: optional.hh:122
const value_type & value() const
Definition: optional.hh:276
Dune namespace.
Definition: alignedallocator.hh:9
value_type & value()
Definition: optional.hh:284
bad_optional_access(const std::string &what)
Definition: optional.hh:64
constexpr optional(nullopt_t) noexcept
Definition: optional.hh:91
value_type value_or(U &&value) const
Definition: optional.hh:293
Definition: optional.hh:45
bad_optional_access(const char *what)
Definition: optional.hh:65
T value_type
type of value
Definition: optional.hh:82
Definition: optional.hh:78
void reset() noexcept
Definition: optional.hh:315
static constexpr optional< typename std::decay< T >::type > make_optional(T &&value)
Definition: optional.hh:424
Definition: optional.hh:31
static constexpr bool operator==(const optional< T > &lhs, const optional< T > &rhs)
Definition: optional.hh:357
value_type value_
Definition: optional.hh:348
constexpr optional(in_place_t, Args &&... args)
Definition: optional.hh:111
STL namespace.
bigunsignedint< k > operator*(const bigunsignedint< k > &x, std::uintmax_t y)
Definition: bigunsignedint.hh:543
optional(optional< U > &&other)
Definition: optional.hh:177
optional(optional &&other) noexcept(std::is_nothrow_move_constructible< T >::value)
Definition: optional.hh:129
void emplace(Args &&... args)
Definition: optional.hh:306
optional(value_type &&value)
Definition: optional.hh:108