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