2 * Copyright 2017 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 * Optional - For conditional initialization of values, like boost::optional,
21 * but with support for move semantics and emplacement. Reference type support
22 * has not been included due to limited use cases and potential confusion with
23 * semantics of assignment: Assigning to an optional reference could quite
24 * reasonably copy its value or redirect the reference.
26 * Optional can be useful when a variable might or might not be needed:
28 * Optional<Logger> maybeLogger = ...;
30 * maybeLogger->log("hello");
33 * Optional enables a 'null' value for types which do not otherwise have
34 * nullability, especially useful for parameter passing:
36 * void testIterator(const unique_ptr<Iterator>& it,
37 * initializer_list<int> idsExpected,
38 * Optional<initializer_list<int>> ranksExpected = none) {
39 * for (int i = 0; it->next(); ++i) {
40 * EXPECT_EQ(it->doc().id(), idsExpected[i]);
41 * if (ranksExpected) {
42 * EXPECT_EQ(it->doc().rank(), (*ranksExpected)[i]);
47 * Optional models OptionalPointee, so calling 'get_pointer(opt)' will return a
48 * pointer to nullptr if the 'opt' is empty, and a pointer to the value if it is
51 * Optional<int> maybeInt = ...;
52 * if (int* v = get_pointer(maybeInt)) {
61 #include <type_traits>
64 #include <folly/Launder.h>
65 #include <folly/Portability.h>
66 #include <folly/Utility.h>
73 // Allow each translation unit to control its own -fexceptions setting.
74 // If exceptions are disabled, std::terminate() will be called instead of
75 // throwing OptionalEmptyException when the condition fails.
76 [[noreturn]] void throw_optional_empty_exception();
79 typedef int detail::NoneHelper::*None;
81 const None none = nullptr;
83 class OptionalEmptyException : public std::runtime_error {
85 OptionalEmptyException()
86 : std::runtime_error("Empty Optional cannot be unwrapped") {}
89 template <class Value>
92 typedef Value value_type;
95 !std::is_reference<Value>::value,
96 "Optional may not be used with reference types");
98 !std::is_abstract<Value>::value,
99 "Optional may not be used with abstract types");
101 Optional() noexcept {}
103 Optional(const Optional& src) noexcept(
104 std::is_nothrow_copy_constructible<Value>::value) {
105 if (src.hasValue()) {
106 storage_.construct(src.value());
110 Optional(Optional&& src) noexcept(
111 std::is_nothrow_move_constructible<Value>::value) {
112 if (src.hasValue()) {
113 storage_.construct(std::move(src.value()));
118 /* implicit */ Optional(const None&) noexcept {}
120 /* implicit */ Optional(Value&& newValue) noexcept(
121 std::is_nothrow_move_constructible<Value>::value) {
122 storage_.construct(std::move(newValue));
125 /* implicit */ Optional(const Value& newValue) noexcept(
126 std::is_nothrow_copy_constructible<Value>::value) {
127 storage_.construct(newValue);
130 template <typename... Args>
131 explicit Optional(in_place_t, Args&&... args) noexcept(
132 std::is_nothrow_constructible<Value, Args...>::value) {
133 storage_.construct(std::forward<Args>(args)...);
136 void assign(const None&) {
140 void assign(Optional&& src) {
142 if (src.hasValue()) {
143 assign(std::move(src.value()));
151 void assign(const Optional& src) {
152 if (src.hasValue()) {
159 void assign(Value&& newValue) {
161 *storage_.value_pointer() = std::move(newValue);
163 storage_.construct(std::move(newValue));
167 void assign(const Value& newValue) {
169 *storage_.value_pointer() = newValue;
171 storage_.construct(newValue);
176 Optional& operator=(Arg&& arg) {
177 assign(std::forward<Arg>(arg));
181 Optional& operator=(Optional&& other) noexcept(
182 std::is_nothrow_move_assignable<Value>::value) {
183 assign(std::move(other));
187 Optional& operator=(const Optional& other) noexcept(
188 std::is_nothrow_copy_assignable<Value>::value) {
193 template <class... Args>
194 void emplace(Args&&... args) {
196 storage_.construct(std::forward<Args>(args)...);
203 const Value& value() const & {
205 return *storage_.value_pointer();
210 return *storage_.value_pointer();
215 return std::move(*storage_.value_pointer());
218 const Value&& value() const && {
220 return std::move(*storage_.value_pointer());
223 const Value* get_pointer() const & {
224 return storage_.value_pointer();
226 Value* get_pointer() & {
227 return storage_.value_pointer();
229 Value* get_pointer() && = delete;
231 bool hasValue() const noexcept {
232 return storage_.hasValue();
235 explicit operator bool() const noexcept {
239 const Value& operator*() const & {
242 Value& operator*() & {
245 const Value&& operator*() const && {
246 return std::move(value());
248 Value&& operator*() && {
249 return std::move(value());
252 const Value* operator->() const {
255 Value* operator->() {
259 // Return a copy of the value if set, or a given default if not.
261 Value value_or(U&& dflt) const & {
262 if (storage_.hasValue()) {
263 return *storage_.value_pointer();
266 return std::forward<U>(dflt);
270 Value value_or(U&& dflt) && {
271 if (storage_.hasValue()) {
272 return std::move(*storage_.value_pointer());
275 return std::forward<U>(dflt);
279 void require_value() const {
280 if (!storage_.hasValue()) {
281 detail::throw_optional_empty_exception();
285 struct StorageTriviallyDestructible {
288 typename std::aligned_storage<sizeof(Value), alignof(Value)>::type
292 StorageTriviallyDestructible() : hasValue_{false} {}
298 struct StorageNonTriviallyDestructible {
301 typename std::aligned_storage<sizeof(Value), alignof(Value)>::type
305 StorageNonTriviallyDestructible() : hasValue_{false} {}
306 ~StorageNonTriviallyDestructible() {
313 launder(reinterpret_cast<Value*>(value_))->~Value();
318 struct Storage : std::conditional<
319 std::is_trivially_destructible<Value>::value,
320 StorageTriviallyDestructible,
321 StorageNonTriviallyDestructible>::type {
322 bool hasValue() const noexcept {
323 return this->hasValue_;
326 Value* value_pointer() {
327 if (this->hasValue_) {
328 return launder(reinterpret_cast<Value*>(this->value_));
333 Value const* value_pointer() const {
334 if (this->hasValue_) {
335 return launder(reinterpret_cast<Value const*>(this->value_));
340 template <class... Args>
341 void construct(Args&&... args) {
342 new (raw_pointer()) Value(std::forward<Args>(args)...);
343 this->hasValue_ = true;
347 void* raw_pointer() {
348 return static_cast<void*>(this->value_);
356 const T* get_pointer(const Optional<T>& opt) {
357 return opt.get_pointer();
361 T* get_pointer(Optional<T>& opt) {
362 return opt.get_pointer();
366 void swap(Optional<T>& a, Optional<T>& b) {
367 if (a.hasValue() && b.hasValue()) {
370 swap(a.value(), b.value());
371 } else if (a.hasValue() || b.hasValue()) {
372 std::swap(a, b); // fall back to default implementation if they're mixed.
376 template <class T, class Opt = Optional<typename std::decay<T>::type>>
377 Opt make_optional(T&& v) {
378 return Opt(std::forward<T>(v));
381 ///////////////////////////////////////////////////////////////////////////////
384 template <class U, class V>
385 bool operator==(const Optional<U>& a, const V& b) {
386 return a.hasValue() && a.value() == b;
389 template <class U, class V>
390 bool operator!=(const Optional<U>& a, const V& b) {
394 template <class U, class V>
395 bool operator==(const U& a, const Optional<V>& b) {
396 return b.hasValue() && b.value() == a;
399 template <class U, class V>
400 bool operator!=(const U& a, const Optional<V>& b) {
404 template <class U, class V>
405 bool operator==(const Optional<U>& a, const Optional<V>& b) {
406 if (a.hasValue() != b.hasValue()) {
410 return a.value() == b.value();
415 template <class U, class V>
416 bool operator!=(const Optional<U>& a, const Optional<V>& b) {
420 template <class U, class V>
421 bool operator<(const Optional<U>& a, const Optional<V>& b) {
422 if (a.hasValue() != b.hasValue()) {
423 return a.hasValue() < b.hasValue();
426 return a.value() < b.value();
431 template <class U, class V>
432 bool operator>(const Optional<U>& a, const Optional<V>& b) {
436 template <class U, class V>
437 bool operator<=(const Optional<U>& a, const Optional<V>& b) {
441 template <class U, class V>
442 bool operator>=(const Optional<U>& a, const Optional<V>& b) {
446 // Suppress comparability of Optional<T> with T, despite implicit conversion.
448 bool operator<(const Optional<V>&, const V& other) = delete;
450 bool operator<=(const Optional<V>&, const V& other) = delete;
452 bool operator>=(const Optional<V>&, const V& other) = delete;
454 bool operator>(const Optional<V>&, const V& other) = delete;
456 bool operator<(const V& other, const Optional<V>&) = delete;
458 bool operator<=(const V& other, const Optional<V>&) = delete;
460 bool operator>=(const V& other, const Optional<V>&) = delete;
462 bool operator>(const V& other, const Optional<V>&) = delete;
464 // Comparisons with none
466 bool operator==(const Optional<V>& a, None) noexcept {
467 return !a.hasValue();
470 bool operator==(None, const Optional<V>& a) noexcept {
471 return !a.hasValue();
474 bool operator<(const Optional<V>&, None) noexcept {
478 bool operator<(None, const Optional<V>& a) noexcept {
482 bool operator>(const Optional<V>& a, None) noexcept {
486 bool operator>(None, const Optional<V>&) noexcept {
490 bool operator<=(None, const Optional<V>&) noexcept {
494 bool operator<=(const Optional<V>& a, None) noexcept {
495 return !a.hasValue();
498 bool operator>=(const Optional<V>&, None) noexcept {
502 bool operator>=(None, const Optional<V>& a) noexcept {
503 return !a.hasValue();
506 ///////////////////////////////////////////////////////////////////////////////
510 // Allow usage of Optional<T> in std::unordered_map and std::unordered_set
511 FOLLY_NAMESPACE_STD_BEGIN
513 struct hash<folly::Optional<T>> {
514 size_t operator()(folly::Optional<T> const& obj) const {
515 if (!obj.hasValue()) {
518 return hash<typename remove_const<T>::type>()(*obj);
521 FOLLY_NAMESPACE_STD_END