1#ifndef HALCHECK_LIB_OPTIONAL_HPP
2#define HALCHECK_LIB_OPTIONAL_HPP
11#include <halcheck/lib/type_traits.hpp>
12#include <halcheck/lib/utility.hpp>
20#if __cplusplus >= 201606L
24namespace halcheck {
namespace lib {
50 const char *what()
const noexcept override {
return "halcheck::lib::bad_optional_access"; }
58template<
typename T,
typename =
void>
60 constexpr optional_base() noexcept : _dummy(), _has_value(false) {}
62 template<
typename... Args>
64 : _value(
std::forward<Args>(args)...), _has_value(true) {}
75struct optional_base<T &> {
76 constexpr optional_base() noexcept : _value(
nullptr) {}
78 explicit constexpr optional_base(lib::in_place_t, T &value) noexcept : _value(
std::addressof(value)) {}
85struct optional_base<T, lib::
enable_if_t<!std::is_trivially_destructible<T>()>> {
86 constexpr optional_base() noexcept : _dummy(), _has_value(false) {}
88 template<
typename... Args>
89 explicit constexpr optional_base(lib::in_place_t, Args &&...args)
90 : _value(
std::
forward<Args>(args)...), _has_value(true) {}
107struct optional_ops :
private optional_base<T> {
108 using optional_base<T>::optional_base;
110 using value_type = T;
111 using iterator = T *;
112 using const_iterator =
const T *;
116 iterator
end() {
return begin() + (this->_has_value ? 1 : 0); }
117 const_iterator
end()
const {
return begin() + (this->_has_value ? 1 : 0); }
119 explicit operator bool() const noexcept {
return this->_has_value; }
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; }
126 void reset() noexcept {
127 if (this->_has_value) {
129 this->_has_value =
false;
134 T &emplace(Args &&...args) {
137 this->_has_value =
true;
143struct optional_ops<T &> :
private optional_base<T &> {
144 using optional_base<T &>::optional_base;
146 using value_type = T;
147 using iterator = T *;
148 using const_iterator =
const T *;
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); }
155 optional_ops() =
default;
157 explicit operator bool() const noexcept {
return this->_value; }
159 const T &operator*()
const {
return *this->_value; }
160 T &operator*() {
return *this->_value; }
162 void reset() noexcept { this->_value =
nullptr; }
164 template<typename U = T, HALCHECK_REQUIRE(std::is_convertible<T *, U *>())>
165 T &emplace(U &value) {
167 return *this->_value;
171template<
typename T,
typename =
void>
172struct optional_copy_constructor_base :
public optional_ops<T> {
173 using optional_ops<T>::optional_ops;
177struct optional_copy_constructor_base<
179 lib::
enable_if_t<!std::is_trivially_copy_constructible<T>() && std::is_copy_constructible<T>()>>
180 :
public optional_ops<T> {
181 using optional_ops<T>::optional_ops;
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;
189 optional_copy_constructor_base(
const optional_copy_constructor_base &other) {
191 this->emplace(*other);
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;
201struct optional_copy_assignment_base<
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;
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;
214 optional_copy_assignment_base &operator=(
const optional_copy_assignment_base &other) {
215 if (
this != &other) {
221 this->emplace(*other);
229struct optional_copy_assignment_base<
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;
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;
242 optional_copy_assignment_base &operator=(
const optional_copy_assignment_base &other) {
243 if (
this != &other && *other)
244 this->emplace(*other);
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;
256struct optional_move_constructor_base<
258 lib::
enable_if_t<!std::is_trivially_move_constructible<T>() && std::is_move_constructible<T>()>>
259 :
public optional_copy_assignment_base<T> {
260 using optional_copy_assignment_base<T>::optional_copy_assignment_base;
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;
268 optional_move_constructor_base(optional_move_constructor_base &&other)
noexcept(
271 this->emplace(std::move(*other));
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;
281struct optional_move_assignment_base<
283 lib::
enable_if_t<!std::is_trivially_move_assignable<T>() && std::is_move_assignable<T>()>>
284 :
public optional_move_constructor_base<T> {
285 using optional_move_constructor_base<T>::optional_move_constructor_base;
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;
293 optional_move_assignment_base &operator=(optional_move_assignment_base &&other)
noexcept(
295 if (
this != &other) {
299 **
this = std::move(*other);
301 this->emplace(std::move(*other));
309struct optional_move_assignment_base<
311 lib::
enable_if_t<!std::is_trivially_move_assignable<T>() && !std::is_move_assignable<T>()>>
312 :
public optional_move_constructor_base<T> {
313 using optional_move_constructor_base<T>::optional_move_constructor_base;
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;
321 optional_move_assignment_base &
323 if (
this != &other && *other)
324 this->emplace(std::move(*other));
338class optional :
private detail::optional_move_assignment_base<T> {
340 using base = detail::optional_move_assignment_base<T>;
395 emplace(std::move(*other));
412 emplace(std::move(*other));
483 **
this = std::move(*other);
485 emplace(std::move(*other));
515 using typename base::value_type;
516 using base::operator bool;
517 using base::operator*;
521 const value_type *operator->()
const {
return &**
this; }
522 value_type *operator->() {
return &**
this; }
524 constexpr bool has_value()
const noexcept {
return bool(*
this); }
526 const T &value()
const & {
540 const T &&value()
const && {
557 constexpr T value_or(U &&default_value)
const & {
558 return *
this ? **this :
static_cast<T
>(
std::forward<U>(default_value));
564 T value_or(U &&default_value) && {
565 return *
this ? std::move(**
this) :
static_cast<T
>(
std::forward<U>(default_value));
572 swap(**
this, *other);
574 other = std::move(*
this);
577 *
this = std::move(other);
582#if __cplusplus >= 201606L
598 template<bool _ = true, HALCHECK_REQUIRE(std::is_move_constructible<T>() &&
lib::is_swappable<T>() && _)>
607struct optional_void_base {
608 using value_type = T;
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) {}
614 lib::optional<T> &operator=(lib::nullopt_t)
noexcept {
616 return *
static_cast<lib::optional<T> *
>(
this);
619 explicit operator bool() const noexcept {
return _has_value; }
620 bool has_value() const noexcept {
return _has_value; }
621 void operator*() const noexcept {}
624 throw lib::bad_optional_access();
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; }
634 friend void swap(lib::optional<T> &lhs, lib::optional<T> &rhs)
noexcept { lhs.swap(rhs); }
646struct optional<void> :
public detail::optional_void_base<void> {
647 using detail::optional_void_base<
void>::optional_void_base;
656struct optional<const void> :
public detail::optional_void_base<const void> {
657 using detail::optional_void_base<
const void>::optional_void_base;
666struct optional<volatile void> :
public detail::optional_void_base<volatile void> {
667 using detail::optional_void_base<
volatile void>::optional_void_base;
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;
755template<
typename T,
typename U>
757 return rhs && lhs == *rhs;
765template<
typename T,
typename U>
767 return lhs && *lhs == rhs;
808template<
typename T,
typename U>
810 return !rhs || lhs != *rhs;
818template<
typename T,
typename U>
820 return !lhs || *lhs != rhs;
857template<
typename T,
typename U>
859 return rhs && lhs < *rhs;
866template<
typename T,
typename U>
868 return !lhs || *lhs < rhs;
905template<
typename T,
typename U>
907 return !rhs || lhs > *rhs;
914template<
typename T,
typename U>
916 return lhs && *lhs < rhs;
953template<
typename T,
typename U>
955 return rhs && lhs <= *rhs;
962template<
typename T,
typename U>
964 return !lhs || *lhs <= rhs;
1001template<
typename T,
typename U>
1003 return !rhs || lhs >= *rhs;
1010template<
typename T,
typename U>
1012 return lhs && *lhs >= rhs;
1022 return bool(lhs) == bool(rhs);
1031bool operator!=(
const lib::optional<T> &lhs,
const lib::optional<U> &rhs) {
1032 return bool(lhs) != bool(rhs);
1040bool operator<(
const lib::optional<T> &lhs,
const lib::optional<U> &rhs) {
1041 return bool(lhs) < bool(rhs);
1049bool operator>(
const lib::optional<T> &lhs,
const lib::optional<U> &rhs) {
1050 return bool(lhs) > bool(rhs);
1058bool operator<=(
const lib::optional<T> &lhs,
const lib::optional<U> &rhs) {
1059 return bool(lhs) <= bool(rhs);
1067bool operator>=(
const lib::optional<T> &lhs,
const lib::optional<U> &rhs) {
1068 return bool(lhs) >= bool(rhs);
1079struct hash<halcheck::lib::optional<T>> {
1080 template<typename U = T, HALCHECK_REQUIRE(halcheck::lib::is_hashable<U>())>
1085 template<typename U = T, HALCHECK_REQUIRE(std::is_void<U>())>
An implementation of std::optional.
Definition optional.hpp:338
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
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
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