]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/third-party/folly/folly/Optional.h
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / rocksdb / third-party / folly / folly / Optional.h
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5
6 #pragma once
7
8 /*
9 * Optional - For conditional initialization of values, like boost::optional,
10 * but with support for move semantics and emplacement. Reference type support
11 * has not been included due to limited use cases and potential confusion with
12 * semantics of assignment: Assigning to an optional reference could quite
13 * reasonably copy its value or redirect the reference.
14 *
15 * Optional can be useful when a variable might or might not be needed:
16 *
17 * Optional<Logger> maybeLogger = ...;
18 * if (maybeLogger) {
19 * maybeLogger->log("hello");
20 * }
21 *
22 * Optional enables a 'null' value for types which do not otherwise have
23 * nullability, especially useful for parameter passing:
24 *
25 * void testIterator(const unique_ptr<Iterator>& it,
26 * initializer_list<int> idsExpected,
27 * Optional<initializer_list<int>> ranksExpected = none) {
28 * for (int i = 0; it->next(); ++i) {
29 * EXPECT_EQ(it->doc().id(), idsExpected[i]);
30 * if (ranksExpected) {
31 * EXPECT_EQ(it->doc().rank(), (*ranksExpected)[i]);
32 * }
33 * }
34 * }
35 *
36 * Optional models OptionalPointee, so calling 'get_pointer(opt)' will return a
37 * pointer to nullptr if the 'opt' is empty, and a pointer to the value if it is
38 * not:
39 *
40 * Optional<int> maybeInt = ...;
41 * if (int* v = get_pointer(maybeInt)) {
42 * cout << *v << endl;
43 * }
44 */
45
46 #include <cstddef>
47 #include <functional>
48 #include <new>
49 #include <stdexcept>
50 #include <type_traits>
51 #include <utility>
52
53 #include <folly/CPortability.h>
54 #include <folly/Traits.h>
55 #include <folly/Utility.h>
56
57 namespace folly {
58
59 template <class Value>
60 class Optional;
61
62 namespace detail {
63 template <class Value>
64 struct OptionalPromiseReturn;
65 } // namespace detail
66
67 struct None {
68 enum class _secret { _token };
69
70 /**
71 * No default constructor to support both `op = {}` and `op = none`
72 * as syntax for clearing an Optional, just like std::nullopt_t.
73 */
74 constexpr explicit None(_secret) {}
75 };
76 constexpr None none{None::_secret::_token};
77
78 class FOLLY_EXPORT OptionalEmptyException : public std::runtime_error {
79 public:
80 OptionalEmptyException()
81 : std::runtime_error("Empty Optional cannot be unwrapped") {}
82 };
83
84 template <class Value>
85 class Optional {
86 public:
87 typedef Value value_type;
88
89 static_assert(
90 !std::is_reference<Value>::value,
91 "Optional may not be used with reference types");
92 static_assert(
93 !std::is_abstract<Value>::value,
94 "Optional may not be used with abstract types");
95
96 Optional() noexcept {}
97
98 Optional(const Optional& src) noexcept(
99 std::is_nothrow_copy_constructible<Value>::value) {
100 if (src.hasValue()) {
101 construct(src.value());
102 }
103 }
104
105 Optional(Optional&& src) noexcept(
106 std::is_nothrow_move_constructible<Value>::value) {
107 if (src.hasValue()) {
108 construct(std::move(src.value()));
109 src.clear();
110 }
111 }
112
113 /* implicit */ Optional(const None&) noexcept {}
114
115 /* implicit */ Optional(Value&& newValue) noexcept(
116 std::is_nothrow_move_constructible<Value>::value) {
117 construct(std::move(newValue));
118 }
119
120 /* implicit */ Optional(const Value& newValue) noexcept(
121 std::is_nothrow_copy_constructible<Value>::value) {
122 construct(newValue);
123 }
124
125 template <typename... Args>
126 explicit Optional(in_place_t, Args&&... args) noexcept(
127 std::is_nothrow_constructible<Value, Args...>::value)
128 : Optional{PrivateConstructor{}, std::forward<Args>(args)...} {}
129
130 template <typename U, typename... Args>
131 explicit Optional(
132 in_place_t,
133 std::initializer_list<U> il,
134 Args&&... args) noexcept(std::
135 is_nothrow_constructible<
136 Value,
137 std::initializer_list<U>,
138 Args...>::value)
139 : Optional{PrivateConstructor{}, il, std::forward<Args>(args)...} {}
140
141 // Used only when an Optional is used with coroutines on MSVC
142 /* implicit */ Optional(const detail::OptionalPromiseReturn<Value>& p)
143 : Optional{} {
144 p.promise_->value_ = this;
145 }
146
147 void assign(const None&) {
148 clear();
149 }
150
151 void assign(Optional&& src) {
152 if (this != &src) {
153 if (src.hasValue()) {
154 assign(std::move(src.value()));
155 src.clear();
156 } else {
157 clear();
158 }
159 }
160 }
161
162 void assign(const Optional& src) {
163 if (src.hasValue()) {
164 assign(src.value());
165 } else {
166 clear();
167 }
168 }
169
170 void assign(Value&& newValue) {
171 if (hasValue()) {
172 storage_.value = std::move(newValue);
173 } else {
174 construct(std::move(newValue));
175 }
176 }
177
178 void assign(const Value& newValue) {
179 if (hasValue()) {
180 storage_.value = newValue;
181 } else {
182 construct(newValue);
183 }
184 }
185
186 Optional& operator=(None) noexcept {
187 reset();
188 return *this;
189 }
190
191 template <class Arg>
192 Optional& operator=(Arg&& arg) {
193 assign(std::forward<Arg>(arg));
194 return *this;
195 }
196
197 Optional& operator=(Optional&& other) noexcept(
198 std::is_nothrow_move_assignable<Value>::value) {
199 assign(std::move(other));
200 return *this;
201 }
202
203 Optional& operator=(const Optional& other) noexcept(
204 std::is_nothrow_copy_assignable<Value>::value) {
205 assign(other);
206 return *this;
207 }
208
209 template <class... Args>
210 Value& emplace(Args&&... args) {
211 clear();
212 construct(std::forward<Args>(args)...);
213 return value();
214 }
215
216 template <class U, class... Args>
217 typename std::enable_if<
218 std::is_constructible<Value, std::initializer_list<U>&, Args&&...>::value,
219 Value&>::type
220 emplace(std::initializer_list<U> ilist, Args&&... args) {
221 clear();
222 construct(ilist, std::forward<Args>(args)...);
223 return value();
224 }
225
226 void reset() noexcept {
227 storage_.clear();
228 }
229
230 void clear() noexcept {
231 reset();
232 }
233
234 void swap(Optional& that) noexcept(IsNothrowSwappable<Value>::value) {
235 if (hasValue() && that.hasValue()) {
236 using std::swap;
237 swap(value(), that.value());
238 } else if (hasValue()) {
239 that.emplace(std::move(value()));
240 reset();
241 } else if (that.hasValue()) {
242 emplace(std::move(that.value()));
243 that.reset();
244 }
245 }
246
247 const Value& value() const& {
248 require_value();
249 return storage_.value;
250 }
251
252 Value& value() & {
253 require_value();
254 return storage_.value;
255 }
256
257 Value&& value() && {
258 require_value();
259 return std::move(storage_.value);
260 }
261
262 const Value&& value() const&& {
263 require_value();
264 return std::move(storage_.value);
265 }
266
267 const Value* get_pointer() const& {
268 return storage_.hasValue ? &storage_.value : nullptr;
269 }
270 Value* get_pointer() & {
271 return storage_.hasValue ? &storage_.value : nullptr;
272 }
273 Value* get_pointer() && = delete;
274
275 bool has_value() const noexcept {
276 return storage_.hasValue;
277 }
278
279 bool hasValue() const noexcept {
280 return has_value();
281 }
282
283 explicit operator bool() const noexcept {
284 return has_value();
285 }
286
287 const Value& operator*() const& {
288 return value();
289 }
290 Value& operator*() & {
291 return value();
292 }
293 const Value&& operator*() const&& {
294 return std::move(value());
295 }
296 Value&& operator*() && {
297 return std::move(value());
298 }
299
300 const Value* operator->() const {
301 return &value();
302 }
303 Value* operator->() {
304 return &value();
305 }
306
307 // Return a copy of the value if set, or a given default if not.
308 template <class U>
309 Value value_or(U&& dflt) const& {
310 if (storage_.hasValue) {
311 return storage_.value;
312 }
313
314 return std::forward<U>(dflt);
315 }
316
317 template <class U>
318 Value value_or(U&& dflt) && {
319 if (storage_.hasValue) {
320 return std::move(storage_.value);
321 }
322
323 return std::forward<U>(dflt);
324 }
325
326 private:
327 template <class T>
328 friend Optional<_t<std::decay<T>>> make_optional(T&&);
329 template <class T, class... Args>
330 friend Optional<T> make_optional(Args&&... args);
331 template <class T, class U, class... As>
332 friend Optional<T> make_optional(std::initializer_list<U>, As&&...);
333
334 /**
335 * Construct the optional in place, this is duplicated as a non-explicit
336 * constructor to allow returning values that are non-movable from
337 * make_optional using list initialization.
338 *
339 * Until C++17, at which point this will become unnecessary because of
340 * specified prvalue elision.
341 */
342 struct PrivateConstructor {
343 explicit PrivateConstructor() = default;
344 };
345 template <typename... Args>
346 Optional(PrivateConstructor, Args&&... args) noexcept(
347 std::is_constructible<Value, Args&&...>::value) {
348 construct(std::forward<Args>(args)...);
349 }
350
351 void require_value() const {
352 if (!storage_.hasValue) {
353 throw OptionalEmptyException{};
354 }
355 }
356
357 template <class... Args>
358 void construct(Args&&... args) {
359 const void* ptr = &storage_.value;
360 // For supporting const types.
361 new (const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
362 storage_.hasValue = true;
363 }
364
365 struct StorageTriviallyDestructible {
366 union {
367 char emptyState;
368 Value value;
369 };
370 bool hasValue;
371
372 StorageTriviallyDestructible()
373 : emptyState('\0'), hasValue{false} {}
374 void clear() {
375 hasValue = false;
376 }
377 };
378
379 struct StorageNonTriviallyDestructible {
380 union {
381 char emptyState;
382 Value value;
383 };
384 bool hasValue;
385
386 StorageNonTriviallyDestructible() : hasValue{false} {}
387 ~StorageNonTriviallyDestructible() {
388 clear();
389 }
390
391 void clear() {
392 if (hasValue) {
393 hasValue = false;
394 value.~Value();
395 }
396 }
397 };
398
399 using Storage = typename std::conditional<
400 std::is_trivially_destructible<Value>::value,
401 StorageTriviallyDestructible,
402 StorageNonTriviallyDestructible>::type;
403
404 Storage storage_;
405 };
406
407 template <class T>
408 const T* get_pointer(const Optional<T>& opt) {
409 return opt.get_pointer();
410 }
411
412 template <class T>
413 T* get_pointer(Optional<T>& opt) {
414 return opt.get_pointer();
415 }
416
417 template <class T>
418 void swap(Optional<T>& a, Optional<T>& b) noexcept(noexcept(a.swap(b))) {
419 a.swap(b);
420 }
421
422 template <class T>
423 Optional<_t<std::decay<T>>> make_optional(T&& v) {
424 using PrivateConstructor =
425 typename folly::Optional<_t<std::decay<T>>>::PrivateConstructor;
426 return {PrivateConstructor{}, std::forward<T>(v)};
427 }
428
429 template <class T, class... Args>
430 folly::Optional<T> make_optional(Args&&... args) {
431 using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor;
432 return {PrivateConstructor{}, std::forward<Args>(args)...};
433 }
434
435 template <class T, class U, class... Args>
436 folly::Optional<T> make_optional(
437 std::initializer_list<U> il,
438 Args&&... args) {
439 using PrivateConstructor = typename folly::Optional<T>::PrivateConstructor;
440 return {PrivateConstructor{}, il, std::forward<Args>(args)...};
441 }
442
443 ///////////////////////////////////////////////////////////////////////////////
444 // Comparisons.
445
446 template <class U, class V>
447 bool operator==(const Optional<U>& a, const V& b) {
448 return a.hasValue() && a.value() == b;
449 }
450
451 template <class U, class V>
452 bool operator!=(const Optional<U>& a, const V& b) {
453 return !(a == b);
454 }
455
456 template <class U, class V>
457 bool operator==(const U& a, const Optional<V>& b) {
458 return b.hasValue() && b.value() == a;
459 }
460
461 template <class U, class V>
462 bool operator!=(const U& a, const Optional<V>& b) {
463 return !(a == b);
464 }
465
466 template <class U, class V>
467 bool operator==(const Optional<U>& a, const Optional<V>& b) {
468 if (a.hasValue() != b.hasValue()) {
469 return false;
470 }
471 if (a.hasValue()) {
472 return a.value() == b.value();
473 }
474 return true;
475 }
476
477 template <class U, class V>
478 bool operator!=(const Optional<U>& a, const Optional<V>& b) {
479 return !(a == b);
480 }
481
482 template <class U, class V>
483 bool operator<(const Optional<U>& a, const Optional<V>& b) {
484 if (a.hasValue() != b.hasValue()) {
485 return a.hasValue() < b.hasValue();
486 }
487 if (a.hasValue()) {
488 return a.value() < b.value();
489 }
490 return false;
491 }
492
493 template <class U, class V>
494 bool operator>(const Optional<U>& a, const Optional<V>& b) {
495 return b < a;
496 }
497
498 template <class U, class V>
499 bool operator<=(const Optional<U>& a, const Optional<V>& b) {
500 return !(b < a);
501 }
502
503 template <class U, class V>
504 bool operator>=(const Optional<U>& a, const Optional<V>& b) {
505 return !(a < b);
506 }
507
508 // Suppress comparability of Optional<T> with T, despite implicit conversion.
509 template <class V>
510 bool operator<(const Optional<V>&, const V& other) = delete;
511 template <class V>
512 bool operator<=(const Optional<V>&, const V& other) = delete;
513 template <class V>
514 bool operator>=(const Optional<V>&, const V& other) = delete;
515 template <class V>
516 bool operator>(const Optional<V>&, const V& other) = delete;
517 template <class V>
518 bool operator<(const V& other, const Optional<V>&) = delete;
519 template <class V>
520 bool operator<=(const V& other, const Optional<V>&) = delete;
521 template <class V>
522 bool operator>=(const V& other, const Optional<V>&) = delete;
523 template <class V>
524 bool operator>(const V& other, const Optional<V>&) = delete;
525
526 // Comparisons with none
527 template <class V>
528 bool operator==(const Optional<V>& a, None) noexcept {
529 return !a.hasValue();
530 }
531 template <class V>
532 bool operator==(None, const Optional<V>& a) noexcept {
533 return !a.hasValue();
534 }
535 template <class V>
536 bool operator<(const Optional<V>&, None) noexcept {
537 return false;
538 }
539 template <class V>
540 bool operator<(None, const Optional<V>& a) noexcept {
541 return a.hasValue();
542 }
543 template <class V>
544 bool operator>(const Optional<V>& a, None) noexcept {
545 return a.hasValue();
546 }
547 template <class V>
548 bool operator>(None, const Optional<V>&) noexcept {
549 return false;
550 }
551 template <class V>
552 bool operator<=(None, const Optional<V>&) noexcept {
553 return true;
554 }
555 template <class V>
556 bool operator<=(const Optional<V>& a, None) noexcept {
557 return !a.hasValue();
558 }
559 template <class V>
560 bool operator>=(const Optional<V>&, None) noexcept {
561 return true;
562 }
563 template <class V>
564 bool operator>=(None, const Optional<V>& a) noexcept {
565 return !a.hasValue();
566 }
567
568 ///////////////////////////////////////////////////////////////////////////////
569
570 } // namespace folly