added iOS source code
[wl-app.git] / 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 (file)
index 0000000..29a8be1
--- /dev/null
@@ -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 <realm/util/features.h>
+
+#include <stdexcept>  // std::logic_error
+#include <functional> // std::less
+
+namespace realm {
+namespace util {
+
+template <class T>
+class Optional;
+
+// some() should be the equivalent of the proposed C++17 `make_optional`.
+template <class T, class... Args>
+Optional<T> some(Args&&...);
+template <class T>
+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 <class T, bool = std::is_trivially_destructible<T>::value>
+struct OptionalStorage;
+
+template <class T, class U>
+struct TypeIsAssignableToOptional {
+    // Constraints from [optional.object.assign.18]
+    static const bool value = (std::is_same<typename std::remove_reference<U>::type, T>::value &&
+                               std::is_constructible<T, U>::value && std::is_assignable<T&, U>::value);
+};
+
+} // namespace _impl
+
+namespace util {
+
+// Note: Should conform with the future std::optional.
+template <class T>
+class Optional : private _impl::OptionalStorage<T> {
+public:
+    using value_type = T;
+
+    constexpr Optional();
+    constexpr Optional(None);
+    Optional(Optional<T>&& other);
+    Optional(const Optional<T>& other);
+
+    constexpr Optional(T&& value);
+    constexpr Optional(const T& value);
+
+    template <class... Args>
+    constexpr Optional(InPlace tag, Args&&...);
+    // FIXME: std::optional specifies an std::initializer_list constructor overload as well.
+
+    Optional<T>& operator=(None);
+    Optional<T>& operator=(Optional<T>&& other);
+    Optional<T>& operator=(const Optional<T>& other);
+
+    template <class U, class = typename std::enable_if<_impl::TypeIsAssignableToOptional<T, U>::value>::type>
+    Optional<T>& 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 <class U>
+    constexpr T value_or(U&& value) const &;
+
+    template <class U>
+    T value_or(U&& value) &&;
+
+    void swap(Optional<T>& other); // FIXME: Add noexcept() clause
+
+    template <class... Args>
+    void emplace(Args&&...);
+    // FIXME: std::optional specifies an std::initializer_list overload for `emplace` as well.
+private:
+    using Storage = _impl::OptionalStorage<T>;
+    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<void> 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<void> {
+// public:
+//     Optional() {}
+//     Optional(None) {}
+//     Optional(Optional<void>&&) = default;
+//     Optional(const Optional<void>&) = default;
+//     explicit operator bool() const { return m_engaged; }
+// private:
+//     bool m_engaged = false;
+//     friend struct Some<void>;
+// };
+
+/// An Optional<T&> is a non-owning nullable pointer that throws on dereference.
+// FIXME: Visual Studio 2015's constexpr support isn't sufficient to allow Optional<T&> to compile
+// in constexpr contexts.
+template <class T>
+class Optional<T&> {
+public:
+    using value_type = T&;
+    using target_type = typename std::decay<T>::type;
+
+    constexpr Optional()
+    {
+    }
+    constexpr Optional(None)
+    {
+    } // FIXME: Was a delegating constructor, but not fully supported in VS2015
+    Optional(const Optional<T&>& other) = default;
+    template <class U>
+    Optional(const Optional<U&>& other)
+        : m_ptr(other.m_ptr)
+    {
+    }
+    template <class U>
+    Optional(std::reference_wrapper<U> 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<T&>& operator=(None)
+    {
+        m_ptr = nullptr;
+        return *this;
+    }
+    Optional<T&>& operator=(const Optional<T&>& other)
+    {
+        m_ptr = other.m_ptr;
+        return *this;
+    }
+
+    template <class U>
+    Optional<T&>& operator=(std::reference_wrapper<U> 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<T&> other); // FIXME: Add noexcept() clause
+private:
+    T* m_ptr = nullptr;
+
+    template <class U>
+    friend class Optional;
+};
+
+
+template <class T>
+struct RemoveOptional {
+    using type = T;
+};
+template <class T>
+struct RemoveOptional<Optional<T>> {
+    using type = typename RemoveOptional<T>::type; // Remove recursively
+};
+
+
+/// Implementation:
+
+template <class T>
+struct Some {
+    template <class... Args>
+    static Optional<T> some(Args&&... args)
+    {
+        return Optional<T>{std::forward<Args>(args)...};
+    }
+};
+
+/// Disabled for compliance with std::optional.
+// template <>
+// struct Some<void> {
+//     static Optional<void> some()
+//     {
+//         Optional<void> opt;
+//         opt.m_engaged = true;
+//         return opt;
+//     }
+// };
+
+template <class T, class... Args>
+Optional<T> some(Args&&... args)
+{
+    return Some<T>::some(std::forward<Args>(args)...);
+}
+
+
+template <class T>
+constexpr Optional<T>::Optional()
+    : Storage(none)
+{
+}
+
+template <class T>
+constexpr Optional<T>::Optional(None)
+    : Storage(none)
+{
+}
+
+template <class T>
+Optional<T>::Optional(Optional<T>&& other)
+    : Storage(none)
+{
+    if (other.m_engaged) {
+        new (&m_value) T(std::move(other.m_value));
+        m_engaged = true;
+    }
+}
+
+template <class T>
+Optional<T>::Optional(const Optional<T>& other)
+    : Storage(none)
+{
+    if (other.m_engaged) {
+        new (&m_value) T(other.m_value);
+        m_engaged = true;
+    }
+}
+
+template <class T>
+constexpr Optional<T>::Optional(T&& r_value)
+    : Storage(std::move(r_value))
+{
+}
+
+template <class T>
+constexpr Optional<T>::Optional(const T& l_value)
+    : Storage(l_value)
+{
+}
+
+template <class T>
+template <class... Args>
+constexpr Optional<T>::Optional(InPlace, Args&&... args)
+    : Storage(std::forward<Args>(args)...)
+{
+}
+
+template <class T>
+void Optional<T>::clear()
+{
+    if (m_engaged) {
+        m_value.~T();
+        m_engaged = false;
+    }
+}
+
+template <class T>
+Optional<T>& Optional<T>::operator=(None)
+{
+    clear();
+    return *this;
+}
+
+template <class T>
+Optional<T>& Optional<T>::operator=(Optional<T>&& 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 <class T>
+Optional<T>& Optional<T>::operator=(const Optional<T>& 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 <class T>
+template <class U, class>
+Optional<T>& Optional<T>::operator=(U&& r_value)
+{
+    if (m_engaged) {
+        m_value = std::forward<U>(r_value);
+    }
+    else {
+        new (&m_value) T(std::forward<U>(r_value));
+        m_engaged = true;
+    }
+    return *this;
+}
+
+template <class T>
+constexpr Optional<T>::operator bool() const
+{
+    return m_engaged;
+}
+
+template <class T>
+constexpr const T& Optional<T>::value() const
+{
+    return m_engaged ? m_value : (throw BadOptionalAccess{"bad optional access"}, m_value);
+}
+
+template <class T>
+T& Optional<T>::value()
+{
+    if (!m_engaged) {
+        throw BadOptionalAccess{"bad optional access"};
+    }
+    return m_value;
+}
+
+template <class T>
+constexpr const typename Optional<T&>::target_type& Optional<T&>::value() const
+{
+    return m_ptr ? *m_ptr : (throw BadOptionalAccess{"bad optional access"}, *m_ptr);
+}
+
+template <class T>
+typename Optional<T&>::target_type& Optional<T&>::value()
+{
+    if (!m_ptr) {
+        throw BadOptionalAccess{"bad optional access"};
+    }
+    return *m_ptr;
+}
+
+template <class T>
+constexpr const T& Optional<T>::operator*() const
+{
+    // Note: This differs from std::optional, which doesn't throw.
+    return value();
+}
+
+template <class T>
+T& Optional<T>::operator*()
+{
+    // Note: This differs from std::optional, which doesn't throw.
+    return value();
+}
+
+template <class T>
+constexpr const T* Optional<T>::operator->() const
+{
+    // Note: This differs from std::optional, which doesn't throw.
+    return &value();
+}
+
+template <class T>
+T* Optional<T>::operator->()
+{
+    // Note: This differs from std::optional, which doesn't throw.
+    return &value();
+}
+
+template <class T>
+template <class U>
+constexpr T Optional<T>::value_or(U&& otherwise) const &
+{
+    return m_engaged ? T{m_value} : T{std::forward<U>(otherwise)};
+}
+
+template <class T>
+template <class U>
+T Optional<T>::value_or(U&& otherwise) &&
+{
+    if (is_engaged()) {
+        return T(std::move(m_value));
+    }
+    else {
+        return T(std::forward<U>(otherwise));
+    }
+}
+
+template <class T>
+void Optional<T>::swap(Optional<T>& other)
+{
+    // FIXME: This might be optimizable.
+    Optional<T> tmp = std::move(other);
+    other = std::move(*this);
+    *this = std::move(tmp);
+}
+
+template <class T>
+template <class... Args>
+void Optional<T>::emplace(Args&&... args)
+{
+    clear();
+    new (&m_value) T(std::forward<Args>(args)...);
+    m_engaged = true;
+}
+
+
+template <class T>
+constexpr Optional<typename std::decay<T>::type> make_optional(T&& value)
+{
+    using Type = typename std::decay<T>::type;
+    return some<Type>(std::forward<T>(value));
+}
+
+template <class T>
+bool operator==(const Optional<T>& lhs, const Optional<T>& rhs)
+{
+    if (!lhs && !rhs) {
+        return true;
+    }
+    if (lhs && rhs) {
+        return *lhs == *rhs;
+    }
+    return false;
+}
+
+template <class T>
+bool operator!=(const Optional<T>& lhs, const Optional<T>& rhs)
+{
+    return !(lhs == rhs);
+}
+
+template <class T>
+bool operator<(const Optional<T>& lhs, const Optional<T>& rhs)
+{
+    if (!rhs) {
+        return false;
+    }
+    if (!lhs) {
+        return true;
+    }
+    return std::less<T>{}(*lhs, *rhs);
+}
+
+template <class T>
+bool operator>(const util::Optional<T>& lhs, const util::Optional<T>& rhs)
+{
+    if (!lhs) {
+        return false;
+    }
+    if (!rhs) {
+        return true;
+    }
+    return std::greater<T>{}(*lhs, *rhs);
+}
+
+template <class T>
+bool operator==(const Optional<T>& lhs, None)
+{
+    return !bool(lhs);
+}
+
+template <class T>
+bool operator!=(const Optional<T>& lhs, None)
+{
+    return bool(lhs);
+}
+
+template <class T>
+bool operator<(const Optional<T>& lhs, None)
+{
+    static_cast<void>(lhs);
+    return false;
+}
+
+template <class T>
+bool operator==(None, const Optional<T>& rhs)
+{
+    return !bool(rhs);
+}
+
+template <class T>
+bool operator!=(None, const Optional<T>& rhs)
+{
+    return bool(rhs);
+}
+
+template <class T>
+bool operator<(None, const Optional<T>& rhs)
+{
+    return bool(rhs);
+}
+
+template <class T, class U>
+bool operator==(const Optional<T>& lhs, const U& rhs)
+{
+    return lhs ? *lhs == rhs : false;
+}
+
+template <class T>
+bool operator<(const Optional<T>& lhs, const T& rhs)
+{
+    return lhs ? std::less<T>{}(*lhs, rhs) : true;
+}
+
+template <class T, class U>
+bool operator==(const T& lhs, const Optional<U>& rhs)
+{
+    return rhs ? lhs == *rhs : false;
+}
+
+template <class T>
+bool operator<(const T& lhs, const Optional<T>& rhs)
+{
+    return rhs ? std::less<T>{}(lhs, *rhs) : false;
+}
+
+template <class T, class F>
+auto operator>>(Optional<T> lhs, F&& rhs) -> decltype(fmap(lhs, std::forward<F>(rhs)))
+{
+    return fmap(lhs, std::forward<F>(rhs));
+}
+
+template <class OS, class T>
+OS& operator<<(OS& os, const Optional<T>& rhs)
+{
+    if (rhs) {
+        os << "some(" << *rhs << ")";
+    }
+    else {
+        os << "none";
+    }
+    return os;
+}
+
+template <class T>
+T unwrap(T&& value)
+{
+    return value;
+}
+
+template <class T>
+T unwrap(util::Optional<T>&& value)
+{
+    return *value;
+}
+
+template <class T>
+T unwrap(const util::Optional<T>& value)
+{
+    return *value;
+}
+
+template <class T>
+T unwrap(util::Optional<T>& value)
+{
+    return *value;
+}
+
+} // namespace util
+
+namespace _impl {
+
+// T is trivially destructible.
+template <class T>
+struct OptionalStorage<T, true> {
+    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 <class... Args>
+    constexpr OptionalStorage(Args&&... args)
+        : m_value(args...)
+        , m_engaged(true)
+    {
+    }
+};
+
+// T is not trivially destructible.
+template <class T>
+struct OptionalStorage<T, false> {
+    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 <class... Args>
+    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