Dune Core Modules (2.7.0)

optional.hh
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
15namespace 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
72 class bad_optional_access
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 >
207 optional ( optional< U > &&other )
208 : engaged_( other.engaged_ )
209 {
210 if( engaged_ )
211 rawEmplace(std::move(other.value_));
212 }
213
214 optional &operator= ( nullopt_t ) noexcept
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
254 operator= ( U &&value )
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
266 ~optional ()
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
298 value_type &value ()
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
463namespace 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
STL namespace.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)