xtd 0.2.0
optional.h
Go to the documentation of this file.
1 #pragma once
4 #if defined(__cpp_lib_optional) || __cplusplus >= 201703l
6 #include <optional>
7 #else
8 #include <stdexcept>
9 #include <utility>
10 
11 namespace std {
12  /*
13  class bad_optional_access : public std::exception {
14  public:
15  const char* what() const noexcept override {return "bad optional access";}
16  };
17  */
18 
19  template <typename value_t>
20  class optional {
21  private:
22  alignas(value_t) unsigned char data_[sizeof(value_t)];
23  bool has_value_;
24 
25  public:
26  optional() : has_value_(false) {}
27 
28  optional(const value_t& value) : has_value_(true) {
29  new (data_) value_t(value);
30  }
31 
32  optional(value_t&& value) : has_value_(true) {
33  new (data_) value_t(std::move(value));
34  }
35 
36  optional(const optional& other) : has_value_(other.has_value_) {
37  if (other.has_value_) {
38  new (data_) value_t(*other);
39  }
40  }
41 
42  optional(optional&& other) : has_value_(other.has_value_) {
43  if (other.has_value_) {
44  new (data_) value_t(std::move(*other));
45  }
46  other.reset();
47  }
48 
49  optional& operator=(const value_t& value) {
50  if (has_value_) {
51  *reinterpret_cast<value_t*>(data_) = value;
52  } else {
53  new (data_) value_t(value);
54  has_value_ = true;
55  }
56  return *this;
57  }
58 
59  optional& operator=(value_t&& value) {
60  if (has_value_) {
61  *reinterpret_cast<value_t*>(data_) = std::move(value);
62  } else {
63  new (data_) value_t(std::move(value));
64  has_value_ = true;
65  }
66  return *this;
67  }
68 
69  optional& operator=(const optional& other) {
70  if (this == &other) {
71  return *this;
72  }
73 
74  if (other.has_value_) {
75  if (has_value()) {
76  *reinterpret_cast<value_t*>(data_) = *other;
77  } else {
78  new (data_) value_t(*other);
79  has_value_ = true;
80  }
81  } else {
82  reset();
83  }
84  return *this;
85  }
86 
87  optional& operator=(optional&& other) {
88  if (this == &other) {
89  return *this;
90  }
91 
92  if (other.has_value_) {
93  if (has_value()) {
94  *reinterpret_cast<value_t*>(data_) = std::move(*other);
95  } else {
96  new (data_) value_t(std::move(*other));
97  has_value_ = true;
98  }
99  } else {
100  reset();
101  }
102  other.reset();
103  return *this;
104  }
105 
106  ~optional() {
107  reset();
108  }
109 
110  bool has_value() const {
111  return has_value_;
112  }
113 
114  const value_t& value() const {
115  return operator*();
116  }
117 
118  const value_t& value_or(const value_t& other) const {
119  return has_value() ? operator*() : other;
120  }
121 
122  void reset() {
123  if (!has_value()) return;
124  reinterpret_cast<value_t*>(data_)->~value_t();
125  has_value_ = false;
126  }
127 
128  const value_t* operator->() const {
129  if (!has_value()) {
130  throw std::runtime_error("optional does not contain a value.");
131  }
132  return reinterpret_cast<const value_t*>(data_);
133  }
134 
135  value_t* operator->() {
136  if (!has_value_) {
137  throw std::runtime_error("optional does not contain a value.");
138  }
139  return reinterpret_cast<value_t*>(data_);
140  }
141 
142  const value_t& operator*() const {
143  return *operator->();
144  }
145 
146  value_t& operator*() {
147  return *operator->();
148  }
149 
150  explicit operator bool() const {
151  return has_value_;
152  }
153  };
154 }
155 #endif
156