Dune Core Modules (2.6.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#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
60 class bad_optional_access
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 >
193 optional ( optional< U > &&other )
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
252 ~optional ()
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
437namespace 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
Dune namespace.
Definition: alignedallocator.hh:10
STL namespace.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)