/* Unit testing for outcomes (C) 2017-2026 Niall Douglas (7 commits) Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define BOOST_OUTCOME_SYSTEM_ERROR2_FATAL(msg) abort() #include #include // for INT_MAX #include // status_code> using error = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::error; // Outcome's result must be told when it is dealing with an erased status code template using result = BOOST_OUTCOME_V2_NAMESPACE::experimental::status_result; enum class arithmetic_errc { success, divide_by_zero, integer_divide_overflows, not_integer_division }; class _arithmetic_errc_domain; using arithmetic_errc_error = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<_arithmetic_errc_domain>; class _arithmetic_errc_domain : public BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code_domain { using _base = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code_domain; public: using value_type = arithmetic_errc; constexpr explicit _arithmetic_errc_domain(typename _base::unique_id_type id = 0x290f170194f0c6c7) noexcept : _base(id) { } static inline constexpr const _arithmetic_errc_domain &get(); protected: virtual int _do_name(_vtable_name_args &args) const noexcept override final { args.ret = string_ref("arithmetic error domain"); return 0; } virtual void _do_payload_info(_vtable_payload_info_args &args) const noexcept override final { args.ret = {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type), (alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)}; } virtual bool _do_failure(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code &code) const noexcept override final // NOLINT { assert(code.domain() == *this); // NOLINT const auto &c1 = static_cast(code); // NOLINT return c1.value() != arithmetic_errc::success; } virtual bool _do_equivalent(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code &, const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code &) const noexcept override final { return false; } // NOLINT virtual void _do_generic_code(_vtable_generic_code_args &args) const noexcept override final { args.ret = {}; } virtual int _do_message(_vtable_message_args &args) const noexcept override final { assert(args.code.domain() == *this); // NOLINT const auto &c1 = static_cast(args.code); // NOLINT switch(c1.value()) { case arithmetic_errc::success: args.ret = _base::string_ref("success"); return 0; case arithmetic_errc::divide_by_zero: args.ret = _base::string_ref("divide by zero"); return 0; case arithmetic_errc::integer_divide_overflows: args.ret = _base::string_ref("integer divide overflows"); return 0; case arithmetic_errc::not_integer_division: args.ret = _base::string_ref("not integer division"); return 0; } args.ret = _base::string_ref("unknown"); return 0; } BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code &) const override final { abort(); } // NOLINT }; constexpr _arithmetic_errc_domain arithmetic_errc_domain; inline constexpr const _arithmetic_errc_domain &_arithmetic_errc_domain::get() { return arithmetic_errc_domain; } // Tell status code about the available implicit conversion inline arithmetic_errc_error make_status_code(arithmetic_errc e) { return arithmetic_errc_error(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::in_place, e); } BOOST_OUTCOME_V2_NAMESPACE_BEGIN namespace trait { // Tell Outcome that arithmetic_errc is convertible into std::error template <> struct is_error_type_enum { static constexpr bool value = true; }; } // namespace trait BOOST_OUTCOME_V2_NAMESPACE_END // And tell Outcome how to perform the implicit conversion inline error make_error_code(arithmetic_errc e) { return arithmetic_errc_error(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::in_place, e); } result safe_divide(int i, int j) { if(j == 0) { return arithmetic_errc::divide_by_zero; } if(i == INT_MIN && j == -1) { return arithmetic_errc::integer_divide_overflows; } if(i % j != 0) { return arithmetic_errc::not_integer_division; } return i / j; } int caller2(int i, int j) { auto r = safe_divide(i, j); if(r) { return r.value(); } if(r.error() == arithmetic_errc::divide_by_zero) { return 0; } if(r.error() == arithmetic_errc::not_integer_division) { return i / j; // ignore } if(r.error() == arithmetic_errc::integer_divide_overflows) { return INT_MIN; } return 0; } int main() { printf("%d\n", caller2(5, 6)); // NOLINT return 0; }