#pragma once #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 constexpr explicit unexpected(Err && e) : error_(std::forward(e)) {} 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 il, Args &&... args) : error_{il, 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 & x, unexpected & y) { return x.error() == y.error(); } friend constexpr void swap(unexpected & x, unexpected & y) noexcept(noexcept(x.swap(y))) { return x.swap(y); } 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: bad_expected_access(E error) : error_(std::move(error)) {} char const * what() const noexcept override { return error_.c_str(); } 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 > constexpr explicit(!std::is_convertible_v) expected(U && v) : value_(std::in_place_index<0>, std::forward(v)) {} template constexpr explicit(!std::is_convertible_v) expected(unexpected const & e) : value_(std::in_place_index<1>, e.error()) {} template constexpr explicit(!std::is_convertible_v) expected(unexpected && e) : value_(std::in_place_index<1>, std::move(e).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 il, Args &&... args) : value_(std::in_place_index<0>, il, 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 il, Args &&... args) : value_(std::in_place_index<1>, il, 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 & noexcept { if (JVALIDATE_LIKELY(has_value())) { return operator*(); } throw bad_expected_access(error()); } constexpr T & value() & noexcept { if (JVALIDATE_LIKELY(has_value())) { return operator*(); } throw bad_expected_access(std::as_const(error())); } constexpr T && value() && noexcept { if (JVALIDATE_LIKELY(has_value())) { 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 && f) & { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(f)(**this)); } return expected(unexpect, error()); } template constexpr auto transform(F && f) const & { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(f)(**this)); } return expected(unexpect, error()); } template constexpr auto transform(F && f) && { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(f)(*std::move(*this))); } return expected(unexpect, std::move(*this).error()); } template constexpr auto transform_error(F && f) & { using G = std::invoke_result_t; if (has_value()) { return expected(**this); } return expected(unexpect, std::forward(f)(error())); } template constexpr auto transform_error(F && f) const & { using G = std::invoke_result_t; if (has_value()) { return expected(**this); } return expected(unexpect, std::forward(f)(error())); } template constexpr auto transform_error(F && f) && { using G = std::invoke_result_t; if (has_value()) { return expected(*std::move(*this)); } return expected(unexpect, std::forward(f)(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 & e) : value_(std::in_place_index<1>, e.error()) {} template constexpr explicit(!std::is_convertible_v) expected(unexpected && e) : value_(std::in_place_index<1>, std::move(e).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 il, Args &&... args) : value_(std::in_place, il, 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 (JVALIDATE_LIKELY(has_value())) { return operator*(); } throw bad_expected_access(error()); } void value() && noexcept { if (JVALIDATE_LIKELY(has_value())) { 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 && f) & { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(f)()); } return expected(unexpect, error()); } template constexpr auto transform(F && f) const & { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(f)()); } return expected(unexpect, error()); } template constexpr auto transform(F && f) && { using G = std::invoke_result_t; if (has_value()) { return expected(std::forward(f)()); } return expected(unexpect, std::move(*this).error()); } template constexpr auto transform_error(F && f) & { using G = std::invoke_result_t; if (has_value()) { return expected(**this); } return expected(unexpect, std::forward(f)(error())); } template constexpr auto transform_error(F && f) const & { using G = std::invoke_result_t; if (has_value()) { return expected(**this); } return expected(unexpect, std::forward(f)(error())); } template constexpr auto transform_error(F && f) && { using G = std::invoke_result_t; if (has_value()) { return expected(*std::move(*this)); } return expected(unexpect, std::forward(f)(std::move(*this).error())); } private: std::optional value_; }; } #endif namespace jvalidate::detail { inline std::string to_message(std::errc ec) { return std::make_error_code(ec).message(); } }