diff options
Diffstat (limited to 'nihil.ucl/integer.ccm')
| -rw-r--r-- | nihil.ucl/integer.ccm | 165 |
1 files changed, 95 insertions, 70 deletions
diff --git a/nihil.ucl/integer.ccm b/nihil.ucl/integer.ccm index e35a471..eb7fa6b 100644 --- a/nihil.ucl/integer.ccm +++ b/nihil.ucl/integer.ccm @@ -1,114 +1,139 @@ -/* - * This source code is released into the public domain. - */ - +// This source code is released into the public domain. module; -#include <compare> -#include <cstdint> -#include <cstdlib> -#include <expected> -#include <format> -#include <utility> - #include <ucl.h> export module nihil.ucl:integer; +import nihil.std; +import nihil.core; +import nihil.error; import :object; import :type; namespace nihil::ucl { -export struct integer final : object { +export struct integer final : object +{ using contained_type = std::int64_t; - inline static constexpr object_type ucl_type = object_type::integer; - - /* - * Create an integer holding the value 0. Throws std::system_error - * on failure. - */ - integer(); - - /* - * Create an integer holding a specific value. Throws std::system_error - * on failure. - */ - explicit integer(contained_type value); - - /* - * Create a new integer from a UCL object. Throws type_mismatch - * on failure. - */ - integer(ref_t, ::ucl_object_t const *uobj); - integer(noref_t, ::ucl_object_t *uobj); + static constexpr object_type ucl_type = object_type::integer; + + // Create an integer holding the value 0. Throws std::system_error + // on failure. + integer() + : integer(0) + { + } + + // Create an integer holding a specific value. Throws std::system_error + // on failure. + explicit integer(contained_type value) + : integer(noref, [&] { + auto *uobj = ::ucl_object_fromint(value); + if (uobj == nullptr) + throw std::system_error(std::make_error_code(sys_error())); + return uobj; + }()) + { + } + + // Create a new integer from a UCL object. Throws type_mismatch + // on failure. + integer(ref_t, ::ucl_object_t const *uobj) + : object(nihil::ucl::ref, ensure_ucl_type(uobj, integer::ucl_type)) + { + } + + integer(noref_t, ::ucl_object_t *uobj) + : object(nihil::ucl::noref, ensure_ucl_type(uobj, integer::ucl_type)) + { + } // Return the value of this object. - [[nodiscard]] auto value(this integer const &self) -> contained_type; -}; + [[nodiscard]] auto value(this integer const &self) -> contained_type + { + auto v = contained_type{}; + auto const *uobj = self.get_ucl_object(); -/* - * Integer constructors. These return an error instead of throwing. - */ + if (::ucl_object_toint_safe(uobj, &v)) + return v; -export [[nodiscard]] auto -make_integer(integer::contained_type = 0) -> std::expected<integer, error>; + throw std::runtime_error("ucl_object_toint_safe failed"); + } -/* - * Comparison operators. - */ +private: + // + // Comparison operators. + // -export [[nodiscard]] auto operator== (integer const &a, - integer const &b) -> bool; + [[nodiscard]] friend auto operator==(integer const &a, integer const &b) -> bool + { + return a.value() == b.value(); + } -export [[nodiscard]] auto operator== (integer const &a, - integer::contained_type b) -> bool; + [[nodiscard]] friend auto operator==(integer const &a, integer::contained_type b) -> bool + { + return a.value() == b; + } -export [[nodiscard]] auto operator<=> (integer const &a, - integer const &b) - -> std::strong_ordering; + [[nodiscard]] friend auto + operator<=>(integer const &a, integer const &b) -> std::strong_ordering + { + return a.value() <=> b.value(); + } -export [[nodiscard]] auto operator<=> (integer const &a, - integer::contained_type b) - -> std::strong_ordering; + [[nodiscard]] friend auto + operator<=>(integer const &a, integer::contained_type b) -> std::strong_ordering + { + return a.value() <=> b; + } +}; + +// Integer constructors. This returns an error instead of throwing. +export [[nodiscard]] auto +make_integer(integer::contained_type value = 0) -> std::expected<integer, error> +{ + auto *uobj = ::ucl_object_fromint(value); + if (uobj == nullptr) + return error(errc::failed_to_create_object, error(sys_error())); + + return integer(noref, uobj); +} -/* - * Literal operator. - */ +// Literal operator for integers. inline namespace literals { -export constexpr auto operator""_ucl (unsigned long long i) -> integer +export constexpr auto operator""_ucl(unsigned long long i) -> integer { if (std::cmp_greater(i, std::numeric_limits<std::int64_t>::max())) throw std::out_of_range("literal out of range"); return integer(static_cast<std::int64_t>(i)); } -} // namespace nihil::ucl::literals +} // namespace literals } // namespace nihil::ucl -namespace nihil { inline namespace literals { - export using namespace ::nihil::ucl::literals; -}} // namespace nihil::literals +namespace nihil { +inline namespace literals { +export using namespace ::nihil::ucl::literals; +} // namespace literals +} // namespace nihil -/* - * std::formatter for an integer. This provides the same format operations - * as std::formatter<std::int64_t>. - */ -export template<> +// std::formatter for an integer. This provides the same format operations +// as std::formatter<std::int64_t>. +export template <> struct std::formatter<nihil::ucl::integer, char> { std::formatter<std::int64_t> base_formatter; - template<class ParseContext> - constexpr ParseContext::iterator parse(ParseContext& ctx) + template <class ParseContext> + constexpr auto parse(ParseContext &ctx) -> ParseContext::iterator { return base_formatter.parse(ctx); } - template<class FmtContext> - FmtContext::iterator format(nihil::ucl::integer const &o, - FmtContext& ctx) const + template <class FmtContext> + auto format(nihil::ucl::integer const &o, FmtContext &ctx) const -> FmtContext::iterator { return base_formatter.format(o.value(), ctx); } |
