libzed 1.10.2
A general-purpose library for quick and simple data manipulation.
 
Loading...
Searching...
No Matches
std_optional.hpp
1#pragma once
2
3#if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
4// If C++17 or greater, use stdlib optional class.
5#include <optional>
6#elif !defined(DOXYGEN)
7// Otherwise, polyfill our own implementation of std::optional
8
9namespace std {
10
11struct nullopt_t {
12 explicit constexpr nullopt_t(int) noexcept {}
13};
14inline constexpr nullopt_t nullopt{0};
15
16class bad_optional_access : public exception {
17public:
18 bad_optional_access() = default;
19 virtual ~bad_optional_access() = default;
20
21 const char *what() const noexcept override {
22 return "bad optional access";
23 }
24};
25
26template <typename T>
27class optional {
28 union {
29 char dummy;
30 T val;
31 };
32 bool engaged;
33
34public:
35 constexpr optional() noexcept : dummy(0), engaged(false) {}
36 constexpr optional(nullopt_t) noexcept : dummy(0), engaged(false) {}
37
38 optional(const optional &other) {
39 engaged = other.engaged;
40 if (engaged) {
41 val = other.val;
42 } else {
43 dummy = 0;
44 }
45 };
46 optional(optional &&other) noexcept(is_nothrow_move_constructible_v<T>) {
47 engaged = other.engaged;
48 if (engaged) {
49 val = other.val;
50 } else {
51 dummy = 0;
52 }
53 }
54 optional(T &&u) : val(std::forward<T>(u)), engaged(true) {}
55
56 optional(const T &t) : val(t), engaged(true) {}
57
58 optional &operator=(const optional &other) {
59 engaged = other.engaged;
60 if (engaged) {
61 val = other.val;
62 } else {
63 dummy = 0;
64 }
65 return *this;
66 }
67 optional &operator=(const T &other) {
68 if (engaged) {
69 val.~T();
70 }
71 val.T(other);
72 engaged = true;
73 return *this;
74 };
75 optional &operator=(T &&other) {
76 if (engaged) {
77 val.~T();
78 }
79 val.T(other);
80 engaged = true;
81 return *this;
82 }
83
84 ~optional() {
85 if (engaged) {
86 val.~T();
87 }
88 }
89
90 constexpr operator bool() const {
91 return engaged;
92 }
93 constexpr bool has_value() const {
94 return engaged;
95 }
96
97 constexpr T &operator*() & {
98 return val;
99 }
100 constexpr const T &operator*() const & {
101 return val;
102 }
103 constexpr T &&operator*() && {
104 return std::move(val);
105 }
106 constexpr const T &&operator*() const && {
107 return std::move(val);
108 }
109
110 T &value() & {
111 return engaged ? val : throw bad_optional_access();
112 }
113 const T &value() const & {
114 return engaged ? val : throw bad_optional_access();
115 }
116 T &&value() && {
117 return engaged ? std::move(val) : throw bad_optional_access();
118 }
119 const T &&value() const && {
120 return engaged ? std::move(val) : throw bad_optional_access();
121 }
122
123 template <class U>
124 T value_or(U &&u) const {
125 return engaged ? val : static_cast<T>(std::forward<U>(u));
126 }
127};
128
129} // namespace std
130
131#endif