mirror of
https://gitlab.com/niansa/SomeBot.git
synced 2025-03-06 20:48:26 +01:00
1594 lines
37 KiB
C++
1594 lines
37 KiB
C++
// https://github.com/vinniefalco/LuaBridge
|
|
// Copyright 2022, Lucio Asnaghi
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#pragma once
|
|
|
|
#include "Config.h"
|
|
|
|
#include <type_traits>
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#if LUABRIDGE_HAS_EXCEPTIONS
|
|
#include <stdexcept>
|
|
#endif
|
|
|
|
namespace luabridge {
|
|
namespace detail {
|
|
using std::swap;
|
|
|
|
template <class T, class... Args>
|
|
T* construct_at(T* ptr, Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value)
|
|
{
|
|
return static_cast<T*>(::new (const_cast<void*>(static_cast<const void*>(ptr))) T(std::forward<Args>(args)...));
|
|
}
|
|
|
|
template <class T, class U, class = void>
|
|
struct is_swappable_with_impl : std::false_type
|
|
{
|
|
};
|
|
|
|
template <class T, class U>
|
|
struct is_swappable_with_impl<T, U, std::void_t<decltype(swap(std::declval<T>(), std::declval<U>()))>>
|
|
: std::true_type
|
|
{
|
|
};
|
|
|
|
template <class T, class U>
|
|
struct is_nothrow_swappable_with_impl
|
|
{
|
|
static constexpr bool value = noexcept(swap(std::declval<T>(), std::declval<U>())) && noexcept(swap(std::declval<U>(), std::declval<T>()));
|
|
|
|
using type = std::bool_constant<value>;
|
|
};
|
|
|
|
template <class T, class U>
|
|
struct is_swappable_with
|
|
: std::conjunction<
|
|
is_swappable_with_impl<std::add_lvalue_reference_t<T>, std::add_lvalue_reference_t<U>>,
|
|
is_swappable_with_impl<std::add_lvalue_reference_t<U>, std::add_lvalue_reference_t<T>>>::type
|
|
{
|
|
};
|
|
|
|
template <class T, class U>
|
|
struct is_nothrow_swappable_with
|
|
: std::conjunction<is_swappable_with<T, U>, is_nothrow_swappable_with_impl<T, U>>::type
|
|
{
|
|
};
|
|
|
|
template <class T>
|
|
struct is_nothrow_swappable
|
|
: std::is_nothrow_swappable_with<std::add_lvalue_reference_t<T>, std::add_lvalue_reference_t<T>>
|
|
{
|
|
};
|
|
} // namespace detail
|
|
|
|
template <class T, class E>
|
|
class Expected;
|
|
|
|
struct UnexpectType
|
|
{
|
|
constexpr UnexpectType() = default;
|
|
};
|
|
|
|
static constexpr const auto& unexpect = UnexpectType();
|
|
|
|
namespace detail {
|
|
template <class T, class E, bool = std::is_default_constructible_v<T>, bool = (std::is_void_v<T> || std::is_trivial_v<T>) && std::is_trivial_v<E>>
|
|
union expected_storage
|
|
{
|
|
public:
|
|
template <class U = T, class = std::enable_if_t<std::is_default_constructible_v<U>>>
|
|
constexpr expected_storage() noexcept
|
|
: value_()
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept
|
|
: value_(std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept
|
|
: error_(std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
~expected_storage() = default;
|
|
|
|
constexpr const T& value() const noexcept
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
constexpr T& value() noexcept
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
constexpr const E& error() const noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
constexpr E& error() noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
private:
|
|
T value_;
|
|
E error_;
|
|
};
|
|
|
|
template <class E>
|
|
union expected_storage<void, E, true, true>
|
|
{
|
|
public:
|
|
constexpr expected_storage() noexcept
|
|
: dummy_(0)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept
|
|
: error_(std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
~expected_storage() = default;
|
|
|
|
constexpr const E& error() const noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
constexpr E& error() noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
private:
|
|
char dummy_;
|
|
E error_;
|
|
};
|
|
|
|
template <class T, class E>
|
|
union expected_storage<T, E, true, false>
|
|
{
|
|
public:
|
|
constexpr expected_storage() noexcept(std::is_nothrow_default_constructible_v<T>)
|
|
: value_()
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
|
|
: value_(std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<E, Args...>)
|
|
: error_(std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
~expected_storage()
|
|
{
|
|
}
|
|
|
|
constexpr const T& value() const noexcept
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
constexpr T& value() noexcept
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
constexpr const E& error() const noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
constexpr E& error() noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
private:
|
|
T value_;
|
|
E error_;
|
|
};
|
|
|
|
template <class T, class E>
|
|
union expected_storage<T, E, false, false>
|
|
{
|
|
public:
|
|
constexpr explicit expected_storage() noexcept
|
|
: dummy_(0)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit expected_storage(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
|
|
: value_(std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<E, Args...>)
|
|
: error_(std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
~expected_storage()
|
|
{
|
|
}
|
|
|
|
constexpr const T& value() const noexcept
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
constexpr T& value() noexcept
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
constexpr const E& error() const noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
constexpr E& error() noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
private:
|
|
char dummy_;
|
|
T value_;
|
|
E error_;
|
|
};
|
|
|
|
|
|
template <class E>
|
|
union expected_storage<void, E, true, false>
|
|
{
|
|
public:
|
|
constexpr expected_storage() noexcept
|
|
: dummy_(0)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit expected_storage(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<E, Args...>)
|
|
: error_(std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
~expected_storage()
|
|
{
|
|
}
|
|
|
|
constexpr const E& error() const noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
constexpr E& error() noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
private:
|
|
char dummy_;
|
|
E error_;
|
|
};
|
|
|
|
template <class T, class E, bool IsCopyConstructible, bool IsMoveConstructible>
|
|
class ExpectedBaseTrivial
|
|
{
|
|
using this_type = ExpectedBaseTrivial<T, E, IsCopyConstructible, IsMoveConstructible>;
|
|
|
|
protected:
|
|
using storage_type = expected_storage<T, E>;
|
|
|
|
constexpr ExpectedBaseTrivial() noexcept
|
|
: valid_(true)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr ExpectedBaseTrivial(std::in_place_t, Args&&... args) noexcept
|
|
: storage_(std::in_place, std::forward<Args>(args)...)
|
|
, valid_(true)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr ExpectedBaseTrivial(UnexpectType, Args&&... args) noexcept
|
|
: storage_(unexpect, std::forward<Args>(args)...)
|
|
, valid_(false)
|
|
{
|
|
}
|
|
|
|
ExpectedBaseTrivial(const ExpectedBaseTrivial& other) noexcept
|
|
{
|
|
if (other.valid_)
|
|
{
|
|
construct(std::in_place, other.value());
|
|
}
|
|
else
|
|
{
|
|
construct(unexpect, other.error());
|
|
}
|
|
}
|
|
|
|
ExpectedBaseTrivial(ExpectedBaseTrivial&& other) noexcept
|
|
{
|
|
if (other.valid_)
|
|
{
|
|
construct(std::in_place, std::move(other.value()));
|
|
}
|
|
else
|
|
{
|
|
construct(unexpect, std::move(other.error()));
|
|
}
|
|
}
|
|
|
|
~ExpectedBaseTrivial() noexcept = default;
|
|
|
|
constexpr const T& value() const noexcept
|
|
{
|
|
return storage_.value();
|
|
}
|
|
|
|
constexpr T& value() noexcept
|
|
{
|
|
return storage_.value();
|
|
}
|
|
|
|
constexpr const E& error() const noexcept
|
|
{
|
|
return storage_.error();
|
|
}
|
|
|
|
constexpr E& error() noexcept
|
|
{
|
|
return storage_.error();
|
|
}
|
|
|
|
constexpr const T* valuePtr() const noexcept
|
|
{
|
|
return std::addressof(value());
|
|
}
|
|
|
|
constexpr T* valuePtr() noexcept
|
|
{
|
|
return std::addressof(value());
|
|
}
|
|
|
|
constexpr const E* errorPtr() const noexcept
|
|
{
|
|
return std::addressof(error());
|
|
}
|
|
|
|
constexpr E* errorPtr() noexcept
|
|
{
|
|
return std::addressof(error());
|
|
}
|
|
|
|
constexpr bool valid() const noexcept
|
|
{
|
|
return valid_;
|
|
}
|
|
|
|
template <class... Args>
|
|
inline T& construct(std::in_place_t, Args&&... args) noexcept
|
|
{
|
|
valid_ = true;
|
|
return *detail::construct_at(valuePtr(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <class... Args>
|
|
inline E& construct(UnexpectType, Args&&... args) noexcept
|
|
{
|
|
valid_ = false;
|
|
return *detail::construct_at(errorPtr(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
inline void destroy() noexcept
|
|
{
|
|
}
|
|
|
|
private:
|
|
storage_type storage_;
|
|
bool valid_;
|
|
};
|
|
|
|
template <class T, class E, bool IsCopyConstructible, bool IsMoveConstructible>
|
|
class ExpectedBaseNonTrivial
|
|
{
|
|
using this_type = ExpectedBaseNonTrivial<T, E, IsCopyConstructible, IsMoveConstructible>;
|
|
|
|
protected:
|
|
using storage_type = expected_storage<T, E>;
|
|
|
|
constexpr ExpectedBaseNonTrivial() noexcept(std::is_nothrow_default_constructible_v<storage_type>)
|
|
: valid_(true)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr ExpectedBaseNonTrivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<storage_type, std::in_place_t, Args...>)
|
|
: storage_(std::in_place, std::forward<Args>(args)...)
|
|
, valid_(true)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr ExpectedBaseNonTrivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<storage_type, UnexpectType, Args...>)
|
|
: storage_(unexpect, std::forward<Args>(args)...)
|
|
, valid_(false)
|
|
{
|
|
}
|
|
|
|
ExpectedBaseNonTrivial(const ExpectedBaseNonTrivial& other)
|
|
{
|
|
if (other.valid_)
|
|
{
|
|
construct(std::in_place, other.value());
|
|
}
|
|
else
|
|
{
|
|
construct(unexpect, other.error());
|
|
}
|
|
}
|
|
|
|
ExpectedBaseNonTrivial(ExpectedBaseNonTrivial&& other)
|
|
{
|
|
if (other.valid_)
|
|
{
|
|
construct(std::in_place, std::move(other.value()));
|
|
}
|
|
else
|
|
{
|
|
construct(unexpect, std::move(other.error()));
|
|
}
|
|
}
|
|
|
|
~ExpectedBaseNonTrivial() noexcept(noexcept(std::declval<this_type>().destroy()))
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
constexpr const T& value() const noexcept
|
|
{
|
|
return storage_.value();
|
|
}
|
|
|
|
constexpr T& value() noexcept
|
|
{
|
|
return storage_.value();
|
|
}
|
|
|
|
constexpr const E& error() const noexcept
|
|
{
|
|
return storage_.error();
|
|
}
|
|
|
|
constexpr E& error() noexcept
|
|
{
|
|
return storage_.error();
|
|
}
|
|
|
|
constexpr const T* valuePtr() const noexcept
|
|
{
|
|
return std::addressof(value());
|
|
}
|
|
|
|
constexpr T* valuePtr() noexcept
|
|
{
|
|
return std::addressof(value());
|
|
}
|
|
|
|
constexpr const E* errorPtr() const noexcept
|
|
{
|
|
return std::addressof(error());
|
|
}
|
|
|
|
constexpr E* errorPtr() noexcept
|
|
{
|
|
return std::addressof(error());
|
|
}
|
|
|
|
constexpr bool valid() const noexcept
|
|
{
|
|
return valid_;
|
|
}
|
|
|
|
template <class... Args>
|
|
inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
|
|
{
|
|
valid_ = true;
|
|
return *detail::construct_at(valuePtr(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <class... Args>
|
|
inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<E, Args...>)
|
|
{
|
|
valid_ = false;
|
|
return *detail::construct_at(errorPtr(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
inline void destroy() noexcept(std::is_nothrow_destructible_v<T>&& std::is_nothrow_destructible_v<E>)
|
|
{
|
|
if (valid_)
|
|
{
|
|
std::destroy_at(valuePtr());
|
|
}
|
|
else
|
|
{
|
|
std::destroy_at(errorPtr());
|
|
}
|
|
}
|
|
|
|
private:
|
|
storage_type storage_;
|
|
bool valid_;
|
|
};
|
|
|
|
template <class T, class E, bool IsMoveConstructible>
|
|
class ExpectedBaseNonTrivial<T, E, false, IsMoveConstructible>
|
|
{
|
|
using this_type = ExpectedBaseNonTrivial<T, E, false, IsMoveConstructible>;
|
|
|
|
protected:
|
|
using storage_type = expected_storage<T, E>;
|
|
|
|
constexpr ExpectedBaseNonTrivial() noexcept(std::is_nothrow_default_constructible_v<storage_type>)
|
|
: valid_(true)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr ExpectedBaseNonTrivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<storage_type, std::in_place_t, Args...>)
|
|
: storage_(std::in_place, std::forward<Args>(args)...)
|
|
, valid_(true)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr ExpectedBaseNonTrivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<storage_type, UnexpectType, Args...>)
|
|
: storage_(unexpect, std::forward<Args>(args)...)
|
|
, valid_(false)
|
|
{
|
|
}
|
|
|
|
ExpectedBaseNonTrivial(const ExpectedBaseNonTrivial& other) = delete;
|
|
|
|
ExpectedBaseNonTrivial(ExpectedBaseNonTrivial&& other)
|
|
{
|
|
if (other.valid_)
|
|
{
|
|
construct(std::in_place, std::move(other.value()));
|
|
}
|
|
else
|
|
{
|
|
construct(unexpect, std::move(other.error()));
|
|
}
|
|
}
|
|
|
|
~ExpectedBaseNonTrivial() noexcept(noexcept(std::declval<this_type>().destroy()))
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
constexpr const T& value() const noexcept
|
|
{
|
|
return storage_.value();
|
|
}
|
|
|
|
constexpr T& value() noexcept
|
|
{
|
|
return storage_.value();
|
|
}
|
|
|
|
constexpr const E& error() const noexcept
|
|
{
|
|
return storage_.error();
|
|
}
|
|
|
|
constexpr E& error() noexcept
|
|
{
|
|
return storage_.error();
|
|
}
|
|
|
|
constexpr const T* valuePtr() const noexcept
|
|
{
|
|
return std::addressof(value());
|
|
}
|
|
|
|
constexpr T* valuePtr() noexcept
|
|
{
|
|
return std::addressof(value());
|
|
}
|
|
|
|
constexpr const E* errorPtr() const noexcept
|
|
{
|
|
return std::addressof(error());
|
|
}
|
|
|
|
constexpr E* errorPtr() noexcept
|
|
{
|
|
return std::addressof(error());
|
|
}
|
|
|
|
constexpr bool valid() const noexcept
|
|
{
|
|
return valid_;
|
|
}
|
|
|
|
template <class... Args>
|
|
inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
|
|
{
|
|
valid_ = true;
|
|
return *detail::construct_at(valuePtr(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <class... Args>
|
|
inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<E, Args...>)
|
|
{
|
|
valid_ = false;
|
|
return *detail::construct_at(errorPtr(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
inline void destroy() noexcept(std::is_nothrow_destructible_v<T>&& std::is_nothrow_destructible_v<E>)
|
|
{
|
|
if (valid_)
|
|
{
|
|
std::destroy_at(valuePtr());
|
|
}
|
|
else
|
|
{
|
|
std::destroy_at(errorPtr());
|
|
}
|
|
}
|
|
|
|
private:
|
|
storage_type storage_;
|
|
bool valid_;
|
|
};
|
|
|
|
template <class T, class E, bool IsCopyConstructible>
|
|
class ExpectedBaseNonTrivial<T, E, IsCopyConstructible, false>
|
|
{
|
|
using this_type = ExpectedBaseNonTrivial<T, E, IsCopyConstructible, false>;
|
|
|
|
protected:
|
|
using storage_type = expected_storage<T, E>;
|
|
|
|
template <class U = storage_type, class = std::enable_if_t<std::is_default_constructible_v<U>>>
|
|
constexpr ExpectedBaseNonTrivial() noexcept(std::is_nothrow_default_constructible_v<storage_type>)
|
|
: valid_(true)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr ExpectedBaseNonTrivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<storage_type, std::in_place_t, Args...>)
|
|
: storage_(std::in_place, std::forward<Args>(args)...)
|
|
, valid_(true)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr ExpectedBaseNonTrivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<storage_type, UnexpectType, Args...>)
|
|
: storage_(unexpect, std::forward<Args>(args)...)
|
|
, valid_(false)
|
|
{
|
|
}
|
|
|
|
ExpectedBaseNonTrivial(const ExpectedBaseNonTrivial& other)
|
|
{
|
|
if (other.valid_)
|
|
{
|
|
construct(std::in_place, other.value());
|
|
}
|
|
else
|
|
{
|
|
construct(unexpect, other.error());
|
|
}
|
|
}
|
|
|
|
ExpectedBaseNonTrivial(ExpectedBaseNonTrivial&& other) = delete;
|
|
|
|
~ExpectedBaseNonTrivial() noexcept(noexcept(std::declval<this_type>().destroy()))
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
constexpr const T& value() const noexcept
|
|
{
|
|
return storage_.value();
|
|
}
|
|
|
|
constexpr T& value() noexcept
|
|
{
|
|
return storage_.value();
|
|
}
|
|
|
|
constexpr const E& error() const noexcept
|
|
{
|
|
return storage_.error();
|
|
}
|
|
|
|
constexpr E& error() noexcept
|
|
{
|
|
return storage_.error();
|
|
}
|
|
|
|
constexpr const T* valuePtr() const noexcept
|
|
{
|
|
return std::addressof(value());
|
|
}
|
|
|
|
constexpr T* valuePtr() noexcept
|
|
{
|
|
return std::addressof(value());
|
|
}
|
|
|
|
constexpr const E* errorPtr() const noexcept
|
|
{
|
|
return std::addressof(error());
|
|
}
|
|
|
|
constexpr E* errorPtr() noexcept
|
|
{
|
|
return std::addressof(error());
|
|
}
|
|
|
|
constexpr bool valid() const noexcept
|
|
{
|
|
return valid_;
|
|
}
|
|
|
|
template <class... Args>
|
|
inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
|
|
{
|
|
valid_ = true;
|
|
return *detail::construct_at(valuePtr(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <class... Args>
|
|
inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<E, Args...>)
|
|
{
|
|
valid_ = false;
|
|
return *detail::construct_at(errorPtr(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
inline void destroy() noexcept(std::is_nothrow_destructible_v<T>&& std::is_nothrow_destructible_v<E>)
|
|
{
|
|
if (valid_)
|
|
{
|
|
std::destroy_at(valuePtr());
|
|
}
|
|
else
|
|
{
|
|
std::destroy_at(errorPtr());
|
|
}
|
|
}
|
|
|
|
private:
|
|
storage_type storage_;
|
|
bool valid_;
|
|
};
|
|
|
|
template <class T, class E>
|
|
class ExpectedBaseNonTrivial<T, E, false, false>
|
|
{
|
|
using this_type = ExpectedBaseNonTrivial<T, E, false, false>;
|
|
|
|
protected:
|
|
using storage_type = expected_storage<T, E>;
|
|
|
|
template <class U = storage_type, class = std::enable_if_t<std::is_default_constructible_v<U>>>
|
|
constexpr ExpectedBaseNonTrivial() noexcept(std::is_nothrow_default_constructible_v<storage_type>)
|
|
: valid_(true)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr ExpectedBaseNonTrivial(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<storage_type, std::in_place_t, Args...>)
|
|
: storage_(std::in_place, std::forward<Args>(args)...)
|
|
, valid_(true)
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr ExpectedBaseNonTrivial(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<storage_type, UnexpectType, Args...>)
|
|
: storage_(unexpect, std::forward<Args>(args)...)
|
|
, valid_(false)
|
|
{
|
|
}
|
|
|
|
ExpectedBaseNonTrivial(const ExpectedBaseNonTrivial& other) = delete;
|
|
|
|
ExpectedBaseNonTrivial(ExpectedBaseNonTrivial&& other) = delete;
|
|
|
|
~ExpectedBaseNonTrivial() noexcept(noexcept(std::declval<this_type>().destroy()))
|
|
{
|
|
destroy();
|
|
}
|
|
|
|
constexpr const T& value() const noexcept
|
|
{
|
|
return storage_.value();
|
|
}
|
|
|
|
constexpr T& value() noexcept
|
|
{
|
|
return storage_.value();
|
|
}
|
|
|
|
constexpr const E& error() const noexcept
|
|
{
|
|
return storage_.error();
|
|
}
|
|
|
|
constexpr E& error() noexcept
|
|
{
|
|
return storage_.error();
|
|
}
|
|
|
|
constexpr const T* valuePtr() const noexcept
|
|
{
|
|
return std::addressof(value());
|
|
}
|
|
|
|
constexpr T* valuePtr() noexcept
|
|
{
|
|
return std::addressof(value());
|
|
}
|
|
|
|
constexpr const E* errorPtr() const noexcept
|
|
{
|
|
return std::addressof(error());
|
|
}
|
|
|
|
constexpr E* errorPtr() noexcept
|
|
{
|
|
return std::addressof(error());
|
|
}
|
|
|
|
constexpr bool valid() const noexcept
|
|
{
|
|
return valid_;
|
|
}
|
|
|
|
template <class... Args>
|
|
inline T& construct(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
|
|
{
|
|
valid_ = true;
|
|
return *detail::construct_at(valuePtr(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <class... Args>
|
|
inline E& construct(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<E, Args...>)
|
|
{
|
|
valid_ = false;
|
|
return *detail::construct_at(errorPtr(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
inline void destroy() noexcept(std::is_nothrow_destructible_v<T>&& std::is_nothrow_destructible_v<E>)
|
|
{
|
|
if (valid_)
|
|
{
|
|
std::destroy_at(valuePtr());
|
|
}
|
|
else
|
|
{
|
|
std::destroy_at(errorPtr());
|
|
}
|
|
}
|
|
|
|
private:
|
|
storage_type storage_;
|
|
bool valid_;
|
|
};
|
|
|
|
template <class T, class E, bool IsCopyConstructible, bool IsMoveConstructible>
|
|
using ExpectedBase = std::conditional_t<
|
|
(std::is_void_v<T> || std::is_trivially_destructible_v<T>) && std::is_trivially_destructible_v<E>,
|
|
ExpectedBaseTrivial<T, E, IsCopyConstructible, IsMoveConstructible>,
|
|
ExpectedBaseNonTrivial<T, E, IsCopyConstructible, IsMoveConstructible>>;
|
|
|
|
} // namespace detail
|
|
|
|
template <class E>
|
|
class Unexpected
|
|
{
|
|
static_assert(!std::is_reference_v<E> && !std::is_void_v<E>, "Unexpected type can't be a reference or void");
|
|
|
|
public:
|
|
Unexpected() = delete;
|
|
|
|
constexpr explicit Unexpected(E&& e) noexcept(std::is_nothrow_move_constructible_v<E>)
|
|
: error_(std::move(e))
|
|
{
|
|
}
|
|
|
|
constexpr explicit Unexpected(const E& e) noexcept(std::is_nothrow_copy_constructible_v<E>)
|
|
: error_(e)
|
|
{
|
|
}
|
|
|
|
constexpr const E& value() const& noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
constexpr E& value() & noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
constexpr const E&& value() const&& noexcept
|
|
{
|
|
return std::move(error_);
|
|
}
|
|
|
|
constexpr E&& value() && noexcept
|
|
{
|
|
return std::move(error_);
|
|
}
|
|
|
|
private:
|
|
E error_;
|
|
};
|
|
|
|
template <class E>
|
|
constexpr bool operator==(const Unexpected<E>& lhs, const Unexpected<E>& rhs) noexcept
|
|
{
|
|
return lhs.value() == rhs.value();
|
|
}
|
|
|
|
template <class E>
|
|
constexpr bool operator!=(const Unexpected<E>& lhs, const Unexpected<E>& rhs) noexcept
|
|
{
|
|
return lhs.value() != rhs.value();
|
|
}
|
|
|
|
template <class E>
|
|
constexpr inline Unexpected<std::decay_t<E>> makeUnexpected(E&& error) noexcept(std::is_nothrow_constructible_v<Unexpected<std::decay_t<E>>, E>)
|
|
{
|
|
return Unexpected<std::decay_t<E>>{ std::forward<E>(error) };
|
|
}
|
|
|
|
#if LUABRIDGE_HAS_EXCEPTIONS
|
|
template <class E>
|
|
class BadExpectedAccess;
|
|
|
|
template <>
|
|
class BadExpectedAccess<void> : public std::exception
|
|
{
|
|
public:
|
|
explicit BadExpectedAccess() noexcept
|
|
{
|
|
}
|
|
};
|
|
template <class E>
|
|
class BadExpectedAccess : public BadExpectedAccess<void>
|
|
{
|
|
public:
|
|
explicit BadExpectedAccess(E error) noexcept(std::is_nothrow_constructible_v<E, E&&>)
|
|
: error_(std::move(error))
|
|
{
|
|
}
|
|
|
|
const E& error() const& noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
E& error() & noexcept
|
|
{
|
|
return error_;
|
|
}
|
|
|
|
E&& error() && noexcept
|
|
{
|
|
return std::move(error_);
|
|
}
|
|
|
|
private:
|
|
E error_;
|
|
};
|
|
#endif
|
|
|
|
template <class T>
|
|
struct is_expected : std::false_type
|
|
{
|
|
};
|
|
|
|
template <class T, class E>
|
|
struct is_expected<Expected<T, E>> : std::true_type
|
|
{
|
|
};
|
|
template <class T>
|
|
struct is_unexpected : std::false_type
|
|
{
|
|
};
|
|
|
|
template <class E>
|
|
struct is_unexpected<Unexpected<E>> : std::true_type
|
|
{
|
|
};
|
|
|
|
template <class T, class E>
|
|
class Expected : public detail::ExpectedBase<T, E, std::is_copy_constructible_v<T>, std::is_move_constructible_v<T>>
|
|
{
|
|
static_assert(!std::is_reference_v<E> && !std::is_void_v<E>, "Unexpected type can't be a reference or void");
|
|
|
|
using base_type = detail::ExpectedBase<T, E, std::is_copy_constructible_v<T>, std::is_move_constructible_v<T>>;
|
|
using this_type = Expected<T, E>;
|
|
|
|
public:
|
|
using value_type = T;
|
|
|
|
using error_type = E;
|
|
|
|
using unexpected_type = Unexpected<E>;
|
|
|
|
template <class U>
|
|
struct rebind
|
|
{
|
|
using type = Expected<U, error_type>;
|
|
};
|
|
|
|
template <class U = T, class = std::enable_if_t<std::is_default_constructible_v<U>>>
|
|
constexpr Expected() noexcept(std::is_nothrow_default_constructible_v<base_type>)
|
|
: base_type()
|
|
{
|
|
}
|
|
|
|
constexpr Expected(const Expected& other) noexcept(std::is_nothrow_copy_constructible_v<base_type>) = default;
|
|
|
|
constexpr Expected(Expected&& other) noexcept(std::is_nothrow_move_constructible_v<base_type>) = default;
|
|
|
|
template <class U, class G>
|
|
Expected(const Expected<U, G>& other)
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
this->construct(std::in_place, other.value());
|
|
}
|
|
else
|
|
{
|
|
this->construct(unexpect, other.error());
|
|
}
|
|
}
|
|
|
|
template <class U, class G>
|
|
Expected(Expected<U, G>&& other)
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
this->construct(std::in_place, std::move(other.value()));
|
|
}
|
|
else
|
|
{
|
|
this->construct(unexpect, std::move(other.error()));
|
|
}
|
|
}
|
|
|
|
template <class U = T, std::enable_if_t<!std::is_void_v<T> && std::is_constructible_v<T, U&&> && !std::is_same_v<std::decay_t<U>, std::in_place_t> && !is_expected<std::decay_t<U>>::value && !is_unexpected<std::decay_t<U>>::value, int> = 0>
|
|
constexpr Expected(U&& value) noexcept(std::is_nothrow_constructible_v<base_type, std::in_place_t, U>)
|
|
: base_type(std::in_place, std::forward<U>(value))
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit Expected(std::in_place_t, Args&&... args) noexcept(std::is_nothrow_constructible_v<base_type, std::in_place_t, Args...>)
|
|
: base_type(std::in_place, std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
template <class U, class... Args>
|
|
constexpr explicit Expected(std::in_place_t, std::initializer_list<U> ilist, Args&&... args) noexcept(std::is_nothrow_constructible_v<base_type, std::in_place_t, std::initializer_list<U>, Args...>)
|
|
: base_type(std::in_place, ilist, std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
template <class G = E>
|
|
constexpr Expected(const Unexpected<G>& u) noexcept(std::is_nothrow_constructible_v<base_type, UnexpectType, const G&>)
|
|
: base_type(unexpect, u.value())
|
|
{
|
|
}
|
|
|
|
template <class G = E>
|
|
constexpr Expected(Unexpected<G>&& u) noexcept(std::is_nothrow_constructible_v<base_type, UnexpectType, G&&>)
|
|
: base_type(unexpect, std::move(u.value()))
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit Expected(UnexpectType, Args&&... args) noexcept(std::is_nothrow_constructible_v<base_type, UnexpectType, Args...>)
|
|
: base_type(unexpect, std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
template <class U, class... Args>
|
|
constexpr explicit Expected(UnexpectType, std::initializer_list<U> ilist, Args&&... args) noexcept(std::is_nothrow_constructible_v<base_type, UnexpectType, std::initializer_list<U>, Args...>)
|
|
: base_type(unexpect, ilist, std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
Expected& operator=(const Expected& other)
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
assign(std::in_place, other.value());
|
|
}
|
|
else
|
|
{
|
|
assign(unexpect, other.error());
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
Expected& operator=(Expected&& other)
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
assign(std::in_place, std::move(other.value()));
|
|
}
|
|
else
|
|
{
|
|
assign(unexpect, std::move(other.error()));
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
template <class U = T, std::enable_if_t<!is_expected<std::decay_t<U>>::value && !is_unexpected<std::decay_t<U>>::value, int> = 0>
|
|
Expected& operator=(U&& value)
|
|
{
|
|
assign(std::in_place, std::forward<U>(value));
|
|
return *this;
|
|
}
|
|
|
|
template <class G = E>
|
|
Expected& operator=(const Unexpected<G>& u)
|
|
{
|
|
assign(unexpect, u.value());
|
|
return *this;
|
|
}
|
|
|
|
template <class G = E>
|
|
Expected& operator=(Unexpected<G>&& u)
|
|
{
|
|
assign(unexpect, std::move(u.value()));
|
|
return *this;
|
|
}
|
|
|
|
template <class... Args>
|
|
T& emplace(Args&&... args) noexcept(noexcept(std::declval<this_type>().assign(std::in_place, std::forward<Args>(args)...)))
|
|
{
|
|
return assign(std::in_place, std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <class U, class... Args>
|
|
T& emplace(std::initializer_list<U> ilist, Args&&... args) noexcept(noexcept(std::declval<this_type>().assign(std::in_place, ilist, std::forward<Args>(args)...)))
|
|
{
|
|
return assign(std::in_place, ilist, std::forward<Args>(args)...);
|
|
}
|
|
|
|
void swap(Expected& other) noexcept(detail::is_nothrow_swappable<value_type>::value && detail::is_nothrow_swappable<error_type>::value)
|
|
{
|
|
using std::swap;
|
|
|
|
if (hasValue())
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
swap(value(), other.value());
|
|
}
|
|
else
|
|
{
|
|
E error = std::move(other.error());
|
|
other.assign(std::in_place, std::move(value()));
|
|
assign(unexpect, std::move(error));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
other.swap(*this);
|
|
}
|
|
else
|
|
{
|
|
swap(error(), other.error());
|
|
}
|
|
}
|
|
}
|
|
|
|
constexpr const T* operator->() const
|
|
{
|
|
return base_type::valuePtr();
|
|
}
|
|
|
|
constexpr T* operator->()
|
|
{
|
|
return base_type::valuePtr();
|
|
}
|
|
|
|
constexpr const T& operator*() const&
|
|
{
|
|
return value();
|
|
}
|
|
|
|
constexpr T& operator*() &
|
|
{
|
|
return value();
|
|
}
|
|
|
|
constexpr const T&& operator*() const&&
|
|
{
|
|
return std::move(value());
|
|
}
|
|
|
|
constexpr T&& operator*() &&
|
|
{
|
|
return std::move(value());
|
|
}
|
|
|
|
constexpr explicit operator bool() const noexcept
|
|
{
|
|
return hasValue();
|
|
}
|
|
|
|
constexpr bool hasValue() const noexcept
|
|
{
|
|
return base_type::valid();
|
|
}
|
|
|
|
constexpr const T& value() const&
|
|
{
|
|
#if LUABRIDGE_HAS_EXCEPTIONS
|
|
if (!hasValue())
|
|
throw BadExpectedAccess<E>(error());
|
|
#endif
|
|
|
|
return base_type::value();
|
|
}
|
|
|
|
constexpr T& value() &
|
|
{
|
|
#if LUABRIDGE_HAS_EXCEPTIONS
|
|
if (!hasValue())
|
|
throw BadExpectedAccess<E>(error());
|
|
#endif
|
|
|
|
return base_type::value();
|
|
}
|
|
|
|
constexpr const T&& value() const&& noexcept
|
|
{
|
|
#if LUABRIDGE_HAS_EXCEPTIONS
|
|
if (!hasValue())
|
|
throw BadExpectedAccess<E>(error());
|
|
#endif
|
|
|
|
return std::move(base_type::value());
|
|
}
|
|
|
|
constexpr T&& value() &&
|
|
{
|
|
#if LUABRIDGE_HAS_EXCEPTIONS
|
|
if (!hasValue())
|
|
throw BadExpectedAccess<E>(error());
|
|
#endif
|
|
return std::move(base_type::value());
|
|
}
|
|
|
|
constexpr const E& error() const& noexcept
|
|
{
|
|
return base_type::error();
|
|
}
|
|
|
|
constexpr E& error() & noexcept
|
|
{
|
|
return base_type::error();
|
|
}
|
|
|
|
constexpr const E&& error() const&& noexcept
|
|
{
|
|
return std::move(base_type::error());
|
|
}
|
|
|
|
constexpr E&& error() && noexcept
|
|
{
|
|
return std::move(base_type::error());
|
|
}
|
|
|
|
template <class U>
|
|
constexpr T valueOr(U&& defaultValue) const&
|
|
{
|
|
return hasValue() ? value() : static_cast<T>(std::forward<U>(defaultValue));
|
|
}
|
|
|
|
template <class U>
|
|
T valueOr(U&& defaultValue) &&
|
|
{
|
|
return hasValue() ? std::move(value()) : static_cast<T>(std::forward<U>(defaultValue));
|
|
}
|
|
|
|
private:
|
|
template <class Tag, class... Args>
|
|
auto assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval<this_type>().destroy()) && noexcept(std::declval<this_type>().construct(tag, std::forward<Args>(args)...)))
|
|
-> decltype(std::declval<this_type>().construct(tag, std::forward<Args>(args)...))
|
|
{
|
|
this->destroy();
|
|
|
|
return this->construct(tag, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <class E>
|
|
class Expected<void, E> : public detail::ExpectedBase<void, E, std::is_copy_constructible_v<E>, std::is_move_constructible_v<E>>
|
|
{
|
|
static_assert(!std::is_reference_v<E> && !std::is_void_v<E>, "Unexpected type can't be a reference or void");
|
|
|
|
using base_type = detail::ExpectedBase<void, E, std::is_copy_constructible_v<E>, std::is_move_constructible_v<E>>;
|
|
using this_type = Expected<void, E>;
|
|
|
|
public:
|
|
using value_type = void;
|
|
|
|
using error_type = E;
|
|
|
|
using unexpected_type = Unexpected<E>;
|
|
|
|
template <class U>
|
|
struct rebind
|
|
{
|
|
using type = Expected<U, error_type>;
|
|
};
|
|
|
|
constexpr Expected() = default;
|
|
|
|
constexpr Expected(const Expected& other) = default;
|
|
|
|
constexpr Expected(Expected&& other) = default;
|
|
|
|
template <class G>
|
|
Expected(const Expected<void, G>& other)
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
this->valid_ = true;
|
|
}
|
|
else
|
|
{
|
|
this->construct(unexpect, other.error());
|
|
}
|
|
}
|
|
|
|
template <class G>
|
|
Expected(Expected<void, G>&& other)
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
this->valid_ = true;
|
|
}
|
|
else
|
|
{
|
|
this->construct(unexpect, std::move(other.error()));
|
|
}
|
|
}
|
|
|
|
template <class G = E>
|
|
constexpr Expected(const Unexpected<G>& u)
|
|
: base_type(unexpect, u.value())
|
|
{
|
|
}
|
|
|
|
template <class G = E>
|
|
constexpr Expected(Unexpected<G>&& u)
|
|
: base_type(unexpect, std::move(u.value()))
|
|
{
|
|
}
|
|
|
|
template <class... Args>
|
|
constexpr explicit Expected(UnexpectType, Args&&... args)
|
|
: base_type(unexpect, std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
template <class U, class... Args>
|
|
constexpr explicit Expected(UnexpectType, std::initializer_list<U> ilist, Args&&... args)
|
|
: base_type(unexpect, ilist, std::forward<Args>(args)...)
|
|
{
|
|
}
|
|
|
|
Expected& operator=(const Expected& other)
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
assign(std::in_place);
|
|
}
|
|
else
|
|
{
|
|
assign(unexpect, other.error());
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
Expected& operator=(Expected&& other)
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
assign(std::in_place);
|
|
}
|
|
else
|
|
{
|
|
assign(unexpect, std::move(other.error()));
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
template <class G = E>
|
|
Expected& operator=(const Unexpected<G>& u)
|
|
{
|
|
assign(unexpect, u.value());
|
|
return *this;
|
|
}
|
|
|
|
template <class G = E>
|
|
Expected& operator=(Unexpected<G>&& u)
|
|
{
|
|
assign(unexpect, std::move(u.value()));
|
|
return *this;
|
|
}
|
|
|
|
void swap(Expected& other) noexcept(detail::is_nothrow_swappable<error_type>::value)
|
|
{
|
|
using std::swap;
|
|
|
|
if (hasValue())
|
|
{
|
|
if (!other.hasValue())
|
|
{
|
|
assign(unexpect, std::move(other.error()));
|
|
other.assign(std::in_place);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (other.hasValue())
|
|
{
|
|
other.swap(*this);
|
|
}
|
|
else
|
|
{
|
|
swap(error(), other.error());
|
|
}
|
|
}
|
|
}
|
|
|
|
constexpr explicit operator bool() const noexcept
|
|
{
|
|
return hasValue();
|
|
}
|
|
|
|
constexpr bool hasValue() const noexcept
|
|
{
|
|
return base_type::valid();
|
|
}
|
|
|
|
constexpr const E& error() const& noexcept
|
|
{
|
|
return base_type::error();
|
|
}
|
|
|
|
constexpr E& error() & noexcept
|
|
{
|
|
return base_type::error();
|
|
}
|
|
|
|
constexpr const E&& error() const&& noexcept
|
|
{
|
|
return std::move(base_type::error());
|
|
}
|
|
|
|
constexpr E&& error() && noexcept
|
|
{
|
|
return std::move(base_type::error());
|
|
}
|
|
|
|
private:
|
|
template <class Tag, class... Args>
|
|
void assign(Tag tag, Args&&... args) noexcept(noexcept(std::declval<this_type>().destroy()) && noexcept(std::declval<this_type>().construct(tag, std::forward<Args>(args)...)))
|
|
{
|
|
this->destroy();
|
|
this->construct(tag, std::forward<Args>(args)...);
|
|
}
|
|
};
|
|
|
|
template <class T, class E>
|
|
constexpr bool operator==(const Expected<T, E>& lhs, const Expected<T, E>& rhs)
|
|
{
|
|
return (lhs && rhs) ? *lhs == *rhs : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false);
|
|
}
|
|
|
|
template <class E>
|
|
constexpr bool operator==(const Expected<void, E>& lhs, const Expected<void, E>& rhs)
|
|
{
|
|
return (lhs && rhs) ? true : ((!lhs && !rhs) ? lhs.error() == rhs.error() : false);
|
|
}
|
|
|
|
template <class T, class E>
|
|
constexpr bool operator!=(const Expected<T, E>& lhs, const Expected<T, E>& rhs)
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
template <class T, class E>
|
|
constexpr bool operator==(const Expected<T, E>& lhs, const T& rhs)
|
|
{
|
|
return lhs ? *lhs == rhs : false;
|
|
}
|
|
|
|
template <class T, class E>
|
|
constexpr bool operator==(const T& lhs, const Expected<T, E>& rhs)
|
|
{
|
|
return rhs == lhs;
|
|
}
|
|
|
|
template <class T, class E>
|
|
constexpr bool operator!=(const Expected<T, E>& lhs, const T& rhs)
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
template <class T, class E>
|
|
constexpr bool operator!=(const T& lhs, const Expected<T, E>& rhs)
|
|
{
|
|
return rhs != lhs;
|
|
}
|
|
|
|
template <class T, class E>
|
|
constexpr bool operator==(const Expected<T, E>& lhs, const Unexpected<E>& rhs)
|
|
{
|
|
return lhs ? false : lhs.error() == rhs.value();
|
|
}
|
|
|
|
template <class T, class E>
|
|
constexpr bool operator==(const Unexpected<E>& lhs, const Expected<T, E>& rhs)
|
|
{
|
|
return rhs == lhs;
|
|
}
|
|
|
|
template <class T, class E>
|
|
constexpr bool operator!=(const Expected<T, E>& lhs, const Unexpected<E>& rhs)
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
template <class T, class E>
|
|
constexpr bool operator!=(const Unexpected<E>& lhs, const Expected<T, E>& rhs)
|
|
{
|
|
return rhs != lhs;
|
|
}
|
|
} // namespace luabridge
|