<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/

#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;

// FIXME: Callers should switch to std::move when we adopt C++14
template<class T>
inline constexpr typename std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept
{
    return static_cast<typename std::remove_reference<T>::type&&>(t);
}

// FIXME: Callers should switch to std::forward when we adopt C++14
template<class T>
inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type& t) noexcept
{
    return static_cast<T&&>(t);
}

// FIXME: Callers should switch to std::forward when we adopt C++14
template<class T>
inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type&& t) noexcept
{
    static_assert(!std::is_lvalue_reference<T>::value, "Can't forward rvalue as lvalue.");
    return static_cast<T&&>(t);
}

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() : m_ptr(nullptr) {}
    constexpr Optional(None) : m_ptr(nullptr) {}
    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& value) : m_ptr(&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<commit_msg>Removed superfluous member initialization.<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/

#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;

// FIXME: Callers should switch to std::move when we adopt C++14
template<class T>
inline constexpr typename std::remove_reference<T>::type&& constexpr_move(T&& t) noexcept
{
    return static_cast<typename std::remove_reference<T>::type&&>(t);
}

// FIXME: Callers should switch to std::forward when we adopt C++14
template<class T>
inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type& t) noexcept
{
    return static_cast<T&&>(t);
}

// FIXME: Callers should switch to std::forward when we adopt C++14
template<class T>
inline constexpr T&& constexpr_forward(typename std::remove_reference<T>::type&& t) noexcept
{
    static_assert(!std::is_lvalue_reference<T>::value, "Can't forward rvalue as lvalue.");
    return static_cast<T&&>(t);
}

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& value) : m_ptr(&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
{'fraction_non_alphanumeric': 0.15054906128232376, 'fraction_numerical': 0.004675876726886291, 'mean_word_length': 4.153705732018985, 'pattern_counts': {'":': 0, '<': 137, '<?xml version=': 0, '>': 145, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5689741', 'n_tokens_mistral': 4229, 'n_tokens_neox': 4069, 'n_words': 1305}