#pragma once // NOLINTBEGIN(readability-identifier-naming) #include #ifdef __cpp_lib_expected #if __cpp_lib_expected >= 202211L #include namespace jvalidate::detail { using std::expected; using std::unexpected; inline constexpr std::unexpect_t unexpect{}; } #endif #else #include #include #include #include #include namespace jvalidate::detail { inline constexpr struct unexpect_t { } unexpect{}; template class unexpected { public: template requires(not std::same_as>) constexpr explicit unexpected(Err && err) : error_(std::forward(err)) {} template constexpr explicit unexpected(std::in_place_t, Args &&... args) : error_{std::forward(args)...} {} template constexpr explicit unexpected(std::in_place_t, std::initializer_list init, Args &&... args) : error_{init, std::forward(args)...} {} constexpr const E & error() const & noexcept { return error_; } constexpr E & error() & noexcept { return error_; } constexpr E && error() && noexcept { return std::move(error_); } constexpr void swap(unexpected & other) noexcept(std::is_nothrow_swappable_v) { using std::swap; swap(error(), other.error()); } template friend constexpr bool operator==(unexpected const & lhs, unexpected const & rhs) { return lhs.error() == rhs.error(); } friend constexpr void swap(unexpected & lhs, unexpected & rhs) noexcept(noexcept(lhs.swap(rhs))) { return lhs.swap(rhs); } private: E error_; }; template unexpected(E) -> unexpected; template class bad_expected_access; template <> class bad_expected_access : public std::exception { public: char const * what() const noexcept override { return "unexpected"; } }; template class bad_expected_access : public bad_expected_access { public: explicit bad_expected_access(E error) : error_(std::move(error)) {} constexpr const E & error() const & noexcept { return error_; } constexpr E & error() & noexcept { return error_; } constexpr E && error() && noexcept { return std::move(error_); } private: E error_; }; template class expected { public: using value_type = T; using error_type = E; using unexpected_type = unexpected; template using rebind = expected; public: constexpr expected() = default; template constexpr explicit(!std::is_convertible_v && !std::is_convertible_v) expected(expected const & other) { if (other.has_value()) { value_.template emplace<0>(*other); } else { value_.template emplace<1>(other.error()); } } template constexpr explicit(!std::is_convertible_v && !std::is_convertible_v) expected(expected && other) { if (other.has_value()) { value_.template emplace<0>(*std::move(other)); } else { value_.template emplace<1>(std::move(other).error()); } } template > requires(not std::same_as>) constexpr explicit(!std::is_convertible_v) expected(U && val) : value_(std::in_place_index<0>, std::forward(val)) {} template constexpr explicit(!std::is_convertible_v) expected(unexpected const & exp) : value_(std::in_place_index<1>, exp.error()) {} template constexpr explicit(!std::is_convertible_v) expected(unexpected && exp) : value_(std::in_place_index<1>, std::move(exp).error()) {} template constexpr explicit expected(std::in_place_t, Args &&... args) : value_(std::in_place_index<0>, std::forward(args)...) {} template constexpr explicit expected(std::in_place_t, std::initializer_list init, Args &&... args) : value_(std::in_place_index<0>, init, std::forward(args)...) {} template constexpr explicit expected(unexpect_t, Args &&... args) : value_(std::in_place_index<1>, std::forward(args)...) {} template constexpr explicit expected(unexpect_t, std::initializer_list init, Args &&... args) : value_(std::in_place_index<1>, init, std::forward(args)...) {} constexpr explicit operator bool() const noexcept { return has_value(); } constexpr bool has_value() const noexcept { return value_.index() == 0; } constexpr const T * operator->() const noexcept { return std::get_if<0>(&value_); } constexpr T * operator->() noexcept { return std::get_if<0>(&value_); } constexpr const T & operator*() const & noexcept { return *std::get_if<0>(&value_); } constexpr T & operator*() & noexcept { return *std::get_if<0>(&value_); } constexpr T && operator*() && noexcept { return std::move(*std::get_if<0>(&value_)); } constexpr const T & value() const & { if (has_value()) [[likely]] { return operator*(); } throw bad_expected_access(error()); } constexpr T & value() & { if (has_value()) [[likely]] { return operator*(); } throw bad_expected_access(std::as_const(error())); } constexpr T && value() && { if (has_value()) [[likely]] { return std::move(*this).operator*(); } throw bad_expected_access(std::move(error())); } constexpr const E & error() const & noexcept { return *std::get_if<1>(&value_); } constexpr E & error() & noexcept { return *std::get_if<1>(&value_); } constexpr E && error() && noexcept { return std::move(*std::get_if<1>(&value_)); } template constexpr auto transform(F && func) & { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(func)(**this)); } return expected(unexpect, error()); } template constexpr auto transform(F && func) const & { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(func)(**this)); } return expected(unexpect, error()); } template constexpr auto transform(F && func) && { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(func)(*std::move(*this))); } return expected(unexpect, std::move(*this).error()); } template constexpr auto transform_error(F && func) & { using G = std::invoke_result_t; if (has_value()) { return expected(**this); } return expected(unexpect, std::forward(func)(error())); } template constexpr auto transform_error(F && func) const & { using G = std::invoke_result_t; if (has_value()) { return expected(**this); } return expected(unexpect, std::forward(func)(error())); } template constexpr auto transform_error(F && func) && { using G = std::invoke_result_t; if (has_value()) { return expected(*std::move(*this)); } return expected(unexpect, std::forward(func)(std::move(*this).error())); } private: std::variant value_; }; template class expected { public: using value_type = void; using error_type = E; using unexpected_type = unexpected; template using rebind = expected; public: constexpr expected() = default; template constexpr explicit(!std::is_convertible_v) expected(expected const & other) { if (not other.has_value()) { *this = other.error(); } } template constexpr explicit(!std::is_convertible_v) expected(expected && other) { if (not other.has_value()) { *this = std::move(other).error(); } } template constexpr explicit(!std::is_convertible_v) expected(unexpected const & exp) : value_(exp.error()) {} template constexpr explicit(!std::is_convertible_v) expected(unexpected && exp) : value_(std::move(exp).error()) {} constexpr explicit expected(std::in_place_t) {} template constexpr explicit expected(unexpect_t, Args &&... args) : value_(std::in_place, std::forward(args)...) {} template constexpr explicit expected(unexpect_t, std::initializer_list init, Args &&... args) : value_(std::in_place, init, std::forward(args)...) {} constexpr explicit operator bool() const noexcept { return has_value(); } constexpr bool has_value() const noexcept { return not value_.has_value(); } constexpr void operator*() const noexcept {} void value() const & noexcept { if (has_value()) [[likely]] { return operator*(); } throw bad_expected_access(error()); } void value() && noexcept { if (has_value()) [[likely]] { return operator*(); } throw bad_expected_access(std::move(error())); } constexpr const E & error() const & noexcept { return *value_; } constexpr E & error() & noexcept { return *value_; } constexpr E && error() && noexcept { return std::move(*value_); } template constexpr auto transform(F && func) & { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(func)()); } return expected(unexpect, error()); } template constexpr auto transform(F && func) const & { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(func)()); } return expected(unexpect, error()); } template constexpr auto transform(F && func) && { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(func)()); } return expected(unexpect, std::move(*this).error()); } template constexpr auto transform_error(F && func) & { using G = std::invoke_result_t; if (has_value()) { return expected(**this); } return expected(unexpect, std::forward(func)(error())); } template constexpr auto transform_error(F && func) const & { using G = std::invoke_result_t; if (has_value()) { return expected(**this); } return expected(unexpect, std::forward(func)(error())); } template constexpr auto transform_error(F && func) && { using G = std::invoke_result_t; if (has_value()) { return expected(*std::move(*this)); } return expected(unexpect, std::forward(func)(std::move(*this).error())); } private: std::optional value_; }; } #endif namespace jvalidate::detail { inline std::string to_message(std::errc ecode) { return std::make_error_code(ecode).message(); } } // NOLINTEND(readability-identifier-naming)