aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.ucl/real.ccm
diff options
context:
space:
mode:
authorLexi Winter <lexi@le-fay.org>2025-07-01 17:07:04 +0100
committerLexi Winter <lexi@le-fay.org>2025-07-01 17:07:04 +0100
commit2e2d1bd3b6c7776b77c33b94f30ead89367a71e6 (patch)
tree54d37ffadf8e677938d9b7a28e4e9b71be1e75c1 /nihil.ucl/real.ccm
parent36427c0966faa7aecd586b397ed9b845f18172f5 (diff)
downloadnihil-2e2d1bd3b6c7776b77c33b94f30ead89367a71e6.tar.gz
nihil-2e2d1bd3b6c7776b77c33b94f30ead89367a71e6.tar.bz2
add nihil.std
Diffstat (limited to 'nihil.ucl/real.ccm')
-rw-r--r--nihil.ucl/real.ccm151
1 files changed, 89 insertions, 62 deletions
diff --git a/nihil.ucl/real.ccm b/nihil.ucl/real.ccm
index f425a9a..b432617 100644
--- a/nihil.ucl/real.ccm
+++ b/nihil.ucl/real.ccm
@@ -1,78 +1,106 @@
-/*
- * This source code is released into the public domain.
- */
-
+// This source code is released into the public domain.
module;
-#include <compare>
-#include <expected>
-#include <format>
-#include <utility>
-
#include <ucl.h>
export module nihil.ucl:real;
+import nihil.std;
+import nihil.core;
import :object;
import :type;
namespace nihil::ucl {
-export struct real final : object {
+export struct real final : object
+{
using contained_type = double;
- inline static constexpr object_type ucl_type = object_type::real;
+ static constexpr object_type ucl_type = object_type::real;
- /*
- * Create a real holding the value 0. Throws std::system_error
- * on failure.
- */
- real();
+ // Create a real holding the value 0. Throws std::system_error
+ // on failure.
+ real()
+ : real(0)
+ {
+ }
- /*
- * Create a real holding a specific value. Throws std::system_error
- * on failure.
- */
- explicit real(contained_type value);
+ // Create a real holding a specific value. Throws std::system_error
+ // on failure.
+ explicit real(contained_type value)
+ : real(noref, [&] {
+ auto *uobj = ::ucl_object_fromdouble(value);
+ if (uobj == nullptr)
+ throw std::system_error(std::make_error_code(sys_error()));
+ return uobj;
+ }())
+ {
+ }
- /*
- * Create a new real from a UCL object. Throws type_mismatch
- * on failure.
- */
- real(ref_t, ::ucl_object_t const *uobj);
- real(noref_t, ::ucl_object_t *uobj);
+ // Create a new real from a UCL object. Throws type_mismatch
+ // on failure.
+ real(ref_t, ::ucl_object_t const *uobj)
+ : object(nihil::ucl::ref, ensure_ucl_type(uobj, real::ucl_type))
+ {
+ }
+
+ real(noref_t, ::ucl_object_t *uobj)
+ : object(nihil::ucl::noref, ensure_ucl_type(uobj, real::ucl_type))
+ {
+ }
// Return the value of this real.
- [[nodiscard]] auto value(this real const &self) -> contained_type;
-};
+ [[nodiscard]] auto value(this real const &self) -> contained_type
+ {
+ auto v = contained_type{};
+ auto const *uobj = self.get_ucl_object();
+
+ if (::ucl_object_todouble_safe(uobj, &v))
+ return v;
-/*
- * Real constructors. These return an error instead of throwing.
- */
+ throw std::runtime_error("ucl_object_todouble_safe failed");
+ }
-export [[nodiscard]] auto
-make_real(real::contained_type = 0) -> std::expected<real, error>;
+private:
+ //
+ // Comparison operators.
+ //
-/*
- * Comparison operators.
- */
+ [[nodiscard]] friend auto operator==(real const &a, real const &b) -> bool
+ {
+ return a.value() == b.value();
+ }
-export [[nodiscard]] auto operator== (real const &a, real const &b) -> bool;
+ [[nodiscard]] friend auto operator<=>(real const &a, real const &b) -> std::partial_ordering
+ {
+ return a.value() <=> b.value();
+ }
-export [[nodiscard]] auto operator== (real const &a,
- real::contained_type b) -> bool;
+ [[nodiscard]] friend auto operator==(real const &a, real::contained_type b) -> bool
+ {
+ return a.value() == b;
+ }
-export [[nodiscard]] auto operator<=> (real const &a, real const &b)
- -> std::partial_ordering;
+ [[nodiscard]] friend auto
+ operator<=>(real const &a, real::contained_type b) -> std::partial_ordering
+ {
+ return a.value() <=> b;
+ }
+};
-export [[nodiscard]] auto operator<=> (real const &a, real::contained_type b)
- -> std::partial_ordering;
+// Real constructor. This returns an error instead of throwing.
+export [[nodiscard]] auto make_real(real::contained_type value = 0) -> std::expected<real, error>
+{
+ auto *uobj = ::ucl_object_fromdouble(value);
+ if (uobj == nullptr)
+ return std::unexpected(error(errc::failed_to_create_object, error(sys_error())));
-/*
- * Literal operator.
- */
+ return real(noref, uobj);
+}
+
+// Literal operator.
inline namespace literals {
-export constexpr auto operator""_ucl (long double d) -> real
+export constexpr auto operator""_ucl(long double d) -> real
{
if (d > static_cast<long double>(std::numeric_limits<double>::max()) ||
d < static_cast<long double>(std::numeric_limits<double>::min()))
@@ -80,32 +108,31 @@ export constexpr auto operator""_ucl (long double d) -> real
return real(static_cast<double>(d));
}
-} // 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 nihil
-/*
- * std::formatter for a real. This provides the same format operations
- * as std::formatter<double>;
- */
-export template<>
+// std::formatter for a real. This provides the same format operations
+// as std::formatter<double>;
+export template <>
struct std::formatter<nihil::ucl::real, char>
{
std::formatter<double> 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::real const &o,
- FmtContext& ctx) const
+ template <class FmtContext>
+ auto format(nihil::ucl::real const &o, FmtContext &ctx) const -> FmtContext::iterator
{
return base_formatter.format(o.value(), ctx);
}