1/* Unit testing for outcomes
2(C) 2017-2024 Niall Douglas <http://www.nedproductions.biz/> (7 commits)
3
4
5Boost Software License - Version 1.0 - August 17th, 2003
6
7Permission is hereby granted, free of charge, to any person or organization
8obtaining a copy of the software and accompanying documentation covered by
9this license (the "Software") to use, reproduce, display, distribute,
10execute, and transmit the Software, and to prepare derivative works of the
11Software, and to permit third-parties to whom the Software is furnished to
12do so, all subject to the following:
13
14The copyright notices in the Software and this entire statement, including
15the above license grant, this restriction and the following disclaimer,
16must be included in all copies of the Software, in whole or in part, and
17all derivative works of the Software, unless such copies or derivative
18works are solely in the form of machine-executable object code generated by
19a source language processor.
20
21THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27DEALINGS IN THE SOFTWARE.
28*/
29
30#include <boost/outcome/experimental/status_result.hpp>
31
32#include <climits> // for INT_MAX
33#include <cstdio>
34
35// status_code<erased<intptr_t>>
36using error = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::error;
37// Outcome's result must be told when it is dealing with an erased status code
38template <class T, class E> using result = BOOST_OUTCOME_V2_NAMESPACE::experimental::status_result<T, E, BOOST_OUTCOME_V2_NAMESPACE::policy::all_narrow>;
39
40enum class arithmetic_errc
41{
42 success,
43 divide_by_zero,
44 integer_divide_overflows,
45 not_integer_division
46};
47
48class _arithmetic_errc_domain;
49using arithmetic_errc_error = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<_arithmetic_errc_domain>;
50
51class _arithmetic_errc_domain : public BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code_domain
52{
53 using _base = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code_domain;
54
55public:
56 using value_type = arithmetic_errc;
57
58 constexpr explicit _arithmetic_errc_domain(typename _base::unique_id_type id = 0x290f170194f0c6c7) noexcept : _base(id) {}
59 static inline constexpr const _arithmetic_errc_domain &get();
60
61 virtual _base::string_ref name() const noexcept override final // NOLINT
62 {
63 static string_ref v("arithmetic error domain");
64 return v; // NOLINT
65 }
66
67 virtual payload_info_t payload_info() const noexcept override
68 {
69 return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
70 (alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
71 }
72
73protected:
74 virtual bool _do_failure(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept override final // NOLINT
75 {
76 assert(code.domain() == *this); // NOLINT
77 const auto &c1 = static_cast<const arithmetic_errc_error &>(code); // NOLINT
78 return c1.value() != arithmetic_errc::success;
79 }
80 virtual bool _do_equivalent(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &, const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &) const noexcept override final { return false; } // NOLINT
81 virtual BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::generic_code _generic_code(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &) const noexcept override final { return {}; } // NOLINT
82 virtual _base::string_ref _do_message(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept override final // NOLINT
83 {
84 assert(code.domain() == *this); // NOLINT
85 const auto &c1 = static_cast<const arithmetic_errc_error &>(code); // NOLINT
86 switch(c1.value())
87 {
88 case arithmetic_errc::success:
89 return _base::string_ref("success");
90 case arithmetic_errc::divide_by_zero:
91 return _base::string_ref("divide by zero");
92 case arithmetic_errc::integer_divide_overflows:
93 return _base::string_ref("integer divide overflows");
94 case arithmetic_errc::not_integer_division:
95 return _base::string_ref("not integer division");
96 }
97 return _base::string_ref("unknown");
98 }
99 BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &) const override final { abort(); } // NOLINT
100};
101
102constexpr _arithmetic_errc_domain arithmetic_errc_domain;
103inline constexpr const _arithmetic_errc_domain &_arithmetic_errc_domain::get()
104{
105 return arithmetic_errc_domain;
106}
107
108
109// Tell status code about the available implicit conversion
110inline arithmetic_errc_error make_status_code(arithmetic_errc e)
111{
112 return arithmetic_errc_error(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::in_place, e);
113}
114
115BOOST_OUTCOME_V2_NAMESPACE_BEGIN
116namespace trait
117{
118 // Tell Outcome that arithmetic_errc is convertible into std::error
119 template <> struct is_error_type_enum<error, arithmetic_errc>
120 {
121 static constexpr bool value = true;
122 };
123}
124BOOST_OUTCOME_V2_NAMESPACE_END
125// And tell Outcome how to perform the implicit conversion
126inline error make_error_code(arithmetic_errc e)
127{
128 return arithmetic_errc_error(BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::in_place, e);
129}
130
131
132result<int, error> safe_divide(int i, int j)
133{
134 if(j == 0)
135 {
136 return arithmetic_errc::divide_by_zero;
137 }
138 if(i == INT_MIN && j == -1)
139 {
140 return arithmetic_errc::integer_divide_overflows;
141 }
142 if(i % j != 0)
143 {
144 return arithmetic_errc::not_integer_division;
145 }
146 return i / j;
147}
148
149int caller2(int i, int j)
150{
151 auto r = safe_divide(i, j);
152 if(r)
153 {
154 return r.value();
155 }
156 if(r.error() == arithmetic_errc::divide_by_zero)
157 {
158 return 0;
159 }
160 if(r.error() == arithmetic_errc::not_integer_division)
161 {
162 return i / j; // ignore
163 }
164 if(r.error() == arithmetic_errc::integer_divide_overflows)
165 {
166 return INT_MIN;
167 }
168 return 0;
169}
170
171int main()
172{
173 printf(format: "%d\n", caller2(i: 5, j: 6)); // NOLINT
174 return 0;
175}
176

source code of boost/libs/outcome/test/tests/experimental-p0709a.cpp