X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/53b27422d140022594fc241cca91c3183be57bca..48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff:/iOS/Pods/Realm/include/core/realm/util/optional.hpp diff --git a/iOS/Pods/Realm/include/core/realm/util/optional.hpp b/iOS/Pods/Realm/include/core/realm/util/optional.hpp new file mode 100644 index 0000000..29a8be1 --- /dev/null +++ b/iOS/Pods/Realm/include/core/realm/util/optional.hpp @@ -0,0 +1,728 @@ +/************************************************************************* + * + * Copyright 2016 Realm 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. + * + **************************************************************************/ + +#pragma once +#ifndef REALM_UTIL_OPTIONAL_HPP +#define REALM_UTIL_OPTIONAL_HPP + +#include + +#include // std::logic_error +#include // std::less + +namespace realm { +namespace util { + +template +class Optional; + +// some() should be the equivalent of the proposed C++17 `make_optional`. +template +Optional some(Args&&...); +template +struct Some; + +// Note: Should conform with the future std::nullopt_t and std::in_place_t. +struct None { + constexpr explicit None(int) + { + } +}; +static constexpr None none{0}; +struct InPlace { + constexpr InPlace() + { + } +}; +static constexpr InPlace in_place; + +// Note: Should conform with the future std::bad_optional_access. +struct BadOptionalAccess : std::logic_error { + explicit BadOptionalAccess(const std::string& what_arg) + : std::logic_error(what_arg) + { + } + explicit BadOptionalAccess(const char* what_arg) + : std::logic_error(what_arg) + { + } +}; + +} // namespace util + +namespace _impl { + +template ::value> +struct OptionalStorage; + +template +struct TypeIsAssignableToOptional { + // Constraints from [optional.object.assign.18] + static const bool value = (std::is_same::type, T>::value && + std::is_constructible::value && std::is_assignable::value); +}; + +} // namespace _impl + +namespace util { + +// Note: Should conform with the future std::optional. +template +class Optional : private _impl::OptionalStorage { +public: + using value_type = T; + + constexpr Optional(); + constexpr Optional(None); + Optional(Optional&& other); + Optional(const Optional& other); + + constexpr Optional(T&& value); + constexpr Optional(const T& value); + + template + constexpr Optional(InPlace tag, Args&&...); + // FIXME: std::optional specifies an std::initializer_list constructor overload as well. + + Optional& operator=(None); + Optional& operator=(Optional&& other); + Optional& operator=(const Optional& other); + + template ::value>::type> + Optional& operator=(U&& value); + + explicit constexpr operator bool() const; + constexpr const T& value() const; // Throws + T& value(); // Throws, FIXME: Can be constexpr with C++14 + constexpr const T& operator*() const; // Throws + T& operator*(); // Throws, FIXME: Can be constexpr with C++14 + constexpr const T* operator->() const; // Throws + T* operator->(); // Throws, FIXME: Can be constexpr with C++14 + + template + constexpr T value_or(U&& value) const &; + + template + T value_or(U&& value) &&; + + void swap(Optional& other); // FIXME: Add noexcept() clause + + template + void emplace(Args&&...); + // FIXME: std::optional specifies an std::initializer_list overload for `emplace` as well. +private: + using Storage = _impl::OptionalStorage; + using Storage::m_engaged; + using Storage::m_value; + + constexpr bool is_engaged() const + { + return m_engaged; + } + void set_engaged(bool b) + { + m_engaged = b; + } + void clear(); +}; + +/// An Optional is functionally equivalent to a bool. +/// Note: C++17 does not (yet) specify this specialization, but it is convenient +/// as a "safer bool", especially in the presence of `fmap`. +/// Disabled for compliance with std::optional. +// template <> +// class Optional { +// public: +// Optional() {} +// Optional(None) {} +// Optional(Optional&&) = default; +// Optional(const Optional&) = default; +// explicit operator bool() const { return m_engaged; } +// private: +// bool m_engaged = false; +// friend struct Some; +// }; + +/// An Optional is a non-owning nullable pointer that throws on dereference. +// FIXME: Visual Studio 2015's constexpr support isn't sufficient to allow Optional to compile +// in constexpr contexts. +template +class Optional { +public: + using value_type = T&; + using target_type = typename std::decay::type; + + constexpr Optional() + { + } + constexpr Optional(None) + { + } // FIXME: Was a delegating constructor, but not fully supported in VS2015 + Optional(const Optional& other) = default; + template + Optional(const Optional& other) + : m_ptr(other.m_ptr) + { + } + template + Optional(std::reference_wrapper ref) + : m_ptr(&ref.get()) + { + } + + constexpr Optional(T& init_value) + : m_ptr(&init_value) + { + } + Optional(T&& value) = delete; // Catches accidental references to rvalue temporaries. + + Optional& operator=(None) + { + m_ptr = nullptr; + return *this; + } + Optional& operator=(const Optional& other) + { + m_ptr = other.m_ptr; + return *this; + } + + template + Optional& operator=(std::reference_wrapper ref) + { + m_ptr = &ref.get(); + return *this; + } + + explicit constexpr operator bool() const + { + return m_ptr; + } + constexpr const target_type& value() const; // Throws + target_type& value(); // Throws + constexpr const target_type& operator*() const + { + return value(); + } + target_type& operator*() + { + return value(); + } + constexpr const target_type* operator->() const + { + return &value(); + } + target_type* operator->() + { + return &value(); + } + + void swap(Optional other); // FIXME: Add noexcept() clause +private: + T* m_ptr = nullptr; + + template + friend class Optional; +}; + + +template +struct RemoveOptional { + using type = T; +}; +template +struct RemoveOptional> { + using type = typename RemoveOptional::type; // Remove recursively +}; + + +/// Implementation: + +template +struct Some { + template + static Optional some(Args&&... args) + { + return Optional{std::forward(args)...}; + } +}; + +/// Disabled for compliance with std::optional. +// template <> +// struct Some { +// static Optional some() +// { +// Optional opt; +// opt.m_engaged = true; +// return opt; +// } +// }; + +template +Optional some(Args&&... args) +{ + return Some::some(std::forward(args)...); +} + + +template +constexpr Optional::Optional() + : Storage(none) +{ +} + +template +constexpr Optional::Optional(None) + : Storage(none) +{ +} + +template +Optional::Optional(Optional&& other) + : Storage(none) +{ + if (other.m_engaged) { + new (&m_value) T(std::move(other.m_value)); + m_engaged = true; + } +} + +template +Optional::Optional(const Optional& other) + : Storage(none) +{ + if (other.m_engaged) { + new (&m_value) T(other.m_value); + m_engaged = true; + } +} + +template +constexpr Optional::Optional(T&& r_value) + : Storage(std::move(r_value)) +{ +} + +template +constexpr Optional::Optional(const T& l_value) + : Storage(l_value) +{ +} + +template +template +constexpr Optional::Optional(InPlace, Args&&... args) + : Storage(std::forward(args)...) +{ +} + +template +void Optional::clear() +{ + if (m_engaged) { + m_value.~T(); + m_engaged = false; + } +} + +template +Optional& Optional::operator=(None) +{ + clear(); + return *this; +} + +template +Optional& Optional::operator=(Optional&& other) +{ + if (m_engaged) { + if (other.m_engaged) { + m_value = std::move(other.m_value); + } + else { + clear(); + } + } + else { + if (other.m_engaged) { + new (&m_value) T(std::move(other.m_value)); + m_engaged = true; + } + } + return *this; +} + +template +Optional& Optional::operator=(const Optional& other) +{ + if (m_engaged) { + if (other.m_engaged) { + m_value = other.m_value; + } + else { + clear(); + } + } + else { + if (other.m_engaged) { + new (&m_value) T(other.m_value); + m_engaged = true; + } + } + return *this; +} + +template +template +Optional& Optional::operator=(U&& r_value) +{ + if (m_engaged) { + m_value = std::forward(r_value); + } + else { + new (&m_value) T(std::forward(r_value)); + m_engaged = true; + } + return *this; +} + +template +constexpr Optional::operator bool() const +{ + return m_engaged; +} + +template +constexpr const T& Optional::value() const +{ + return m_engaged ? m_value : (throw BadOptionalAccess{"bad optional access"}, m_value); +} + +template +T& Optional::value() +{ + if (!m_engaged) { + throw BadOptionalAccess{"bad optional access"}; + } + return m_value; +} + +template +constexpr const typename Optional::target_type& Optional::value() const +{ + return m_ptr ? *m_ptr : (throw BadOptionalAccess{"bad optional access"}, *m_ptr); +} + +template +typename Optional::target_type& Optional::value() +{ + if (!m_ptr) { + throw BadOptionalAccess{"bad optional access"}; + } + return *m_ptr; +} + +template +constexpr const T& Optional::operator*() const +{ + // Note: This differs from std::optional, which doesn't throw. + return value(); +} + +template +T& Optional::operator*() +{ + // Note: This differs from std::optional, which doesn't throw. + return value(); +} + +template +constexpr const T* Optional::operator->() const +{ + // Note: This differs from std::optional, which doesn't throw. + return &value(); +} + +template +T* Optional::operator->() +{ + // Note: This differs from std::optional, which doesn't throw. + return &value(); +} + +template +template +constexpr T Optional::value_or(U&& otherwise) const & +{ + return m_engaged ? T{m_value} : T{std::forward(otherwise)}; +} + +template +template +T Optional::value_or(U&& otherwise) && +{ + if (is_engaged()) { + return T(std::move(m_value)); + } + else { + return T(std::forward(otherwise)); + } +} + +template +void Optional::swap(Optional& other) +{ + // FIXME: This might be optimizable. + Optional tmp = std::move(other); + other = std::move(*this); + *this = std::move(tmp); +} + +template +template +void Optional::emplace(Args&&... args) +{ + clear(); + new (&m_value) T(std::forward(args)...); + m_engaged = true; +} + + +template +constexpr Optional::type> make_optional(T&& value) +{ + using Type = typename std::decay::type; + return some(std::forward(value)); +} + +template +bool operator==(const Optional& lhs, const Optional& rhs) +{ + if (!lhs && !rhs) { + return true; + } + if (lhs && rhs) { + return *lhs == *rhs; + } + return false; +} + +template +bool operator!=(const Optional& lhs, const Optional& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator<(const Optional& lhs, const Optional& rhs) +{ + if (!rhs) { + return false; + } + if (!lhs) { + return true; + } + return std::less{}(*lhs, *rhs); +} + +template +bool operator>(const util::Optional& lhs, const util::Optional& rhs) +{ + if (!lhs) { + return false; + } + if (!rhs) { + return true; + } + return std::greater{}(*lhs, *rhs); +} + +template +bool operator==(const Optional& lhs, None) +{ + return !bool(lhs); +} + +template +bool operator!=(const Optional& lhs, None) +{ + return bool(lhs); +} + +template +bool operator<(const Optional& lhs, None) +{ + static_cast(lhs); + return false; +} + +template +bool operator==(None, const Optional& rhs) +{ + return !bool(rhs); +} + +template +bool operator!=(None, const Optional& rhs) +{ + return bool(rhs); +} + +template +bool operator<(None, const Optional& rhs) +{ + return bool(rhs); +} + +template +bool operator==(const Optional& lhs, const U& rhs) +{ + return lhs ? *lhs == rhs : false; +} + +template +bool operator<(const Optional& lhs, const T& rhs) +{ + return lhs ? std::less{}(*lhs, rhs) : true; +} + +template +bool operator==(const T& lhs, const Optional& rhs) +{ + return rhs ? lhs == *rhs : false; +} + +template +bool operator<(const T& lhs, const Optional& rhs) +{ + return rhs ? std::less{}(lhs, *rhs) : false; +} + +template +auto operator>>(Optional lhs, F&& rhs) -> decltype(fmap(lhs, std::forward(rhs))) +{ + return fmap(lhs, std::forward(rhs)); +} + +template +OS& operator<<(OS& os, const Optional& rhs) +{ + if (rhs) { + os << "some(" << *rhs << ")"; + } + else { + os << "none"; + } + return os; +} + +template +T unwrap(T&& value) +{ + return value; +} + +template +T unwrap(util::Optional&& value) +{ + return *value; +} + +template +T unwrap(const util::Optional& value) +{ + return *value; +} + +template +T unwrap(util::Optional& value) +{ + return *value; +} + +} // namespace util + +namespace _impl { + +// T is trivially destructible. +template +struct OptionalStorage { + union { + T m_value; + char m_null_state; + }; + bool m_engaged = false; + + constexpr OptionalStorage(realm::util::None) + : m_null_state() + { + } + constexpr OptionalStorage(T&& value) + : m_value(std::move(value)) + , m_engaged(true) + { + } + + template + constexpr OptionalStorage(Args&&... args) + : m_value(args...) + , m_engaged(true) + { + } +}; + +// T is not trivially destructible. +template +struct OptionalStorage { + union { + T m_value; + char m_null_state; + }; + bool m_engaged = false; + + constexpr OptionalStorage(realm::util::None) + : m_null_state() + { + } + constexpr OptionalStorage(T&& value) + : m_value(std::move(value)) + , m_engaged(true) + { + } + + template + constexpr OptionalStorage(Args&&... args) + : m_value(args...) + , m_engaged(true) + { + } + + ~OptionalStorage() + { + if (m_engaged) + m_value.~T(); + } +}; + +} // namespace _impl + +using util::none; + +} // namespace realm + +#endif // REALM_UTIL_OPTIONAL_HPP