VCCC  2024.05
VisualCamp Common C++ library
optional.h
Go to the documentation of this file.
1 # /*
2 # * Created by YongGyu Lee on 2021/05/23.
3 # */
4 #
5 # ifndef VCCC_OPTIONAL_OPTIONAL_H_
6 # define VCCC_OPTIONAL_OPTIONAL_H_
7 #
8 # include <type_traits>
9 # include <new>
10 # include <utility>
11 #
21 # include "vccc/__optional/swap.h"
26 
27 namespace vccc {
28 
31 
40 template<typename T>
41 class optional :
42  private internal::optional::move_assign<T>,
43  private internal::optional::check_copy_constructible<T>,
44  private internal::optional::check_move_constructible<T>,
45  private internal::optional::check_copy_assignable<T>,
46  private internal::optional::check_move_assignable<T> {
47  using base = internal::optional::move_assign<T>;
48  using base::base;
49 
50  public:
51  using value_type = T;
52 
53  static_assert(!std::is_reference<T>::value,
54  "vccc::optional : T must not be a reference type");
55  static_assert(!std::is_same<std::remove_reference_t<std::decay_t<T>>, nullopt_t>::value,
56  "vccc::optional : T must not be vccc::nullopt_t");
57  static_assert(!std::is_same<std::remove_reference_t<std::decay_t<T>>, in_place_t>::value,
58  "vccc::optional : T must not be vccc::in_place_t");
59  static_assert(std::is_destructible<T>::value,
60  "vccc::optional : T must be destructible");
61  static_assert(!std::is_array<T>::value,
62  "vccc::optional : T must be an array type");
63 
64  // constructors
65 
68  constexpr optional() noexcept = default;
69  constexpr optional(nullopt_t) noexcept {};
70  constexpr optional(const optional& other) = default;
71  constexpr optional(optional&& other) = default;
72 
73  template<typename U,
74  std::enable_if_t<
76  internal::optional::check_constructible<value_type, optional<U>>::value &&
77  internal::optional::check_convertible <value_type, optional<U>>::value,
78  int> = 0>
79  constexpr optional(const optional<U>& other) {
80  this->construct_if(other);
81  }
82 
83  template<typename U,
84  std::enable_if_t<
86  internal::optional::check_constructible<value_type, optional<U>>::value &&
87  internal::optional::check_convertible <value_type, optional<U>>::value &&
89  int> = 0>
90  explicit constexpr optional(const optional<U>& other) {
91  this->construct_if(other);
92  }
93 
94  template<typename U,
95  std::enable_if_t<
97  internal::optional::check_constructible<value_type, optional<U>>::value &&
98  internal::optional::check_convertible <value_type, optional<U>>::value,
99  int> = 0>
100  constexpr optional(optional<U>&& other) {
101  this->construct_if(std::move(other));
102  }
103 
104  template<typename U,
105  std::enable_if_t<
107  internal::optional::check_constructible<value_type, optional<U>>::value &&
108  internal::optional::check_convertible <value_type, optional<U>>::value &&
110  int> = 0>
111  explicit constexpr optional(optional<U>&& other) {
112  this->construct_if(std::move(other));
113  }
114 
115  // Split into 2 overloads to prevent MSVC from making an ambiguous call in C++14
116  template<typename InPlaceT,
117  std::enable_if_t<
120  int> = 0>
121  constexpr explicit optional(InPlaceT)
122  : base(in_place) {}
123 
124  template<typename Arg, typename ...Args,
125  std::enable_if_t<
126  std::is_constructible<value_type, Arg, Args...>::value,
127  int> = 0>
128  constexpr explicit optional(in_place_t, Arg&& arg, Args&&... args)
129  : base(in_place, std::forward<Arg>(arg), std::forward<Args>(args)...) {}
130 
131  template<typename U, typename ...Args,
132  std::enable_if_t<
133  std::is_constructible<value_type, std::initializer_list<U>&, Args&&...>::value,
134  int> = 0>
135  constexpr explicit optional(in_place_t, std::initializer_list<U> ilist, Args&&... args)
136  : base(in_place, ilist, std::forward<Args>(args)...) {}
137 
138  template<typename U = value_type,
139  std::enable_if_t<
142  !std::is_same<internal::optional::strip_t<U>, in_place_t>::value &&
143  !std::is_same<internal::optional::strip_t<U>, optional<value_type>>::value,
144  int> = 0>
145  constexpr optional(U&& value)
146  : base(in_place, std::forward<U>(value)) {}
147 
148  template<typename U = value_type,
149  std::enable_if_t<
152  !std::is_same<internal::optional::strip_t<U>, in_place_t>::value &&
153  !std::is_same<internal::optional::strip_t<U>, optional<value_type>>::value,
154  int> = 0>
155  constexpr explicit optional(U&& value)
156  : base(in_place, std::forward<U>(value)) {}
158 
159  // assignment operators
160 
164  this->reset();
165  return *this;
166  }
167 
168  constexpr optional& operator=(optional const&) = default;
169  constexpr optional& operator=(optional &&) = default;
170 
171  template<typename U,
172  std::enable_if_t<
175  !std::is_same<internal::optional::strip_t<U>, optional>::value) &&
177  !std::is_same<std::decay_t<U>, value_type>::value),
178  int> = 0>
180  if (has_value()) {
181  this->val = std::forward<U>(value);
182  } else {
183  this->construct(std::forward<U>(value));
184  }
185  return *this;
186  }
187 
188  template<typename U,
189  std::enable_if_t<
190  internal::optional::check_constructible<value_type, optional<U>>::value &&
191  internal::optional::check_convertible <value_type, optional<U>>::value &&
192  internal::optional::check_assignable <value_type, optional<U>>::value &&
195  int> = 0>
196  optional& operator=(const optional<U>& other) {
197  if (other.has_value()) {
198  if (this->has_value())
199  this->val = *other;
200  else
201  this->construct(*other);
202  } else { // !other.has_value()
203  if (this->has_value())
204  this->reset();
205  }
206  return *this;
207  }
208 
209  template<typename U,
210  std::enable_if_t<
211  internal::optional::check_constructible<value_type, optional<U>>::value &&
212  internal::optional::check_convertible <value_type, optional<U>>::value &&
213  internal::optional::check_assignable <value_type, optional<U>>::value &&
216  int> = 0>
218  if (other.has_value()) {
219  if (this->has_value())
220  this->val = std::move(*other);
221  else
222  this->construct(std::move(*other));
223  } else { // !other.has_value()
224  if (this->has_value())
225  this->reset();
226  }
227  return *this;
228  }
230 
231 
234  constexpr inline const value_type* operator->() const noexcept { return this->pointer(); }
235  constexpr inline value_type* operator->() noexcept { return this->pointer(); }
237 
240  constexpr inline const value_type& operator*() const& noexcept { return this->ref(); }
241  constexpr inline value_type& operator*() & noexcept { return this->ref(); }
242  constexpr inline const value_type&& operator*() const&& noexcept { return std::move(this->ref()); }
243  constexpr inline value_type&& operator*() && noexcept { return std::move(this->ref()); }
245 
246  constexpr explicit inline operator bool() const noexcept {
247  return this->valid;
248  }
249  constexpr inline bool has_value() const noexcept {
250  return this->valid;
251  }
252 
255  constexpr inline value_type& value() & {
256  if (!this->has_value())
257  throw bad_optional_access{};
258  return this->ref();
259  }
260  constexpr inline const value_type& value() const& {
261  if (!this->has_value())
262  throw bad_optional_access{};
263  return this->ref();
264  }
265  constexpr inline value_type&& value() && {
266  if (!this->has_value())
267  throw bad_optional_access{};
268  return std::move(this->ref());
269  }
270  constexpr inline const value_type&& value() const && {
271  if (!this->has_value())
272  throw bad_optional_access{};
273  return std::move(this->ref());
274  }
276 
279  template<typename U>
280  constexpr value_type value_or(U&& default_value) const & {
282  "vccc::optional<T>::value_or : T must be copy constructible");
284  "vccc::optional<T>::value_or : U&& must be convertible to T");
285 
286  return this->has_value() ? **this : static_cast<value_type>(std::forward<U>(default_value));
287  }
288 
289  template<typename U>
290  constexpr value_type value_or(U&& default_value) && {
292  "vccc::optional<T>::value_or : T must be move constructible");
294  "vccc::optional<T>::value_or : U&& must be convertible to T");
295 
296  return this->has_value() ? std::move(**this) : static_cast<value_type>(std::forward<U>(default_value));
297  }
299 
300 
303  template<typename F, std::enable_if_t<
305  constexpr auto and_then(F&& f) & {
306  if (*this)
307  return vccc::invoke(std::forward<F>(f), **this);
309  }
310 
311  template<typename F, std::enable_if_t<
313  constexpr auto and_then(F&& f) const & {
314  if (*this)
315  return vccc::invoke(std::forward<F>(f), **this);
317  }
318 
319  template<typename F, std::enable_if_t<
321  constexpr auto and_then(F&& f) && {
322  if (*this)
323  return vccc::invoke(std::forward<F>(f), std::move(**this));
325  }
326 
327  template<typename F, std::enable_if_t<
329  constexpr auto and_then(F&& f) const && {
330  if (*this)
331  return vccc::invoke(std::forward<F>(f), std::move(**this));
333  }
335 
336 
340  constexpr auto transform(F&& f) & {
341  using U = std::remove_cv_t<invoke_result_t<F, T&>>;
342  if (*this)
343  return optional<U>(vccc::invoke(std::forward<F>(f), **this));
344  return optional<U>{};
345  }
346 
348  constexpr auto transform(F&& f) const & {
349  using U = std::remove_cv_t<invoke_result_t<F, const T&>>;
350  if (*this)
351  return optional<U>(vccc::invoke(std::forward<F>(f), **this));
352  return optional<U>{};
353  }
354 
356  constexpr auto transform(F&& f) && {
357  using U = std::remove_cv_t<invoke_result_t<F, T>>;
358  if (*this)
359  return optional<U>(vccc::invoke(std::forward<F>(f), std::move(**this)));
360  return optional<U>{};
361  }
362 
364  constexpr auto transform(F&& f) const && {
365  using U = std::remove_cv_t<invoke_result_t<F, const T>>;
366  if (*this)
367  return optional<U>(vccc::invoke(std::forward<F>(f), std::move(**this)));
368  return optional<U>{};
369  }
371 
372 
375  template<typename F, std::enable_if_t<conjunction<
378  >::value, int> = 0>
379  constexpr optional or_else(F&& f) const& {
380  static_assert(std::is_same<remove_cvref_t<invoke_result_t<F>>, optional>::value, "Invalid return type from f");
381  return *this ? *this : std::forward<F>(f)();
382  }
383  template<typename F, std::enable_if_t<conjunction<
384  move_constructible<T>,
386  >::value, int> = 0>
387  constexpr optional or_else(F&& f) && {
388  static_assert(std::is_same<remove_cvref_t<invoke_result_t<F>>, optional>::value, "Invalid return type from f");
389  return *this ? std::move(*this) : std::forward<F>(f)();
390  }
392 
393  void swap(optional& other)
395  {
397  "vccc::optional<T>::swap : T must be move constructible");
398 
399  if (other.has_value()) {
400  if (this->has_value()) {
401  std::swap(**this, *other);
402  } else { // !this->has_value()
403  this->construct(std::move(*other));
404  other.reset();
405  }
406  } else {
407  if (this->has_value()) {
408  other.construct(**this);
409  this->reset();
410  }
411  }
412  }
413 
416  template<typename Dummy = void,
417  std::enable_if_t<
420  int> = 0>
421  value_type& emplace() {
422  this->reset();
423  this->construct();
424  return **this;
425  }
426 
427  template<typename Arg, typename ...Args,
428  std::enable_if_t<
429  std::is_constructible<value_type, Arg, Args...>::value,
430  int> = 0>
431  value_type& emplace(Arg&& arg, Args&&... args) {
432  this->reset();
433  this->construct(std::forward<Arg>(arg), std::forward<Args>(args)...);
434  return **this;
435  }
436 
437  template<typename U, typename ...Args,
438  std::enable_if_t<
439  std::is_constructible<value_type, std::initializer_list<U>&, Args&&...>::value,
440  int> = 0>
441  value_type& emplace(std::initializer_list<U> ilist, Args&&... args) {
442  this->reset();
443  this->construct(ilist, std::forward<Args>(args)...);
444  return **this;
445  }
447 
448  using base::reset;
449 };
450 
451 # if __cplusplus >= 201703
452 template<class T> optional(T) -> optional<T>;
453 # endif
454 
457 
458 template<typename T>
460  return optional<std::decay_t<T>>(std::forward<T>(value));
461 }
462 
463 template<typename T>
464 constexpr inline optional<T> make_optional() {
465  return optional<T>(in_place);
466 }
467 
468 template<typename T, typename Arg, typename ...Args>
469 constexpr inline optional<T> make_optional(Arg&& arg, Args&&... args) {
470  return optional<T>(in_place, std::forward<Arg>(arg), std::forward<Args>(args)...);
471 }
472 
473 template<typename T, typename U, typename ...Args>
474 constexpr inline optional<T> make_optional(std::initializer_list<U> ilist, Args&&... args) {
475  return optional<T>(in_place, ilist, std::forward<Args>(args)...);
476 }
477 
479 
480 // compare two optional objects
481 
484 
485 template<typename T, typename U >
486 constexpr bool operator==(const optional<T>& lhs, const optional<U>& rhs) {
487  if (bool(lhs) != bool(rhs))
488  return false;
489  if (!lhs)
490  return true;
491  return *lhs == *rhs;
492 }
493 
494 template<typename T, typename U >
495 constexpr bool operator!=(const optional<T>& lhs, const optional<U>& rhs) {
496  if (bool(lhs) != bool(rhs))
497  return true;
498  if (!lhs)
499  return false;
500  return lhs != rhs;
501 }
502 
503 template<typename T, typename U >
504 constexpr bool operator<(const optional<T>& lhs, const optional<U>& rhs) {
505  if (!rhs.has_value())
506  return false;
507  if (!lhs.has_value())
508  return true;
509  return *lhs < *rhs;
510 }
511 
512 template<typename T, typename U >
513 constexpr bool operator<=(const optional<T>& lhs, const optional<U>& rhs) {
514  if (!lhs.has_value())
515  return true;
516  if (!rhs.has_value())
517  return false;
518  return *lhs <= *rhs;
519 }
520 
521 template<typename T, typename U >
522 constexpr bool operator>(const optional<T>& lhs, const optional<U>& rhs) {
523  if (!lhs.has_value())
524  return false;
525  if (!rhs.has_value())
526  return true;
527  return *lhs > *rhs;
528 }
529 
530 template<typename T, typename U >
531 constexpr bool operator>=(const optional<T>& lhs, const optional<U>& rhs) {
532  if (!rhs.has_value())
533  return true;
534  if (!lhs.has_value())
535  return false;
536  return *lhs >= *rhs;
537 }
538 
539 
540 // compare an optional object with a nullopt
541 
542 template<typename T>
543 constexpr inline bool operator==(const optional<T>& opt, nullopt_t) noexcept {
544  return !opt;
545 }
546 
547 template<typename T>
548 constexpr inline bool operator==(nullopt_t, const optional<T>& opt) noexcept {
549  return !opt;
550 }
551 
552 template<typename T>
553 constexpr inline bool operator!=(const optional<T>& opt, nullopt_t) noexcept {
554  return bool(opt);
555 }
556 
557 template<typename T>
558 constexpr inline bool operator!=(nullopt_t, const optional<T>& opt) noexcept {
559  return bool(opt);
560 }
561 
562 template<typename T>
563 constexpr inline bool operator<(const optional<T>& opt, nullopt_t) noexcept {
564  return false;
565 }
566 
567 template<typename T>
568 constexpr inline bool operator<(nullopt_t, const optional<T>& opt) noexcept {
569  return bool(opt);
570 }
571 
572 template<typename T>
573 constexpr inline bool operator<=(const optional<T>& opt, nullopt_t) noexcept {
574  return !opt;
575 }
576 
577 template<typename T>
578 constexpr inline bool operator<=(nullopt_t, const optional<T>& opt) noexcept {
579  return true;
580 }
581 
582 template<typename T>
583 constexpr inline bool operator>(const optional<T>& opt, nullopt_t) noexcept {
584  return bool(opt);
585 }
586 
587 template<typename T>
588 constexpr inline bool operator>(nullopt_t, const optional<T>& opt) noexcept {
589  return false;
590 }
591 
592 template<typename T>
593 constexpr inline bool operator>=(const optional<T>& opt, nullopt_t) noexcept {
594  return true;
595 }
596 
597 template<typename T>
598 constexpr inline bool operator>=(nullopt_t, const optional<T>& opt) noexcept {
599  return !opt;
600 }
601 
602 
603 // compare an optional object with a value
604 
605 template<typename T, typename U>
606 constexpr inline bool operator==(const optional<T>& opt, const U& value) {
607  return bool(opt) ? *opt == value : false;
608 }
609 
610 template<typename T, typename U>
611 constexpr inline bool operator==(const T& value, const optional<U>& opt) {
612  return bool(opt) ? value == *opt : false;
613 }
614 
615 template<typename T, typename U>
616 constexpr inline bool operator!=(const optional<T>& opt, const U& value) {
617  return bool(opt) ? opt != value : true;
618 }
619 
620 template<typename T, typename U>
621 constexpr inline bool operator!=(const T& value, const optional<U>& opt) {
622  return bool(opt) ? value != opt : true;
623 }
624 
625 template<typename T, typename U>
626 constexpr inline bool operator<(const optional<T>& opt, const U& value) {
627  return bool(opt) ? opt < value : true;
628 }
629 
630 template<typename T, typename U>
631 constexpr inline bool operator<(const T& value, const optional<U>& opt) {
632  return bool(opt) ? value < opt : false;
633 }
634 
635 template<typename T, typename U>
636 constexpr inline bool operator<=(const optional<T>& opt, const U& value) {
637  return bool(opt) ? opt <= value : true;
638 }
639 
640 template<typename T, typename U>
641 constexpr inline bool operator<=(const T& value, const optional<U>& opt) {
642  return bool(opt) ? value <= opt : false;
643 }
644 
645 template<typename T, typename U>
646 constexpr inline bool operator>(const optional<T>& opt, const U& value) {
647  return bool(opt) ? opt > value : false;
648 }
649 
650 template<typename T, typename U>
651 constexpr inline bool operator>(const T& value, const optional<U>& opt) {
652  return bool(opt) ? value > opt : true;
653 }
654 
655 template<typename T, typename U>
656 constexpr inline bool operator>=(const optional<T>& opt, const U& value) {
657  return bool(opt) ? opt >= value : false;
658 }
659 
660 template<typename T, typename U>
661 constexpr inline bool operator>=(const T& value, const optional<U>& opt) {
662  return bool(opt) ? value >= opt : true;
663 }
664 
666 
668 
669 } // namespace vccc
670 
671 # endif // VCCC_OPTIONAL_OPTIONAL_H_
exception indicating checked access to an optional that doesn't contain a value
Definition: bad_optional_access.h:18
a wrapper that may or may not hold an object
Definition: optional.h:46
constexpr auto and_then(F &&f) const &&
Definition: optional.h:329
constexpr value_type & operator*() &noexcept
Definition: optional.h:241
constexpr value_type value_or(U &&default_value) const &
Definition: optional.h:280
constexpr optional(optional< U > &&other)
Definition: optional.h:100
constexpr optional(in_place_t, std::initializer_list< U > ilist, Args &&... args)
Definition: optional.h:135
constexpr auto and_then(F &&f) const &
Definition: optional.h:313
constexpr value_type * operator->() noexcept
Definition: optional.h:235
constexpr value_type && operator*() &&noexcept
Definition: optional.h:243
value_type & emplace()
Definition: optional.h:421
constexpr auto and_then(F &&f) &
Definition: optional.h:305
constexpr auto transform(F &&f) &
Definition: optional.h:340
constexpr const value_type & operator*() const &noexcept
Definition: optional.h:240
constexpr const value_type & value() const &
Definition: optional.h:260
constexpr const value_type * operator->() const noexcept
Definition: optional.h:234
constexpr auto transform(F &&f) const &&
Definition: optional.h:364
constexpr value_type && value() &&
Definition: optional.h:265
constexpr optional or_else(F &&f) &&
Definition: optional.h:387
constexpr optional() noexcept=default
constexpr bool has_value() const noexcept
Definition: optional.h:249
constexpr optional & operator=(optional const &)=default
constexpr const value_type && operator*() const &&noexcept
Definition: optional.h:242
constexpr auto and_then(F &&f) &&
Definition: optional.h:321
constexpr auto transform(F &&f) &&
Definition: optional.h:356
constexpr value_type value_or(U &&default_value) &&
Definition: optional.h:290
constexpr optional(const optional &other)=default
constexpr optional(InPlaceT)
Definition: optional.h:121
constexpr optional(U &&value)
Definition: optional.h:145
constexpr value_type & value() &
Definition: optional.h:255
optional & operator=(U &&value)
Definition: optional.h:179
constexpr optional(const optional< U > &other)
Definition: optional.h:79
optional & operator=(optional< U > &&other)
Definition: optional.h:217
void swap(optional &other) noexcept(std::is_nothrow_move_constructible< value_type >::value &&vccc::is_nothrow_swappable< value_type >::value)
Definition: optional.h:393
optional & operator=(const optional< U > &other)
Definition: optional.h:196
constexpr const value_type && value() const &&
Definition: optional.h:270
constexpr auto transform(F &&f) const &
Definition: optional.h:348
constexpr optional or_else(F &&f) const &
Definition: optional.h:379
optional & operator=(nullopt_t) noexcept
Definition: optional.h:163
value_type & emplace(Arg &&arg, Args &&... args)
Definition: optional.h:431
constexpr optional(optional &&other)=default
constexpr optional & operator=(optional &&)=default
constexpr optional(in_place_t, Arg &&arg, Args &&... args)
Definition: optional.h:128
value_type & emplace(std::initializer_list< U > ilist, Args &&... args)
Definition: optional.h:441
T value_type
Definition: optional.h:51
constexpr invoke_result_t< F, Args... > invoke(F &&f, Args &&... args) noexcept(is_nothrow_invocable< F, Args... >::value)
Definition: invoke.hpp:38
constexpr optional< std::decay_t< T > > make_optional(T &&value)
Definition: optional.h:459
constexpr bool operator>(const optional< T > &lhs, const optional< U > &rhs)
Definition: optional.h:522
constexpr bool operator<(const optional< T > &lhs, const optional< U > &rhs)
Definition: optional.h:504
constexpr bool operator<=(const optional< T > &lhs, const optional< U > &rhs)
Definition: optional.h:513
constexpr bool operator>=(const optional< T > &lhs, const optional< U > &rhs)
Definition: optional.h:531
void swap(::vccc::optional< T > &lhs, ::vccc::optional< T > &rhs) noexcept(noexcept(lhs.swap(rhs)))
Definition: swap.h:30
typename remove_cvref< T >::type remove_cvref_t
Definition: remove_cvref.hpp:24
typename invoke_result< F, Args... >::type invoke_result_t
Definition: is_invocable.hpp:66
constexpr VCCC_INLINE_OR_STATIC in_place_t in_place
Definition: in_place.hpp:47
Definition: matrix.hpp:495
constexpr std::decay_t< T > default_value()
Definition: sum.hpp:39
Definition: directory.h:12
constexpr bool operator!=(const MatrixBase< E1 > &lhs, const MatrixBase< E2 > &rhs)
Definition: mat_expr_operations.hpp:23
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35
constexpr bool operator==(const MatrixBase< E1 > &lhs, const MatrixBase< E2 > &rhs)
Definition: mat_expr_operations.hpp:15
Definition: conjunction.hpp:22
specifies that an object of a type can be copy constructed and move constructed
Definition: copy_constructible.hpp:55
in-place construction tag
Definition: in_place.hpp:25
specifies that a callable type can be invoked with a given set of argument types
Definition: invocable.hpp:52
Definition: is_swappable.hpp:125
Definition: is_specialization.hpp:30
indicator of optional type with uninitialized state
Definition: nullopt_t.h:19