| /* |
| * Copyright 2015 Facebook, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef FOLLY_OPTIONAL_H_ |
| #define FOLLY_OPTIONAL_H_ |
| |
| /* |
| * Optional - For conditional initialization of values, like boost::optional, |
| * but with support for move semantics and emplacement. Reference type support |
| * has not been included due to limited use cases and potential confusion with |
| * semantics of assignment: Assigning to an optional reference could quite |
| * reasonably copy its value or redirect the reference. |
| * |
| * Optional can be useful when a variable might or might not be needed: |
| * |
| * Optional<Logger> maybeLogger = ...; |
| * if (maybeLogger) { |
| * maybeLogger->log("hello"); |
| * } |
| * |
| * Optional enables a 'null' value for types which do not otherwise have |
| * nullability, especially useful for parameter passing: |
| * |
| * void testIterator(const unique_ptr<Iterator>& it, |
| * initializer_list<int> idsExpected, |
| * Optional<initializer_list<int>> ranksExpected = none) { |
| * for (int i = 0; it->next(); ++i) { |
| * EXPECT_EQ(it->doc().id(), idsExpected[i]); |
| * if (ranksExpected) { |
| * EXPECT_EQ(it->doc().rank(), (*ranksExpected)[i]); |
| * } |
| * } |
| * } |
| * |
| * Optional models OptionalPointee, so calling 'get_pointer(opt)' will return a |
| * pointer to nullptr if the 'opt' is empty, and a pointer to the value if it is |
| * not: |
| * |
| * Optional<int> maybeInt = ...; |
| * if (int* v = get_pointer(maybeInt)) { |
| * cout << *v << endl; |
| * } |
| */ |
| #include <cstddef> |
| #include <stdexcept> |
| #include <type_traits> |
| #include <utility> |
| |
| #include <boost/operators.hpp> |
| |
| #include <folly/Portability.h> |
| |
| namespace folly { |
| |
| namespace detail { struct NoneHelper {}; } |
| |
| typedef int detail::NoneHelper::*None; |
| |
| const None none = nullptr; |
| |
| /** |
| * gcc-4.7 warns about use of uninitialized memory around the use of storage_ |
| * even though this is explicitly initialized at each point. |
| */ |
| #if defined(__GNUC__) && !defined(__clang__) |
| # pragma GCC diagnostic push |
| # pragma GCC diagnostic ignored "-Wuninitialized" |
| # pragma GCC diagnostic ignored "-Wpragmas" |
| # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" |
| #endif // __GNUC__ |
| |
| class OptionalEmptyException : public std::runtime_error { |
| public: |
| OptionalEmptyException() |
| : std::runtime_error("Empty Optional cannot be unwrapped") {} |
| }; |
| |
| template<class Value> |
| class Optional { |
| public: |
| static_assert(!std::is_reference<Value>::value, |
| "Optional may not be used with reference types"); |
| static_assert(!std::is_abstract<Value>::value, |
| "Optional may not be used with abstract types"); |
| |
| Optional() |
| : hasValue_(false) { |
| } |
| |
| Optional(const Optional& src) |
| noexcept(std::is_nothrow_copy_constructible<Value>::value) { |
| |
| if (src.hasValue()) { |
| construct(src.value()); |
| } else { |
| hasValue_ = false; |
| } |
| } |
| |
| Optional(Optional&& src) |
| noexcept(std::is_nothrow_move_constructible<Value>::value) { |
| |
| if (src.hasValue()) { |
| construct(std::move(src.value())); |
| src.clear(); |
| } else { |
| hasValue_ = false; |
| } |
| } |
| |
| /* implicit */ Optional(const None&) noexcept |
| : hasValue_(false) { |
| } |
| |
| /* implicit */ Optional(Value&& newValue) |
| noexcept(std::is_nothrow_move_constructible<Value>::value) { |
| construct(std::move(newValue)); |
| } |
| |
| /* implicit */ Optional(const Value& newValue) |
| noexcept(std::is_nothrow_copy_constructible<Value>::value) { |
| construct(newValue); |
| } |
| |
| ~Optional() noexcept { |
| clear(); |
| } |
| |
| void assign(const None&) { |
| clear(); |
| } |
| |
| void assign(Optional&& src) { |
| if (this != &src) { |
| if (src.hasValue()) { |
| assign(std::move(src.value())); |
| src.clear(); |
| } else { |
| clear(); |
| } |
| } |
| } |
| |
| void assign(const Optional& src) { |
| if (src.hasValue()) { |
| assign(src.value()); |
| } else { |
| clear(); |
| } |
| } |
| |
| void assign(Value&& newValue) { |
| if (hasValue()) { |
| value_ = std::move(newValue); |
| } else { |
| construct(std::move(newValue)); |
| } |
| } |
| |
| void assign(const Value& newValue) { |
| if (hasValue()) { |
| value_ = newValue; |
| } else { |
| construct(newValue); |
| } |
| } |
| |
| template<class Arg> |
| Optional& operator=(Arg&& arg) { |
| assign(std::forward<Arg>(arg)); |
| return *this; |
| } |
| |
| Optional& operator=(Optional &&other) |
| noexcept (std::is_nothrow_move_assignable<Value>::value) { |
| |
| assign(std::move(other)); |
| return *this; |
| } |
| |
| Optional& operator=(const Optional &other) |
| noexcept (std::is_nothrow_copy_assignable<Value>::value) { |
| |
| assign(other); |
| return *this; |
| } |
| |
| template<class... Args> |
| void emplace(Args&&... args) { |
| clear(); |
| construct(std::forward<Args>(args)...); |
| } |
| |
| void clear() { |
| if (hasValue()) { |
| hasValue_ = false; |
| value_.~Value(); |
| } |
| } |
| |
| const Value& value() const& { |
| require_value(); |
| return value_; |
| } |
| |
| Value& value() & { |
| require_value(); |
| return value_; |
| } |
| |
| Value value() && { |
| require_value(); |
| return std::move(value_); |
| } |
| |
| const Value* get_pointer() const& { return hasValue_ ? &value_ : nullptr; } |
| Value* get_pointer() & { return hasValue_ ? &value_ : nullptr; } |
| Value* get_pointer() && = delete; |
| |
| bool hasValue() const { return hasValue_; } |
| |
| explicit operator bool() const { |
| return hasValue(); |
| } |
| |
| const Value& operator*() const& { return value(); } |
| Value& operator*() & { return value(); } |
| Value operator*() && { return std::move(value()); } |
| |
| const Value* operator->() const { return &value(); } |
| Value* operator->() { return &value(); } |
| |
| // Return a copy of the value if set, or a given default if not. |
| template <class U> |
| Value value_or(U&& dflt) const& { |
| return hasValue_ ? value_ : std::forward<U>(dflt); |
| } |
| |
| template <class U> |
| Value value_or(U&& dflt) && { |
| return hasValue_ ? std::move(value_) : std::forward<U>(dflt); |
| } |
| |
| private: |
| void require_value() const { |
| if (!hasValue_) { |
| throw OptionalEmptyException(); |
| } |
| } |
| |
| template<class... Args> |
| void construct(Args&&... args) { |
| const void* ptr = &value_; |
| // for supporting const types |
| new(const_cast<void*>(ptr)) Value(std::forward<Args>(args)...); |
| hasValue_ = true; |
| } |
| |
| // uninitialized |
| union { Value value_; }; |
| bool hasValue_; |
| }; |
| |
| #if defined(__GNUC__) && !defined(__clang__) |
| #pragma GCC diagnostic pop |
| #endif |
| |
| template<class T> |
| const T* get_pointer(const Optional<T>& opt) { |
| return opt.get_pointer(); |
| } |
| |
| template<class T> |
| T* get_pointer(Optional<T>& opt) { |
| return opt.get_pointer(); |
| } |
| |
| template<class T> |
| void swap(Optional<T>& a, Optional<T>& b) { |
| if (a.hasValue() && b.hasValue()) { |
| // both full |
| using std::swap; |
| swap(a.value(), b.value()); |
| } else if (a.hasValue() || b.hasValue()) { |
| std::swap(a, b); // fall back to default implementation if they're mixed. |
| } |
| } |
| |
| template<class T, |
| class Opt = Optional<typename std::decay<T>::type>> |
| Opt make_optional(T&& v) { |
| return Opt(std::forward<T>(v)); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Comparisons. |
| |
| template<class V> |
| bool operator==(const Optional<V>& a, const V& b) { |
| return a.hasValue() && a.value() == b; |
| } |
| |
| template<class V> |
| bool operator!=(const Optional<V>& a, const V& b) { |
| return !(a == b); |
| } |
| |
| template<class V> |
| bool operator==(const V& a, const Optional<V>& b) { |
| return b.hasValue() && b.value() == a; |
| } |
| |
| template<class V> |
| bool operator!=(const V& a, const Optional<V>& b) { |
| return !(a == b); |
| } |
| |
| template<class V> |
| bool operator==(const Optional<V>& a, const Optional<V>& b) { |
| if (a.hasValue() != b.hasValue()) { return false; } |
| if (a.hasValue()) { return a.value() == b.value(); } |
| return true; |
| } |
| |
| template<class V> |
| bool operator!=(const Optional<V>& a, const Optional<V>& b) { |
| return !(a == b); |
| } |
| |
| template<class V> |
| bool operator< (const Optional<V>& a, const Optional<V>& b) { |
| if (a.hasValue() != b.hasValue()) { return a.hasValue() < b.hasValue(); } |
| if (a.hasValue()) { return a.value() < b.value(); } |
| return false; |
| } |
| |
| template<class V> |
| bool operator> (const Optional<V>& a, const Optional<V>& b) { |
| return b < a; |
| } |
| |
| template<class V> |
| bool operator<=(const Optional<V>& a, const Optional<V>& b) { |
| return !(b < a); |
| } |
| |
| template<class V> |
| bool operator>=(const Optional<V>& a, const Optional<V>& b) { |
| return !(a < b); |
| } |
| |
| // Suppress comparability of Optional<T> with T, despite implicit conversion. |
| template<class V> bool operator< (const Optional<V>&, const V& other) = delete; |
| template<class V> bool operator<=(const Optional<V>&, const V& other) = delete; |
| template<class V> bool operator>=(const Optional<V>&, const V& other) = delete; |
| template<class V> bool operator> (const Optional<V>&, const V& other) = delete; |
| template<class V> bool operator< (const V& other, const Optional<V>&) = delete; |
| template<class V> bool operator<=(const V& other, const Optional<V>&) = delete; |
| template<class V> bool operator>=(const V& other, const Optional<V>&) = delete; |
| template<class V> bool operator> (const V& other, const Optional<V>&) = delete; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| } // namespace folly |
| |
| #endif // FOLLY_OPTIONAL_H_ |