omni/Expected.h
File members: omni/Expected.h
// Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#pragma once
#include "detail/ExpectedImpl.h"
namespace omni
{
template <typename TValue, typename TError>
class expected;
template <typename TError>
class unexpected : public omni::detail::UnexpectedImpl<TError>
{
using base_impl = omni::detail::UnexpectedImpl<TError>;
template <typename UError>
friend class unexpected;
public:
using base_impl::base_impl;
template <
typename UError,
typename IsNoexcept = std::enable_if_t<
carb::cpp::conjunction<
std::is_same<TError, UError>,
typename omni::detail::ExpectedTransformIfNonVoid<carb::cpp::is_swappable, UError, std::true_type>::type>::value,
typename omni::detail::ExpectedTransformIfNonVoid<carb::cpp::is_nothrow_swappable, UError, std::true_type>::type>>
constexpr void swap(unexpected& other) noexcept(IsNoexcept::value)
{
base_impl::swap(static_cast<base_impl&>(other));
}
template <typename UError,
typename IsNoexcept = std::enable_if_t<
omni::detail::ExpectedTransformIfNonVoid<carb::cpp::is_swappable, UError, std::true_type>::type::value,
typename omni::detail::ExpectedTransformIfNonVoid<carb::cpp::is_nothrow_swappable, UError, std::true_type>::type>>
friend constexpr void swap(unexpected& lhs, unexpected<UError>& rhs) noexcept(IsNoexcept::value)
{
lhs.swap(rhs);
}
template <typename UError>
constexpr bool operator==(unexpected<UError> const& other) const
{
static_assert(std::is_void<TError>::value == std::is_void<UError>::value, "Can not compare void and non-void");
return base_impl::operator==(other);
}
template <typename UError>
friend constexpr bool operator==(unexpected const& lhs, unexpected<UError> const& rhs)
{
return lhs.operator==(rhs);
}
};
#if CARB_HAS_CPP17
template <typename T>
unexpected(T) -> unexpected<T>;
unexpected()->unexpected<void>;
#endif
struct unexpect_t;
template <typename TValue, typename TError>
class CARB_NODISCARD_TYPE expected : public omni::detail::ExpectedImpl<TValue, TError>
{
private:
using base_impl = omni::detail::ExpectedImpl<TValue, TError>;
public:
using value_type = TValue;
using error_type = TError;
using unexpected_type = unexpected<error_type>;
template <typename UValue>
using rebind = expected<UValue, error_type>;
public:
using base_impl::base_impl;
expected() = default;
expected(expected const& src) = default;
expected(expected&& src) = default;
expected& operator=(expected const& src) = default;
expected& operator=(expected&& src) = default;
~expected() = default;
template <typename UValue = TValue,
std::enable_if_t<omni::detail::IsExpectedDirectConstructibleFrom<UValue, expected>::is_explicit, bool> = true>
constexpr explicit expected(UValue&& src) : base_impl(carb::cpp::in_place, std::forward<UValue>(src))
{
}
#ifndef DOXYGEN_BUILD
template <typename UValue = TValue,
std::enable_if_t<!omni::detail::IsExpectedDirectConstructibleFrom<UValue, expected>::is_explicit, bool> = false>
constexpr expected(UValue&& src) : base_impl(carb::cpp::in_place, std::forward<UValue>(src))
{
}
#endif
template <typename UValue,
typename UError,
std::enable_if_t<omni::detail::IsExpectedCopyConstructibleFrom<expected<UValue, UError>, expected>::is_explicit,
bool> = true>
constexpr explicit expected(expected<UValue, UError> const& src)
: base_impl(::omni::detail::ExpectedCtorBypass{}, src)
{
}
#ifndef DOXYGEN_BUILD
template <typename UValue,
typename UError,
std::enable_if_t<!omni::detail::IsExpectedCopyConstructibleFrom<expected<UValue, UError>, expected>::is_explicit,
bool> = false>
constexpr expected(expected<UValue, UError> const& src) : base_impl(::omni::detail::ExpectedCtorBypass{}, src)
{
}
#endif
template <typename UValue,
typename UError,
std::enable_if_t<omni::detail::IsExpectedMoveConstructibleFrom<expected<UValue, UError>, expected>::is_explicit,
bool> = true>
constexpr explicit expected(expected<UValue, UError>&& src)
: base_impl(::omni::detail::ExpectedCtorBypass{}, std::move(src))
{
}
#ifndef DOXYGEN_BUILD
template <typename UValue,
typename UError,
std::enable_if_t<!omni::detail::IsExpectedMoveConstructibleFrom<expected<UValue, UError>, expected>::is_explicit,
bool> = false>
constexpr expected(expected<UValue, UError>&& src) : base_impl(::omni::detail::ExpectedCtorBypass{}, std::move(src))
{
}
#endif
template <typename UError,
std::enable_if_t<carb::cpp::conjunction<std::is_constructible<TError, UError const&>,
carb::cpp::negation<std::is_convertible<UError const&, TError>>>::value,
bool> = true>
constexpr explicit expected(unexpected<UError> const& src) : base_impl(unexpect, src.error())
{
}
#ifndef DOXYGEN_BUILD
template <typename UError,
std::enable_if_t<carb::cpp::conjunction<std::is_constructible<TError, UError const&>,
std::is_convertible<UError const&, TError>>::value,
bool> = false>
constexpr expected(unexpected<UError> const& src) : base_impl(unexpect, src.error())
{
}
#endif
template <typename UError,
std::enable_if_t<carb::cpp::conjunction<std::is_constructible<TError, UError&&>,
carb::cpp::negation<std::is_convertible<UError&&, TError>>>::value,
bool> = true>
constexpr explicit expected(unexpected<UError>&& src) : base_impl(unexpect, std::move(src).error())
{
}
#ifndef DOXYGEN_BUILD
template <typename UError,
std::enable_if_t<carb::cpp::conjunction<std::is_constructible<TError, UError&&>,
std::is_convertible<UError&&, TError>>::value,
bool> = false>
constexpr expected(unexpected<UError>&& src) : base_impl(unexpect, std::move(src).error())
{
}
#endif
constexpr bool has_value() const noexcept
{
return this->m_state == ::omni::detail::ExpectedState::eSUCCESS;
}
constexpr explicit operator bool() const noexcept
{
return this->has_value();
}
#ifdef DOXYGEN_BUILD
constexpr value_type& value() &;
constexpr value_type const& value() const&;
constexpr value_type&& value() &&;
constexpr value_type const&& value() const&&;
template <typename UValue>
constexpr value_type value_or(UValue&& default_value) const&;
template <typename UValue>
constexpr value_type value_or(UValue&& default_value) &&;
constexpr error_type& error() & noexcept;
constexpr error_type const& error() const& noexcept;
constexpr error_type&& error() && noexcept;
constexpr error_type const&& error() const&& noexcept;
constexpr value_type* operator->() noexcept;
constexpr value_type const* operator->() const noexcept;
constexpr value_type& operator*() & noexcept;
constexpr value_type const& operator*() const& noexcept;
constexpr value_type&& operator*() && noexcept;
constexpr value_type const&& operator*() const&& noexcept;
template <typename... TArgs>
value_type& emplace(TArgs&&... args) noexcept;
void emplace() noexcept;
#endif
template <typename F>
constexpr auto transform(F&& f) const&
{
return ::omni::detail::ExpectedOpTransform<F, expected, expected const&>::transform(std::forward<F>(f), *this);
}
template <typename F>
constexpr auto transform(F&& f) &
{
return ::omni::detail::ExpectedOpTransform<F, expected, expected&>::transform(std::forward<F>(f), *this);
}
template <typename F>
constexpr auto transform(F&& f) &&
{
return ::omni::detail::ExpectedOpTransform<F, expected, expected&&>::transform(
std::forward<F>(f), std::move(*this));
}
template <typename F>
constexpr auto transform(F&& f) const&&
{
return ::omni::detail::ExpectedOpTransform<F, expected, expected const&&>::transform(
std::forward<F>(f), std::move(*this));
}
template <typename F>
constexpr auto and_then(F&& f) const&
{
return ::omni::detail::ExpectedOpAndThen<F, expected, expected const&>::and_then(std::forward<F>(f), *this);
}
template <typename F>
constexpr auto and_then(F&& f) &
{
return ::omni::detail::ExpectedOpAndThen<F, expected, expected&>::and_then(std::forward<F>(f), *this);
}
template <typename F>
constexpr auto and_then(F&& f) &&
{
return ::omni::detail::ExpectedOpAndThen<F, expected, expected&&>::and_then(std::forward<F>(f), std::move(*this));
}
template <typename F>
constexpr auto and_then(F&& f) const&&
{
return ::omni::detail::ExpectedOpAndThen<F, expected, expected const&&>::and_then(
std::forward<F>(f), std::move(*this));
}
template <typename F>
constexpr auto transform_error(F&& f) const&
{
return ::omni::detail::ExpectedOpTransformError<F, expected, expected const&>::transform_error(
std::forward<F>(f), *this);
}
template <typename F>
constexpr auto transform_error(F&& f) &
{
return ::omni::detail::ExpectedOpTransformError<F, expected, expected&>::transform_error(
std::forward<F>(f), *this);
}
template <typename F>
constexpr auto transform_error(F&& f) &&
{
return ::omni::detail::ExpectedOpTransformError<F, expected, expected&&>::transform_error(
std::forward<F>(f), std::move(*this));
}
template <typename F>
constexpr auto transform_error(F&& f) const&&
{
return ::omni::detail::ExpectedOpTransformError<F, expected, expected const&&>::transform_error(
std::forward<F>(f), std::move(*this));
}
template <typename F>
constexpr auto or_else(F&& f) const&
{
return ::omni::detail::ExpectedOpOrElse<F, expected, expected const&>::or_else(std::forward<F>(f), *this);
}
template <typename F>
constexpr auto or_else(F&& f) &
{
return ::omni::detail::ExpectedOpOrElse<F, expected, expected&>::or_else(std::forward<F>(f), *this);
}
template <typename F>
constexpr auto or_else(F&& f) &&
{
return ::omni::detail::ExpectedOpOrElse<F, expected, expected&&>::or_else(std::forward<F>(f), std::move(*this));
}
template <typename F>
constexpr auto or_else(F&& f) const&&
{
return ::omni::detail::ExpectedOpOrElse<F, expected, expected const&&>::or_else(
std::forward<F>(f), std::move(*this));
}
};
template <typename TValueLhs, typename TErrorLhs, typename TValueRhs, typename TErrorRhs>
constexpr bool operator==(expected<TValueLhs, TErrorLhs> const& lhs, expected<TValueRhs, TErrorRhs> const& rhs)
{
static_assert(std::is_void<TValueLhs>::value == std::is_void<TValueRhs>::value,
"Can not compare expected of non-void `value_type` with one of void `value_type`");
static_assert(std::is_void<TErrorLhs>::value == std::is_void<TErrorRhs>::value,
"Can not compare expected of non-void `error_type` with one of void `error_type`");
return ::omni::detail::ExpectedComparer<expected<TValueLhs, TErrorLhs>, expected<TValueRhs, TErrorRhs>>::eq(lhs, rhs);
}
template <typename TValueLhs, typename TErrorLhs, typename TValueRhs>
constexpr bool operator==(expected<TValueLhs, TErrorLhs> const& lhs, TValueRhs const& rhs)
{
static_assert(!std::is_void<TValueLhs>::value, "Can not compare void-valued expected with value");
return lhs.has_value() && static_cast<bool>(lhs.value() == rhs);
}
template <typename TValueLhs, typename TErrorLhs, typename TErrorRhs>
constexpr bool operator==(expected<TValueLhs, TErrorLhs> const& lhs, unexpected<TErrorRhs> const& rhs)
{
static_assert(!std::is_void<TErrorLhs>::value && std::is_void<TErrorRhs>::value,
"Can not compare expected of non-void `error_type` with unexpected<void>");
static_assert(std::is_void<TErrorLhs>::value && !std::is_void<TErrorRhs>::value,
"Can not compare expected of void `error_type` with unexpected of non-void `error_type`");
return ::omni::detail::ExpectedUnexpectedComparer<TErrorLhs, TErrorRhs>::eq(lhs, rhs);
}
} // namespace omni