halcheck 1.0
Loading...
Searching...
No Matches
optional.hpp
1#ifndef HALCHECK_LIB_OPTIONAL_HPP
2#define HALCHECK_LIB_OPTIONAL_HPP
3
11#include <halcheck/lib/type_traits.hpp>
12#include <halcheck/lib/utility.hpp>
13
14#include <cstddef>
15#include <exception>
16#include <functional>
17#include <initializer_list>
18#include <memory>
19#include <type_traits>
20#if __cplusplus >= 201606L
21#include <optional> // IWYU pragma: export
22#endif
23
24namespace halcheck { namespace lib {
25
31struct nullopt_t {
32 struct tag {};
33 explicit constexpr nullopt_t(tag) {}
34};
35
41static constexpr nullopt_t nullopt{nullopt_t::tag{}};
42
49 bad_optional_access() = default;
50 const char *what() const noexcept override { return "halcheck::lib::bad_optional_access"; }
51};
52
53template<typename>
54class optional;
55
56namespace detail {
57
58template<typename T, typename = void>
59struct optional_base {
60 constexpr optional_base() noexcept : _dummy(), _has_value(false) {}
61
62 template<typename... Args>
63 explicit constexpr optional_base(lib::in_place_t, Args &&...args)
64 : _value(std::forward<Args>(args)...), _has_value(true) {}
65
66 struct dummy {};
67 union {
68 dummy _dummy;
69 T _value;
70 };
71 bool _has_value;
72};
73
74template<typename T>
75struct optional_base<T &> {
76 constexpr optional_base() noexcept : _value(nullptr) {}
77
78 explicit constexpr optional_base(lib::in_place_t, T &value) noexcept : _value(std::addressof(value)) {}
79
80 struct dummy {};
81 T *_value;
82};
83
84template<typename T>
85struct optional_base<T, lib::enable_if_t<!std::is_trivially_destructible<T>()>> { // NOLINT
86 constexpr optional_base() noexcept : _dummy(), _has_value(false) {}
87
88 template<typename... Args>
89 explicit constexpr optional_base(lib::in_place_t, Args &&...args)
90 : _value(std::forward<Args>(args)...), _has_value(true) {}
91
92 ~optional_base() {
93 if (_has_value)
94 _value.~T();
95 }
96
97 struct dummy {};
98
99 union {
100 dummy _dummy;
101 T _value;
102 };
103 bool _has_value;
104};
105
106template<typename T>
107struct optional_ops : private optional_base<T> {
108 using optional_base<T>::optional_base;
109
110 using value_type = T;
111 using iterator = T *;
112 using const_iterator = const T *;
113
114 iterator begin() { return std::addressof(this->_value); }
115 const_iterator begin() const { return std::addressof(this->_value); }
116 iterator end() { return begin() + (this->_has_value ? 1 : 0); }
117 const_iterator end() const { return begin() + (this->_has_value ? 1 : 0); }
118
119 explicit operator bool() const noexcept { return this->_has_value; }
120
121 const T &operator*() const & { return this->_value; }
122 T &operator*() & { return this->_value; }
123 const T &&operator*() const && { return this->_value; }
124 T &&operator*() && { return this->_value; }
125
126 void reset() noexcept {
127 if (this->_has_value) {
128 this->_value.~T();
129 this->_has_value = false;
130 }
131 }
132
133 template<typename... Args, HALCHECK_REQUIRE(std::is_constructible<T, Args...>())>
134 T &emplace(Args &&...args) {
135 reset();
136 new (std::addressof(this->_value)) T(std::forward<Args>(args)...);
137 this->_has_value = true;
138 return this->_value;
139 }
140};
141
142template<typename T>
143struct optional_ops<T &> : private optional_base<T &> {
144 using optional_base<T &>::optional_base;
145
146 using value_type = T;
147 using iterator = T *;
148 using const_iterator = const T *;
149
150 iterator begin() { return this->_value; }
151 const_iterator begin() const { return this->_value; }
152 iterator end() { return begin() + (this->_value ? 1 : 0); }
153 const_iterator end() const { return begin() + (this->_value ? 1 : 0); }
154
155 optional_ops() = default;
156
157 explicit operator bool() const noexcept { return this->_value; }
158
159 const T &operator*() const { return *this->_value; }
160 T &operator*() { return *this->_value; }
161
162 void reset() noexcept { this->_value = nullptr; }
163
164 template<typename U = T, HALCHECK_REQUIRE(std::is_convertible<T *, U *>())>
165 T &emplace(U &value) {
166 this->_value = std::addressof(value);
167 return *this->_value;
168 }
169};
170
171template<typename T, typename = void>
172struct optional_copy_constructor_base : public optional_ops<T> {
173 using optional_ops<T>::optional_ops;
174};
175
176template<typename T>
177struct optional_copy_constructor_base<
178 T,
179 lib::enable_if_t<!std::is_trivially_copy_constructible<T>() && std::is_copy_constructible<T>()>>
180 : public optional_ops<T> { // NOLINT
181 using optional_ops<T>::optional_ops;
182
183 optional_copy_constructor_base() = default;
184 optional_copy_constructor_base &operator=(const optional_copy_constructor_base &) = default;
185 optional_copy_constructor_base &operator=(optional_copy_constructor_base &&) = default;
186 optional_copy_constructor_base(optional_copy_constructor_base &&) = default;
187 ~optional_copy_constructor_base() = default;
188
189 optional_copy_constructor_base(const optional_copy_constructor_base &other) {
190 if (other)
191 this->emplace(*other);
192 }
193};
194
195template<typename T, typename = void>
196struct optional_copy_assignment_base : public optional_copy_constructor_base<T> {
197 using optional_copy_constructor_base<T>::optional_copy_constructor_base;
198};
199
200template<typename T>
201struct optional_copy_assignment_base<
202 T,
203 lib::enable_if_t<
204 !std::is_trivially_copy_assignable<T>() && std::is_copy_constructible<T>() && std::is_copy_assignable<T>()>>
205 : public optional_copy_constructor_base<T> {
206 using optional_copy_constructor_base<T>::optional_copy_constructor_base;
207
208 optional_copy_assignment_base() = default;
209 optional_copy_assignment_base(optional_copy_assignment_base &&) = default;
210 optional_copy_assignment_base &operator=(optional_copy_assignment_base &&) = default;
211 optional_copy_assignment_base(const optional_copy_assignment_base &) = default;
212 ~optional_copy_assignment_base() = default;
213
214 optional_copy_assignment_base &operator=(const optional_copy_assignment_base &other) {
215 if (this != &other) {
216 if (!other)
217 this->reset();
218 else if (*this)
219 **this = *other;
220 else
221 this->emplace(*other);
222 }
223
224 return *this;
225 }
226};
227
228template<typename T>
229struct optional_copy_assignment_base<
230 T,
231 lib::enable_if_t<
232 !std::is_trivially_copy_assignable<T>() && std::is_copy_constructible<T>() && !std::is_copy_assignable<T>()>>
233 : public optional_copy_constructor_base<T> {
234 using optional_copy_constructor_base<T>::optional_copy_constructor_base;
235
236 optional_copy_assignment_base() = default;
237 optional_copy_assignment_base(optional_copy_assignment_base &&) = default;
238 optional_copy_assignment_base &operator=(optional_copy_assignment_base &&) = default;
239 optional_copy_assignment_base(const optional_copy_assignment_base &) = default;
240 ~optional_copy_assignment_base() = default;
241
242 optional_copy_assignment_base &operator=(const optional_copy_assignment_base &other) {
243 if (this != &other && *other)
244 this->emplace(*other);
245
246 return *this;
247 }
248};
249
250template<typename T, typename = void>
251struct optional_move_constructor_base : public optional_copy_assignment_base<T> {
252 using optional_copy_assignment_base<T>::optional_copy_assignment_base;
253};
254
255template<typename T>
256struct optional_move_constructor_base<
257 T,
258 lib::enable_if_t<!std::is_trivially_move_constructible<T>() && std::is_move_constructible<T>()>>
259 : public optional_copy_assignment_base<T> { // NOLINT
260 using optional_copy_assignment_base<T>::optional_copy_assignment_base;
261
262 optional_move_constructor_base() = default;
263 optional_move_constructor_base &operator=(const optional_move_constructor_base &) = default;
264 optional_move_constructor_base &operator=(optional_move_constructor_base &&) = default;
265 optional_move_constructor_base(const optional_move_constructor_base &) = default;
266 ~optional_move_constructor_base() = default;
267
268 optional_move_constructor_base(optional_move_constructor_base &&other) noexcept(
270 if (other)
271 this->emplace(std::move(*other));
272 }
273};
274
275template<typename T, typename = void>
276struct optional_move_assignment_base : public optional_move_constructor_base<T> {
277 using optional_move_constructor_base<T>::optional_move_constructor_base;
278};
279
280template<typename T>
281struct optional_move_assignment_base<
282 T,
283 lib::enable_if_t<!std::is_trivially_move_assignable<T>() && std::is_move_assignable<T>()>>
284 : public optional_move_constructor_base<T> { // NOLINT
285 using optional_move_constructor_base<T>::optional_move_constructor_base;
286
287 optional_move_assignment_base() = default;
288 optional_move_assignment_base(const optional_move_assignment_base &) = default;
289 optional_move_assignment_base &operator=(const optional_move_assignment_base &) = default;
290 optional_move_assignment_base(optional_move_assignment_base &&) = default;
291 ~optional_move_assignment_base() = default;
292
293 optional_move_assignment_base &operator=(optional_move_assignment_base &&other) noexcept(
295 if (this != &other) {
296 if (!other)
297 this->reset();
298 else if (*this)
299 **this = std::move(*other);
300 else
301 this->emplace(std::move(*other));
302 }
303
304 return *this;
305 }
306};
307
308template<typename T>
309struct optional_move_assignment_base<
310 T,
311 lib::enable_if_t<!std::is_trivially_move_assignable<T>() && !std::is_move_assignable<T>()>>
312 : public optional_move_constructor_base<T> { // NOLINT
313 using optional_move_constructor_base<T>::optional_move_constructor_base;
314
315 optional_move_assignment_base() = default;
316 optional_move_assignment_base(const optional_move_assignment_base &) = default;
317 optional_move_assignment_base &operator=(const optional_move_assignment_base &) = default;
318 optional_move_assignment_base(optional_move_assignment_base &&) = default;
319 ~optional_move_assignment_base() = default;
320
321 optional_move_assignment_base &
322 operator=(optional_move_assignment_base &&other) noexcept(std::is_nothrow_move_constructible<T>()) {
323 if (this != &other && *other)
324 this->emplace(std::move(*other));
325
326 return *this;
327 }
328};
329
330} // namespace detail
331
337template<typename T>
338class optional : private detail::optional_move_assignment_base<T> {
339private:
340 using base = detail::optional_move_assignment_base<T>;
341
342public:
343 optional() = default;
344
345 constexpr optional(lib::nullopt_t) noexcept {} // NOLINT
346
347 template<
348 typename U = T,
359 optional(const optional<U> &other) { // NOLINT
360 if (other)
361 emplace(*other);
362 }
363
364 template<
365 typename U = T,
376 explicit optional(const optional<U> &other) { // NOLINT
377 if (other)
378 emplace(*other);
379 }
380
381 template<
382 typename U = T,
393 optional(optional<U> &&other) { // NOLINT
394 if (other)
395 emplace(std::move(*other));
396 }
397
398 template<
399 typename U = T,
410 explicit optional(optional<U> &&other) { // NOLINT
411 if (other)
412 emplace(std::move(*other));
413 }
414
415 template<typename U = T, typename... Args, HALCHECK_REQUIRE(std::is_constructible<T, Args...>())>
416 constexpr explicit optional(lib::in_place_t, Args &&...args) : base(lib::in_place, std::forward<Args>(args)...) {}
417
418 template<
419 typename U = T,
420 typename... Args,
422 constexpr explicit optional(lib::in_place_t, std::initializer_list<U> ilist, Args &&...args)
423 : base(lib::in_place, ilist, std::forward<Args>(args)...) {}
424
425 template<
426 typename U = lib::remove_cvref_t<T>,
432 constexpr optional(U &&value) // NOLINT
434
435 template<
436 typename U = lib::remove_cvref_t<T>,
442 explicit constexpr optional(U &&value) : optional(lib::in_place, std::forward<U>(value)) {}
443
444 optional &operator=(lib::nullopt_t) {
445 reset();
446 return *this;
447 }
448
449 template<
450 typename U = lib::remove_cv_t<T>,
455 optional &operator=(U &&other) {
456 if (*this)
457 **this = std::forward<U>(other);
458 else
459 emplace(std::forward<U>(other));
460 return *this;
461 }
462
463 template<
464 typename U,
479 optional &operator=(optional<U> &&other) {
480 if (!other)
481 reset();
482 else if (*this)
483 **this = std::move(*other);
484 else
485 emplace(std::move(*other));
486 return *this;
487 }
488
489 template<
490 typename U,
505 optional &operator=(const optional<U> &other) {
506 if (!other)
507 reset();
508 else if (*this)
509 **this = *other;
510 else
511 emplace(*other);
512 return *this;
513 }
514
515 using typename base::value_type;
516 using base::operator bool;
517 using base::operator*;
518 using base::emplace;
519 using base::reset;
520
521 const value_type *operator->() const { return &**this; }
522 value_type *operator->() { return &**this; }
523
524 constexpr bool has_value() const noexcept { return bool(*this); }
525
526 const T &value() const & {
527 if (!has_value())
529
530 return **this;
531 }
532
533 T &value() & {
534 if (!has_value())
536
537 return **this;
538 }
539
540 const T &&value() const && {
541 if (!has_value())
543
544 return **this;
545 }
546
547 T &&value() && {
548 if (!has_value())
550
551 return **this;
552 }
553
554 template<
555 typename U = lib::remove_cv_t<T>,
557 constexpr T value_or(U &&default_value) const & {
558 return *this ? **this : static_cast<T>(std::forward<U>(default_value));
559 }
560
561 template<
562 typename U = lib::remove_cv_t<T>,
564 T value_or(U &&default_value) && {
565 return *this ? std::move(**this) : static_cast<T>(std::forward<U>(default_value));
566 }
567
568 template<bool _ = std::is_move_constructible<T>() && lib::is_swappable<T>(), HALCHECK_REQUIRE(_)>
570 using std::swap;
571 if (*this && other)
572 swap(**this, *other);
573 else if (*this) {
574 other = std::move(*this);
575 reset();
576 } else {
577 *this = std::move(other);
578 other.reset();
579 }
580 }
581
582#if __cplusplus >= 201606L
583 constexpr operator std::optional<T>() const & { // NOLINT
584 return *this ? std::optional<T>(std::in_place, **this) : std::optional<T>();
585 }
586
587 constexpr operator std::optional<T>() && { // NOLINT
588 return *this ? std::optional<T>(std::in_place, std::move(**this)) : std::optional<T>();
589 }
590#endif
591
592private:
598 template<bool _ = true, HALCHECK_REQUIRE(std::is_move_constructible<T>() && lib::is_swappable<T>() && _)>
599 friend void swap(lib::optional<T> &lhs, lib::optional<T> &rhs) noexcept(
601 lhs.swap(rhs);
602 }
603};
604
605namespace detail {
606template<typename T>
607struct optional_void_base {
608 using value_type = T;
609
610 constexpr optional_void_base() noexcept : _has_value(false) {}
611 explicit constexpr optional_void_base(lib::nullopt_t) noexcept : _has_value(false) {}
612 explicit constexpr optional_void_base(lib::in_place_t) noexcept : _has_value(true) {}
613
614 lib::optional<T> &operator=(lib::nullopt_t) noexcept { // NOLINT: returning reference to subclass
615 _has_value = false;
616 return *static_cast<lib::optional<T> *>(this);
617 }
618
619 explicit operator bool() const noexcept { return _has_value; }
620 bool has_value() const noexcept { return _has_value; }
621 void operator*() const noexcept {}
622 void value() const {
623 if (!_has_value)
624 throw lib::bad_optional_access();
625 }
626
627 void swap(lib::optional<T> &other) noexcept { std::swap(_has_value, other._has_value); }
628 void reset() noexcept { _has_value = false; }
629 void emplace() noexcept { _has_value = true; }
630
631private:
634 friend void swap(lib::optional<T> &lhs, lib::optional<T> &rhs) noexcept { lhs.swap(rhs); }
635
636 bool _has_value;
637};
638} // namespace detail
639
645template<>
646struct optional<void> : public detail::optional_void_base<void> {
647 using detail::optional_void_base<void>::optional_void_base;
648};
649
655template<>
656struct optional<const void> : public detail::optional_void_base<const void> {
657 using detail::optional_void_base<const void>::optional_void_base;
658};
659
665template<>
666struct optional<volatile void> : public detail::optional_void_base<volatile void> {
667 using detail::optional_void_base<volatile void>::optional_void_base;
668};
669
675template<>
676struct optional<const volatile void> : public detail::optional_void_base<const volatile void> {
677 using detail::optional_void_base<const volatile void>::optional_void_base;
678};
679
685template<typename T>
689
695template<
696 typename T,
697 typename... Args,
699constexpr lib::optional<T> make_optional(Args &&...args) {
701}
702
708template<
709 typename T,
710 typename U,
711 typename... Args,
713constexpr lib::optional<T> make_optional(const std::initializer_list<U> &ilist, Args &&...args) {
714 return lib::optional<T>(lib::in_place, ilist, std::forward<T>(args)...);
715}
716
722template<typename T, typename U, HALCHECK_REQUIRE(!std::is_void<T>()), HALCHECK_REQUIRE(!std::is_void<U>())>
723bool operator==(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
724 if (lhs && rhs)
725 return *lhs == *rhs;
726 else
727 return !lhs && !rhs;
728}
729
735template<typename T>
736bool operator==(const lib::nullopt_t &, const lib::optional<T> &value) {
737 return !value;
738}
739
745template<typename T>
746bool operator==(const lib::optional<T> &value, const lib::nullopt_t &) {
747 return !value;
748}
749
755template<typename T, typename U>
756bool operator==(const U &lhs, const lib::optional<T> &rhs) {
757 return rhs && lhs == *rhs;
758}
759
765template<typename T, typename U>
766bool operator==(const lib::optional<T> &lhs, const U &rhs) {
767 return lhs && *lhs == rhs;
768}
769
775template<typename T, typename U, HALCHECK_REQUIRE(!std::is_void<T>()), HALCHECK_REQUIRE(!std::is_void<U>())>
776bool operator!=(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
777 if (lhs && rhs)
778 return *lhs != *rhs;
779 else
780 return lhs || rhs;
781}
782
788template<typename T>
789bool operator!=(const lib::nullopt_t &, const lib::optional<T> &value) {
790 return value;
791}
792
798template<typename T>
799bool operator!=(const lib::optional<T> &value, const lib::nullopt_t &) {
800 return value;
801}
802
808template<typename T, typename U>
809bool operator!=(const U &lhs, const lib::optional<T> &rhs) {
810 return !rhs || lhs != *rhs;
811}
812
818template<typename T, typename U>
819bool operator!=(const lib::optional<T> &lhs, const U &rhs) {
820 return !lhs || *lhs != rhs;
821}
822
827template<typename T, typename U, HALCHECK_REQUIRE(!std::is_void<T>()), HALCHECK_REQUIRE(!std::is_void<U>())>
828bool operator<(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
829 if (lhs && rhs)
830 return *lhs < *rhs;
831 else
832 return !lhs && rhs;
833}
834
839template<typename T>
840bool operator<(const lib::nullopt_t &, const lib::optional<T> &value) {
841 return value;
842}
843
848template<typename T>
850 return false;
851}
852
857template<typename T, typename U>
858bool operator<(const U &lhs, const lib::optional<T> &rhs) {
859 return rhs && lhs < *rhs;
860}
861
866template<typename T, typename U>
867bool operator<(const lib::optional<T> &lhs, const U &rhs) {
868 return !lhs || *lhs < rhs;
869}
870
875template<typename T, typename U, HALCHECK_REQUIRE(!std::is_void<T>()), HALCHECK_REQUIRE(!std::is_void<U>())>
876bool operator>(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
877 if (lhs && rhs)
878 return *lhs > *rhs;
879 else
880 return lhs && !rhs;
881}
882
887template<typename T>
889 return false;
890}
891
896template<typename T>
897bool operator>(const lib::optional<T> &value, const lib::nullopt_t &) {
898 return value;
899}
900
905template<typename T, typename U>
906bool operator>(const U &lhs, const lib::optional<T> &rhs) {
907 return !rhs || lhs > *rhs;
908}
909
914template<typename T, typename U>
915bool operator>(const lib::optional<T> &lhs, const U &rhs) {
916 return lhs && *lhs < rhs;
917}
918
923template<typename T, typename U, HALCHECK_REQUIRE(!std::is_void<T>()), HALCHECK_REQUIRE(!std::is_void<U>())>
924bool operator<=(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
925 if (lhs && rhs)
926 return *lhs <= *rhs;
927 else
928 return !lhs;
929}
930
935template<typename T>
937 return true;
938}
939
944template<typename T>
945bool operator<=(const lib::optional<T> &value, const lib::nullopt_t &) {
946 return !value;
947}
948
953template<typename T, typename U>
954bool operator<=(const U &lhs, const lib::optional<T> &rhs) {
955 return rhs && lhs <= *rhs;
956}
957
962template<typename T, typename U>
963bool operator<=(const lib::optional<T> &lhs, const U &rhs) {
964 return !lhs || *lhs <= rhs;
965}
966
971template<typename T, typename U, HALCHECK_REQUIRE(!std::is_void<T>()), HALCHECK_REQUIRE(!std::is_void<U>())>
972bool operator>=(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
973 if (lhs && rhs)
974 return *lhs >= *rhs;
975 else
976 return !rhs;
977}
978
983template<typename T>
984bool operator>=(const lib::nullopt_t &, const lib::optional<T> &value) {
985 return !value;
986}
987
992template<typename T>
994 return true;
995}
996
1001template<typename T, typename U>
1002bool operator>=(const U &lhs, const lib::optional<T> &rhs) {
1003 return !rhs || lhs >= *rhs;
1004}
1005
1010template<typename T, typename U>
1011bool operator>=(const lib::optional<T> &lhs, const U &rhs) {
1012 return lhs && *lhs >= rhs;
1013}
1014
1020template<typename T, typename U, HALCHECK_REQUIRE(std::is_void<T>()), HALCHECK_REQUIRE(std::is_void<U>())>
1021bool operator==(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
1022 return bool(lhs) == bool(rhs);
1023}
1024
1030template<typename T, typename U, HALCHECK_REQUIRE(std::is_void<T>()), HALCHECK_REQUIRE(std::is_void<U>())>
1031bool operator!=(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
1032 return bool(lhs) != bool(rhs);
1033}
1034
1039template<typename T, typename U, HALCHECK_REQUIRE(std::is_void<T>()), HALCHECK_REQUIRE(std::is_void<U>())>
1040bool operator<(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
1041 return bool(lhs) < bool(rhs);
1042}
1043
1048template<typename T, typename U, HALCHECK_REQUIRE(std::is_void<T>()), HALCHECK_REQUIRE(std::is_void<U>())>
1049bool operator>(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
1050 return bool(lhs) > bool(rhs);
1051}
1052
1057template<typename T, typename U, HALCHECK_REQUIRE(std::is_void<T>()), HALCHECK_REQUIRE(std::is_void<U>())>
1058bool operator<=(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
1059 return bool(lhs) <= bool(rhs);
1060}
1061
1066template<typename T, typename U, HALCHECK_REQUIRE(std::is_void<T>()), HALCHECK_REQUIRE(std::is_void<U>())>
1067bool operator>=(const lib::optional<T> &lhs, const lib::optional<U> &rhs) {
1068 return bool(lhs) >= bool(rhs);
1069}
1070
1071}} // namespace halcheck::lib
1072
1073namespace std {
1074
1078template<typename T>
1079struct hash<halcheck::lib::optional<T>> { // NOLINT
1080 template<typename U = T, HALCHECK_REQUIRE(halcheck::lib::is_hashable<U>())>
1081 std::size_t operator()(const halcheck::lib::optional<T> &value) const noexcept {
1082 return value ? std::hash<halcheck::lib::remove_const_t<T>>()(*value) : 0;
1083 }
1084
1085 template<typename U = T, HALCHECK_REQUIRE(std::is_void<U>())>
1086 std::size_t operator()(const halcheck::lib::optional<T> &value) const noexcept {
1087 return std::hash<bool>()(bool(value));
1088 }
1089};
1090} // namespace std
1091
1092#endif
T addressof(T... args)
An implementation of std::optional.
Definition optional.hpp:338
T forward(T... args)
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::end_cpo::@28 end
Gets an iterator to past the end of a range.
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::begin_cpo::@27 begin
Gets an iterator to the first element of a range.
constexpr lib::optional< lib::decay_t< T > > make_optional(T &&value)
An implementation of std::make_optional.
Definition optional.hpp:686
bool operator==(const lib::optional< T > &lhs, const lib::optional< U > &rhs)
An implementation of std::optional::operator==.
Definition optional.hpp:723
friend void swap(lib::optional< T > &lhs, lib::optional< T > &rhs) noexcept(std::is_nothrow_move_constructible< T >() &&lib::is_nothrow_swappable< T >())
An implementation of std::swap for optional.
Definition optional.hpp:599
bool operator!=(const lib::optional< T > &lhs, const lib::optional< U > &rhs)
An implementation of std::optional::operator==.
Definition optional.hpp:776
static constexpr nullopt_t nullopt
An implementation of std::nullopt.
Definition optional.hpp:41
typename std::remove_cv< typename std::remove_reference< T >::type >::type remove_cvref_t
An implementation of std::remove_cvref_t.
Definition type_traits.hpp:141
typename std::decay< T >::type decay_t
An implementation of std::decay_t.
Definition type_traits.hpp:101
typename std::remove_cv< T >::type remove_cv_t
An implementation of std::remove_cv_t.
Definition type_traits.hpp:109
typename std::enable_if< Cond, T >::type enable_if_t
An implementation of std::enable_if_t.
Definition type_traits.hpp:93
#define HALCHECK_REQUIRE(...)
Expands to a template argument that is only valid if the given argument evaluates to true.
Definition type_traits.hpp:24
static constexpr in_place_t in_place
An implementation of std::in_place.
Definition utility.hpp:33
T in_place
bool operator<(const lib::optional< T > &lhs, const lib::optional< U > &rhs)
An implementation of std::optional::operator<.
Definition optional.hpp:828
bool operator>=(const lib::optional< T > &lhs, const lib::optional< U > &rhs)
An implementation of std::optional::operator>=.
Definition optional.hpp:972
bool operator>(const lib::optional< T > &lhs, const lib::optional< U > &rhs)
An implementation of std::optional::operator>.
Definition optional.hpp:876
bool operator<=(const lib::optional< T > &lhs, const lib::optional< U > &rhs)
An implementation of std::optional::operator<=.
Definition optional.hpp:924
STL namespace.
An implementation of std::bad_optional_access.
Definition optional.hpp:48
An implementation of std::in_place_t.
Definition utility.hpp:26
An implementation of std::is_nothrow_swappable.
Definition type_traits.hpp:311
Determines if a type is a specialization of a template class.
Definition type_traits.hpp:437
An implementation of std::is_swappable.
Definition type_traits.hpp:303
An implementation of std::nullopt_t.
Definition optional.hpp:31
T swap(T... args)