Shaka Player Embedded
optional.h
Go to the documentation of this file.
1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SHAKA_EMBEDDED_OPTIONAL_H_
16 #define SHAKA_EMBEDDED_OPTIONAL_H_
17 
18 #include <assert.h>
19 
20 #include <type_traits>
21 #include <utility>
22 
23 #include "macros.h"
24 
25 namespace shaka {
26 
27 // Note that we shouldn't use the C++17 type even if we are compiling with that
28 // version of C++. This is because Shaka Embedded is compiled using C++11 and
29 // will use this type. So the app should always use this type for our API.
30 // Otherwise using different types will cause subtle bugs.
31 
34  explicit nullopt_t(int) {}
35 };
36 extern const SHAKA_EXPORT nullopt_t nullopt;
37 
38 template <class T>
39 class optional;
40 
41 template <class T>
42 struct is_optional : std::false_type {};
43 template <class T>
44 struct is_optional<optional<T>> : std::true_type {};
45 
54 template <class T>
55 class optional {
56  public:
57  optional() : has_value_(false) {}
58  optional(nullopt_t) : has_value_(false) {}
59  // Avoid errors when returning |nullptr| instead of |nullopt|.
60  optional(std::nullptr_t) = delete;
61  template <class U = T,
62  class = typename std::enable_if<
63  std::is_constructible<T, U&&>::value &&
65  optional(U&& value) : value_(std::forward<U>(value)), has_value_(true) {}
66 
67  optional(const optional& other) : has_value_(other.has_value_) {
68  if (has_value_)
69  new (&value_) T(other.value_);
70  }
71  optional(optional&& other) : has_value_(other.has_value_) {
72  if (has_value_) {
73  new (&value_) T(std::move(other.value_));
74  other.reset();
75  }
76  }
77  template <class U>
78  optional(const optional<U>& other) : has_value_(other.has_value_) {
79  if (has_value_)
80  new (&value_) T(other.value_);
81  }
82  template <class U>
83  optional(optional<U>&& other) : has_value_(other.has_value_) {
84  if (has_value_) {
85  new (&value_) T(std::move(other.value_));
86  other.reset();
87  }
88  }
89 
91  reset();
92  }
93 
94  // This type will still accept assigning to other values but it will use the
95  // constructors to create a temporary first. This avoids having to create a
96  // bunch of overloads here.
97  optional& operator=(const optional& other) {
98  reset();
99  has_value_ = other.has_value_;
100  if (has_value_)
101  new (&value_) T(other.value_);
102  return *this;
103  }
105  reset();
106  has_value_ = other.has_value_;
107  if (has_value_) {
108  new (&value_) T(std::move(other.value_));
109  other.reset();
110  }
111  return *this;
112  }
113 
114 
115  const T* operator->() const {
116  assert(has_value_);
117  return &value_;
118  }
119  T* operator->() {
120  assert(has_value_);
121  return &value_;
122  }
123  const T& operator*() const& {
124  assert(has_value_);
125  return value_;
126  }
127  T& operator*() & {
128  assert(has_value_);
129  return value_;
130  }
131  const T&& operator*() const&& {
132  assert(has_value_);
133  return std::move(value_);
134  }
135  T&& operator*() && {
136  assert(has_value_);
137  return std::move(value_);
138  }
139 
140  explicit operator bool() const {
141  return has_value_;
142  }
143  bool has_value() const {
144  return has_value_;
145  }
146 
147  const T& value() const& {
148  assert(has_value_);
149  return value_;
150  }
151  T& value() & {
152  assert(has_value_);
153  return value_;
154  }
155  const T&& value() const&& {
156  assert(has_value_);
157  return std::move(value_);
158  }
159  T&& value() && {
160  assert(has_value_);
161  return std::move(value_);
162  }
163 
164  template <class U>
165  T value_or(U&& default_value) const& {
166  return has_value_ ? value_ : static_cast<T>(std::forward<U>(default_value));
167  }
168  template <class U>
169  T value_or(U&& default_value) && {
170  return has_value_ ? std::move(value_)
171  : static_cast<T>(std::forward<U>(default_value));
172  }
173 
174  void reset() {
175  if (has_value_) {
176  value_.~T();
177  has_value_ = false;
178  }
179  }
180 
181  template <class... Args>
182  T& emplace(Args&&... args) {
183  reset();
184  has_value_ = true;
185  new (&value_) T(std::forward<Args>(args)...);
186  return value_;
187  }
188 
189  private:
190  template <class U>
191  friend class optional;
192 
193  union {
195  char dummy_;
196  };
197  bool has_value_;
198 };
199 static_assert(sizeof(optional<char>) == 2, "Optional too big");
200 static_assert(alignof(optional<char>) == alignof(char),
201  "Optional bad alignment");
202 
203 
204 // Note that "no value" < "has value" for any value.
205 // See https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
206 template <class A, class B>
207 bool operator==(const optional<A>& lhs, const optional<B>& rhs) {
208  if (!lhs.has_value() || !rhs.has_value())
209  return lhs.has_value() == rhs.has_value();
210  else
211  return lhs.value() == rhs.value();
212 }
213 template <class A, class B>
214 bool operator!=(const optional<A>& lhs, const optional<B>& rhs) {
215  return !(lhs == rhs);
216 }
217 template <class A, class B>
218 bool operator<(const optional<A>& lhs, const optional<B>& rhs) {
219  if (!lhs.has_value() || !rhs.has_value())
220  return rhs.has_value();
221  else
222  return lhs.value() == rhs.value();
223 }
224 template <class A, class B>
225 bool operator<=(const optional<A>& lhs, const optional<B>& rhs) {
226  return lhs < rhs || lhs == rhs;
227 }
228 template <class A, class B>
229 bool operator>(const optional<A>& lhs, const optional<B>& rhs) {
230  return rhs < lhs;
231 }
232 template <class A, class B>
233 bool operator>=(const optional<A>& lhs, const optional<B>& rhs) {
234  return rhs < lhs || lhs == rhs;
235 }
236 
237 template <class T>
238 bool operator==(const optional<T>& opt, nullopt_t) {
239  return !opt; // 7
240 }
241 template <class T>
242 bool operator==(nullopt_t, const optional<T>& opt) {
243  return !opt; // 8
244 }
245 template <class T>
246 bool operator!=(const optional<T>& opt, nullopt_t) {
247  return bool(opt); // 9
248 }
249 template <class T>
250 bool operator!=(nullopt_t, const optional<T>& opt) {
251  return bool(opt); // 10
252 }
253 template <class T>
254 bool operator<(const optional<T>& opt, nullopt_t) {
255  return false; // 11
256 }
257 template <class T>
258 bool operator<(nullopt_t, const optional<T>& opt) {
259  return bool(opt); // 12
260 }
261 template <class T>
262 bool operator<=(const optional<T>& opt, nullopt_t) {
263  return !opt; // 13
264 }
265 template <class T>
266 bool operator<=(nullopt_t, const optional<T>& opt) {
267  return true; // 14
268 }
269 template <class T>
270 bool operator>(const optional<T>& opt, nullopt_t) {
271  return bool(opt); // 15
272 }
273 template <class T>
274 bool operator>(nullopt_t, const optional<T>& opt) {
275  return false; // 16
276 }
277 template <class T>
278 bool operator>=(const optional<T>& opt, nullopt_t) {
279  return true; // 17
280 }
281 template <class T>
282 bool operator>=(nullopt_t, const optional<T>& opt) {
283  return !opt; // 18
284 }
285 
286 template <class A, class B>
287 bool operator==(const optional<A>& opt, const B& value) {
288  return bool(opt) ? *opt == value : false; // 19
289 }
290 template <class A, class B>
291 bool operator==(const A& value, const optional<B>& opt) {
292  return bool(opt) ? value == *opt : false; // 20
293 }
294 template <class A, class B>
295 bool operator!=(const optional<A>& opt, const B& value) {
296  return bool(opt) ? *opt != value : true; // 21
297 }
298 template <class A, class B>
299 bool operator!=(const A& value, const optional<B>& opt) {
300  return bool(opt) ? value == *opt : true; // 22
301 }
302 template <class A, class B>
303 bool operator<(const optional<A>& opt, const B& value) {
304  return bool(opt) ? *opt < value : true; // 23
305 }
306 template <class A, class B>
307 bool operator<(const A& value, const optional<B>& opt) {
308  return bool(opt) ? value < *opt : false; // 24
309 }
310 template <class A, class B>
311 bool operator<=(const optional<A>& opt, const B& value) {
312  return bool(opt) ? *opt <= value : true; // 25
313 }
314 template <class A, class B>
315 bool operator<=(const A& value, const optional<B>& opt) {
316  return bool(opt) ? value <= *opt : false; // 26
317 }
318 template <class A, class B>
319 bool operator>(const optional<A>& opt, const B& value) {
320  return bool(opt) ? *opt > value : false; // 27
321 }
322 template <class A, class B>
323 bool operator>(const A& value, const optional<B>& opt) {
324  return bool(opt) ? value > *opt : true; // 28
325 }
326 template <class A, class B>
327 bool operator>=(const optional<A>& opt, const B& value) {
328  return bool(opt) ? *opt >= value : false; // 29
329 }
330 template <class A, class B>
331 bool operator>=(const A& value, const optional<B>& opt) {
332  return bool(opt) ? value >= *opt : true; // 30
333 }
334 
335 } // namespace shaka
336 
337 #endif // SHAKA_EMBEDDED_OPTIONAL_H_
bool operator>=(const optional< A > &lhs, const optional< B > &rhs)
Definition: optional.h:233
optional(const optional &other)
Definition: optional.h:67
#define SHAKA_EXPORT
Definition: macros.h:30
bool operator>(const optional< A > &lhs, const optional< B > &rhs)
Definition: optional.h:229
const T && operator*() const &&
Definition: optional.h:131
T value_or(U &&default_value) &&
Definition: optional.h:169
T && value() &&
Definition: optional.h:159
optional(optional< U > &&other)
Definition: optional.h:83
const T & operator*() const &
Definition: optional.h:123
bool operator==(const optional< A > &lhs, const optional< B > &rhs)
Definition: optional.h:207
optional(optional &&other)
Definition: optional.h:71
bool operator!=(const optional< A > &lhs, const optional< B > &rhs)
Definition: optional.h:214
T * operator->()
Definition: optional.h:119
const nullopt_t nullopt
Definition: optional.cc:22
optional & operator=(optional &&other)
Definition: optional.h:104
const T & value() const &
Definition: optional.h:147
T & value() &
Definition: optional.h:151
optional(nullopt_t)
Definition: optional.h:58
ExceptionCode type
T & operator*() &
Definition: optional.h:127
T && operator*() &&
Definition: optional.h:135
optional(const optional< U > &other)
Definition: optional.h:78
void reset()
Definition: optional.h:174
optional & operator=(const optional &other)
Definition: optional.h:97
T value_or(U &&default_value) const &
Definition: optional.h:165
const T && value() const &&
Definition: optional.h:155
optional(U &&value)
Definition: optional.h:65
const T * operator->() const
Definition: optional.h:115
bool has_value() const
Definition: optional.h:143
T & emplace(Args &&... args)
Definition: optional.h:182