4598879ed9
Merged from develop branch as CDash reports all green
170 lines
6.0 KiB
C++
170 lines
6.0 KiB
C++
/* Unit testing for outcomes
|
|
(C) 2017-2019 Niall Douglas <http://www.nedproductions.biz/> (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.
|
|
*/
|
|
|
|
#include <boost/outcome/experimental/status_result.hpp>
|
|
|
|
#include <climits> // for INT_MAX
|
|
#include <cstdio>
|
|
|
|
// status_code<erased<intptr_t>>
|
|
using error = BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::error;
|
|
// Outcome's result must be told when it is dealing with an erased status code
|
|
template <class T, class E> using result = BOOST_OUTCOME_V2_NAMESPACE::experimental::status_result<T, E, BOOST_OUTCOME_V2_NAMESPACE::policy::all_narrow>;
|
|
|
|
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();
|
|
|
|
virtual _base::string_ref name() const noexcept override final // NOLINT
|
|
{
|
|
static string_ref v("arithmetic error domain");
|
|
return v; // NOLINT
|
|
}
|
|
|
|
protected:
|
|
virtual bool _do_failure(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept override final // NOLINT
|
|
{
|
|
assert(code.domain() == *this); // NOLINT
|
|
const auto &c1 = static_cast<const arithmetic_errc_error &>(code); // NOLINT
|
|
return c1.value() != arithmetic_errc::success;
|
|
}
|
|
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
|
|
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
|
|
virtual _base::string_ref _do_message(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &code) const noexcept override final // NOLINT
|
|
{
|
|
assert(code.domain() == *this); // NOLINT
|
|
const auto &c1 = static_cast<const arithmetic_errc_error &>(code); // NOLINT
|
|
switch(c1.value())
|
|
{
|
|
case arithmetic_errc::success:
|
|
return _base::string_ref("success");
|
|
case arithmetic_errc::divide_by_zero:
|
|
return _base::string_ref("divide by zero");
|
|
case arithmetic_errc::integer_divide_overflows:
|
|
return _base::string_ref("integer divide overflows");
|
|
case arithmetic_errc::not_integer_division:
|
|
return _base::string_ref("not integer division");
|
|
}
|
|
return _base::string_ref("unknown");
|
|
}
|
|
BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE::status_code<void> &) 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<error, arithmetic_errc>
|
|
{
|
|
static constexpr bool value = true;
|
|
};
|
|
}
|
|
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<int, error> 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;
|
|
}
|