From 7afcb81e4b2aaa6c7034acda316f291813aee9ed Mon Sep 17 00:00:00 2001 From: Liss Heidrich <31625940+liss-h@users.noreply.github.com> Date: Tue, 8 Jul 2025 11:25:26 +0200 Subject: [PATCH 1/3] WIP --- src/rdf4cpp/datatypes/LiteralDatatype.hpp | 2 +- .../datatypes/registry/DatatypeConversion.hpp | 24 ++++++++++---- .../registry/DatatypeConversionTyping.hpp | 6 ++-- .../registry/LiteralDatatypeImpl.hpp | 4 +-- .../datatypes/registry/util/DateTimeUtils.hpp | 8 ++++- src/rdf4cpp/datatypes/xsd/time/Date.cpp | 33 +++++++++++-------- src/rdf4cpp/datatypes/xsd/time/Date.hpp | 3 +- src/rdf4cpp/datatypes/xsd/time/Day.cpp | 8 +++-- src/rdf4cpp/datatypes/xsd/time/Day.hpp | 3 +- src/rdf4cpp/datatypes/xsd/time/Month.cpp | 8 +++-- src/rdf4cpp/datatypes/xsd/time/Month.hpp | 3 +- src/rdf4cpp/datatypes/xsd/time/MonthDay.cpp | 8 +++-- src/rdf4cpp/datatypes/xsd/time/MonthDay.hpp | 3 +- src/rdf4cpp/datatypes/xsd/time/Time.cpp | 28 ++++++++++------ src/rdf4cpp/datatypes/xsd/time/Time.hpp | 6 ++-- src/rdf4cpp/datatypes/xsd/time/Year.cpp | 8 +++-- src/rdf4cpp/datatypes/xsd/time/Year.hpp | 3 +- src/rdf4cpp/datatypes/xsd/time/YearMonth.cpp | 8 +++-- src/rdf4cpp/datatypes/xsd/time/YearMonth.hpp | 3 +- 19 files changed, 109 insertions(+), 60 deletions(-) diff --git a/src/rdf4cpp/datatypes/LiteralDatatype.hpp b/src/rdf4cpp/datatypes/LiteralDatatype.hpp index 5f90a77ef..8b6090d22 100644 --- a/src/rdf4cpp/datatypes/LiteralDatatype.hpp +++ b/src/rdf4cpp/datatypes/LiteralDatatype.hpp @@ -156,7 +156,7 @@ concept PromotableLiteralDatatype = LiteralDatatype && requ typename LiteralDatatypeImpl::template promoted_cpp_type<0>; { LiteralDatatypeImpl::promotion_rank } -> std::convertible_to; { LiteralDatatypeImpl::max_promotion_specialization_ix } -> std::convertible_to; - { LiteralDatatypeImpl::template promote<0>(value) } -> std::convertible_to>; + { LiteralDatatypeImpl::template promote<0>(value) } -> std::convertible_to, DynamicError>>; { LiteralDatatypeImpl::template demote<0>(promoted_value) } -> std::convertible_to>; }; diff --git a/src/rdf4cpp/datatypes/registry/DatatypeConversion.hpp b/src/rdf4cpp/datatypes/registry/DatatypeConversion.hpp index cfe1d12af..d1c083eb3 100644 --- a/src/rdf4cpp/datatypes/registry/DatatypeConversion.hpp +++ b/src/rdf4cpp/datatypes/registry/DatatypeConversion.hpp @@ -105,7 +105,7 @@ consteval ConversionLayer auto make_conversion_layer_impl() { using source_type = Type; using target_type = typename next::template converted; - inline static typename target_type::cpp_type convert(typename source_type::cpp_type const &value) noexcept { + inline static nonstd::expected convert(typename source_type::cpp_type const &value) noexcept { return next::template convert(value); } @@ -128,8 +128,13 @@ consteval ConversionLayer auto make_conversion_layer_impl() { using source_type = typename prev_promotion_t::source_type; using target_type = typename next::template converted; - inline static typename target_type::cpp_type convert(typename source_type::cpp_type const &value) noexcept { - return next::template convert(prev_promotion_t::convert(value)); + inline static nonstd::expected convert(typename source_type::cpp_type const &value) noexcept { + auto const promoted = prev_promotion_t::convert(value); + if (!promoted.has_value()) { + return nonstd::make_unexpected(promoted.error()); + } + + return next::template convert(*promoted); } inline static nonstd::expected inverse_convert(typename target_type::cpp_type const &value) noexcept { @@ -174,7 +179,7 @@ struct PromoteConversion { using converted_cpp_type = typename LiteralDatatypeImpl::template promoted_cpp_type; template - inline static converted_cpp_type convert(cpp_type const &value) noexcept { + inline static nonstd::expected, DynamicError> convert(cpp_type const &value) noexcept { return LiteralDatatypeImpl::template promote(value); } @@ -340,7 +345,7 @@ consteval ConversionTable auto make_conversion_table() { using source_type = Type; using target_type = Type; - inline static typename target_type::cpp_type convert(typename source_type::cpp_type const &value) noexcept { + inline static nonstd::expected convert(typename source_type::cpp_type const &value) noexcept { return value; } @@ -367,8 +372,13 @@ consteval ConversionTable auto make_conversion_table() { using source_type = typename ToSuper::source_type; using target_type = typename PromoteSuper::target_type; - inline static typename target_type::cpp_type convert(typename source_type::cpp_type const &value) noexcept { - return PromoteSuper::convert(ToSuper::convert(value)); + inline static nonstd::expected convert(typename source_type::cpp_type const &value) noexcept { + auto const super = ToSuper::convert(value); + if (!super.has_value()) { + return nonstd::make_unexpected(super.error()); + } + + return PromoteSuper::convert(*super); } inline static nonstd::expected inverse_convert(typename target_type::cpp_type const &value) noexcept { diff --git a/src/rdf4cpp/datatypes/registry/DatatypeConversionTyping.hpp b/src/rdf4cpp/datatypes/registry/DatatypeConversionTyping.hpp index 63157e914..86eff00db 100644 --- a/src/rdf4cpp/datatypes/registry/DatatypeConversionTyping.hpp +++ b/src/rdf4cpp/datatypes/registry/DatatypeConversionTyping.hpp @@ -19,7 +19,7 @@ template concept ConversionEntry = requires(typename T::source_type::cpp_type value) { requires LiteralDatatype; requires LiteralDatatype; - { T::convert(value) } -> std::same_as; + { T::convert(value) } -> std::same_as>; }; @@ -72,7 +72,7 @@ concept ConversionTable = conversion_typing_detail::IsConversionTable::value; * A type erased version of a ConversionEntry. */ struct RuntimeConversionEntry { - using convert_fptr_t = std::any (*)(std::any const &) noexcept; + using convert_fptr_t = nonstd::expected (*)(std::any const &) noexcept; using inverted_convert_fptr_t = nonstd::expected (*)(std::any const &) noexcept; DatatypeID target_type_id; @@ -91,7 +91,7 @@ struct RuntimeConversionEntry { return RuntimeConversionEntry{ .target_type_id = std::move(target_type_iri), - .convert = [](std::any const &value) noexcept -> std::any { + .convert = [](std::any const &value) noexcept -> nonstd::expected { auto const actual_value = std::any_cast(value); return std::any{Entry::convert(actual_value)}; }, diff --git a/src/rdf4cpp/datatypes/registry/LiteralDatatypeImpl.hpp b/src/rdf4cpp/datatypes/registry/LiteralDatatypeImpl.hpp index 6a35b1866..0dc6937ca 100644 --- a/src/rdf4cpp/datatypes/registry/LiteralDatatypeImpl.hpp +++ b/src/rdf4cpp/datatypes/registry/LiteralDatatypeImpl.hpp @@ -105,12 +105,12 @@ struct Promotable { using promoted_cpp_type = typename DatatypeMapping::identifier>::cpp_datatype; template - inline static promoted_cpp_type promote(cpp_type const &value) noexcept { + static nonstd::expected, DynamicError> promote(cpp_type const &value) noexcept { return static_cast>(value); } template - inline static nonstd::expected demote(promoted_cpp_type const &value) noexcept { + static nonstd::expected demote(promoted_cpp_type const &value) noexcept { if constexpr (std::is_integral_v && std::is_integral_v>) { if (!std::in_range(value)) { return nonstd::make_unexpected(DynamicError::InvalidValueForCast); diff --git a/src/rdf4cpp/datatypes/registry/util/DateTimeUtils.hpp b/src/rdf4cpp/datatypes/registry/util/DateTimeUtils.hpp index 06426d150..0cb592f7f 100644 --- a/src/rdf4cpp/datatypes/registry/util/DateTimeUtils.hpp +++ b/src/rdf4cpp/datatypes/registry/util/DateTimeUtils.hpp @@ -218,7 +218,7 @@ inline nonstd::expected timepoint_sub(st } } -static inline std::partial_ordering compare_time_points(const rdf4cpp::TimePoint& a, std::optional atz, +inline std::partial_ordering compare_time_points(const rdf4cpp::TimePoint& a, std::optional atz, const rdf4cpp::TimePoint& b, std::optional btz) noexcept { auto apply_timezone = [](const rdf4cpp::TimePoint& t, rdf4cpp::Timezone tz) noexcept -> std::optional { try { @@ -253,6 +253,12 @@ static inline std::partial_ordering compare_time_points(const rdf4cpp::TimePoint auto a_sys = apply_timezone(a, *atz); return cmp_opt(a_sys, apply_timezone(b, *btz)); } + +inline std::partial_ordering compare_time_points(std::pair const &lhs, + std::pair const &rhs) { + return compare_time_points(lhs.first, lhs.second, rhs.first, rhs.second); +} + template constexpr T number_of_bits(T x) noexcept { return x < 2 ? x : 1 + number_of_bits(x >> 1); diff --git a/src/rdf4cpp/datatypes/xsd/time/Date.cpp b/src/rdf4cpp/datatypes/xsd/time/Date.cpp index 8d928c0e3..bf8f5f260 100644 --- a/src/rdf4cpp/datatypes/xsd/time/Date.cpp +++ b/src/rdf4cpp/datatypes/xsd/time/Date.cpp @@ -63,53 +63,60 @@ capabilities::Inlineable::cpp_type capabilities::Inlineable: return capabilities::Inlineable::cpp_type{YearMonthDay::time_point{YearMonthDay::time_point::duration{i}}, std::nullopt}; } -rdf4cpp::TimePoint date_to_tp(YearMonthDay const &d) noexcept { - return rdf4cpp::util::construct_timepoint(d, rdf4cpp::util::time_point_replacement_time_of_day); +inline capabilities::Promotable::promoted_cpp_type<0> date_to_tp(capabilities::Default::cpp_type const &d) noexcept { + return std::make_pair(rdf4cpp::util::construct_timepoint(d.first, rdf4cpp::util::time_point_replacement_time_of_day), d.second); } template<> template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept { - return std::make_pair(date_to_tp(value.first), value.second); +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>(cpp_type const &value) noexcept { + return date_to_tp(value); } template<> template<> -nonstd::expected::cpp_type, DynamicError> capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { +nonstd::expected::cpp_type, DynamicError> +capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { return std::make_pair(YearMonthDay{std::chrono::floor(value.first)}, value.second); } template<> std::partial_ordering capabilities::Comparable::compare(cpp_type const &lhs, cpp_type const &rhs) noexcept { - return rdf4cpp::datatypes::registry::util::compare_time_points(date_to_tp(lhs.first), lhs.second, date_to_tp(rhs.first), rhs.second); + return rdf4cpp::datatypes::registry::util::compare_time_points(date_to_tp(lhs), date_to_tp(rhs)); } template<> nonstd::expected::timepoint_sub_result_cpp_type, DynamicError> capabilities::Timepoint::timepoint_sub(cpp_type const &lhs, cpp_type const &rhs) noexcept { - auto const super_lhs = Promotable::promote(lhs); - auto const super_rhs = Promotable::promote(rhs); - return util::timepoint_sub(super_lhs, super_rhs); + auto const lhs_tp = date_to_tp(lhs); + auto const rhs_tp = date_to_tp(rhs); + + return util::timepoint_sub(lhs_tp, rhs_tp); } template<> nonstd::expected::cpp_type, DynamicError> capabilities::Timepoint::timepoint_duration_add(cpp_type const &tp, timepoint_duration_operand_cpp_type const &dur) noexcept { auto const super_tp = Promotable::promote(tp); - auto res_tp = util::add_duration_to_date_time(super_tp.first, dur); + assert(super_tp.has_value()); + + auto res_tp = util::add_duration_to_date_time(super_tp->first, dur); auto [date, _] = rdf4cpp::util::deconstruct_timepoint(res_tp); - return std::make_pair(date, super_tp.second); + return std::make_pair(date, super_tp->second); } template<> nonstd::expected::cpp_type, DynamicError> capabilities::Timepoint::timepoint_duration_sub(cpp_type const &tp, timepoint_duration_operand_cpp_type const &dur) noexcept { auto const super_tp = Promotable::promote(tp); - auto res_tp = util::add_duration_to_date_time(super_tp.first, std::make_pair(-dur.first, -dur.second)); + assert(super_tp.has_value()); + + auto res_tp = util::add_duration_to_date_time(super_tp->first, std::make_pair(-dur.first, -dur.second)); auto [date, _] = rdf4cpp::util::deconstruct_timepoint(res_tp); - return std::make_pair(date, super_tp.second); + return std::make_pair(date, super_tp->second); } #endif diff --git a/src/rdf4cpp/datatypes/xsd/time/Date.hpp b/src/rdf4cpp/datatypes/xsd/time/Date.hpp index 91c90f134..97d84f7eb 100644 --- a/src/rdf4cpp/datatypes/xsd/time/Date.hpp +++ b/src/rdf4cpp/datatypes/xsd/time/Date.hpp @@ -49,7 +49,8 @@ capabilities::Inlineable::cpp_type capabilities::Inlineable: template<> template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; template<> template<> diff --git a/src/rdf4cpp/datatypes/xsd/time/Day.cpp b/src/rdf4cpp/datatypes/xsd/time/Day.cpp index 819d9dd53..3f1dd6864 100644 --- a/src/rdf4cpp/datatypes/xsd/time/Day.cpp +++ b/src/rdf4cpp/datatypes/xsd/time/Day.cpp @@ -63,13 +63,15 @@ capabilities::Inlineable::cpp_type capabilities::Inlineable: template<> template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept { - return std::make_pair(YearMonthDay{rdf4cpp::util::time_point_replacement_date.year(), rdf4cpp::util::time_point_replacement_date.month(), value.first}, value.second); +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>([[maybe_unused]] cpp_type const &value) noexcept { + return nonstd::make_unexpected(DynamicError::Unsupported); } template<> template<> -nonstd::expected::cpp_type, DynamicError> capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { +nonstd::expected::cpp_type, DynamicError> +capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { return std::make_pair(value.first.day(), value.second); } #endif diff --git a/src/rdf4cpp/datatypes/xsd/time/Day.hpp b/src/rdf4cpp/datatypes/xsd/time/Day.hpp index c57277249..7a174473b 100644 --- a/src/rdf4cpp/datatypes/xsd/time/Day.hpp +++ b/src/rdf4cpp/datatypes/xsd/time/Day.hpp @@ -40,7 +40,8 @@ capabilities::Inlineable::cpp_type capabilities::Inlineable: template<> template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; template<> template<> diff --git a/src/rdf4cpp/datatypes/xsd/time/Month.cpp b/src/rdf4cpp/datatypes/xsd/time/Month.cpp index 95c7eeef3..b0c8fefef 100644 --- a/src/rdf4cpp/datatypes/xsd/time/Month.cpp +++ b/src/rdf4cpp/datatypes/xsd/time/Month.cpp @@ -63,13 +63,15 @@ capabilities::Inlineable::cpp_type capabilities::Inlineable template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept { - return std::make_pair(YearMonthDay{rdf4cpp::util::time_point_replacement_date.year(), value.first, std::chrono::last}, value.second); +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>([[maybe_unused]] cpp_type const &value) noexcept { + return nonstd::make_unexpected(DynamicError::Unsupported); } template<> template<> -nonstd::expected::cpp_type, DynamicError> capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { +nonstd::expected::cpp_type, DynamicError> +capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { return std::make_pair(value.first.month(), value.second); } #endif diff --git a/src/rdf4cpp/datatypes/xsd/time/Month.hpp b/src/rdf4cpp/datatypes/xsd/time/Month.hpp index 5df892a55..11305f058 100644 --- a/src/rdf4cpp/datatypes/xsd/time/Month.hpp +++ b/src/rdf4cpp/datatypes/xsd/time/Month.hpp @@ -41,7 +41,8 @@ capabilities::Inlineable::cpp_type capabilities::Inlineable template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; template<> template<> diff --git a/src/rdf4cpp/datatypes/xsd/time/MonthDay.cpp b/src/rdf4cpp/datatypes/xsd/time/MonthDay.cpp index c938853cf..2a30e2d29 100644 --- a/src/rdf4cpp/datatypes/xsd/time/MonthDay.cpp +++ b/src/rdf4cpp/datatypes/xsd/time/MonthDay.cpp @@ -69,13 +69,15 @@ std::partial_ordering capabilities::Comparable::compare(cpp_type template<> template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept { - return std::make_pair(YearMonthDay{rdf4cpp::util::time_point_replacement_date.year(), value.first.month(), value.first.day()}, value.second); +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>([[maybe_unused]] cpp_type const &value) noexcept { + return nonstd::make_unexpected(DynamicError::Unsupported); } template<> template<> -nonstd::expected::cpp_type, DynamicError> capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { +nonstd::expected::cpp_type, DynamicError> +capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { return std::make_pair(value.first.month() / value.first.day(), value.second); } #endif diff --git a/src/rdf4cpp/datatypes/xsd/time/MonthDay.hpp b/src/rdf4cpp/datatypes/xsd/time/MonthDay.hpp index 0d81daa12..701791b92 100644 --- a/src/rdf4cpp/datatypes/xsd/time/MonthDay.hpp +++ b/src/rdf4cpp/datatypes/xsd/time/MonthDay.hpp @@ -40,7 +40,8 @@ capabilities::Inlineable::cpp_type capabilities::Inlineable template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; template<> template<> diff --git a/src/rdf4cpp/datatypes/xsd/time/Time.cpp b/src/rdf4cpp/datatypes/xsd/time/Time.cpp index f489023be..bdcee75df 100644 --- a/src/rdf4cpp/datatypes/xsd/time/Time.cpp +++ b/src/rdf4cpp/datatypes/xsd/time/Time.cpp @@ -5,6 +5,11 @@ namespace rdf4cpp::datatypes::registry { #ifndef DOXYGEN_PARSER + +inline capabilities::Promotable::promoted_cpp_type<0> time_to_tp(capabilities::Default::cpp_type const &value) { + return std::make_pair(rdf4cpp::util::construct_timepoint(rdf4cpp::util::time_point_replacement_date, value.first), value.second); +} + template<> capabilities::Default::cpp_type capabilities::Default::from_string(std::string_view s) { using namespace registry::util; @@ -70,34 +75,37 @@ capabilities::Inlineable::cpp_type capabilities::Inlineable: template<> std::partial_ordering capabilities::Comparable::compare(cpp_type const &lhs, cpp_type const &rhs) noexcept { - return registry::util::compare_time_points(rdf4cpp::util::construct_timepoint(rdf4cpp::util::time_point_replacement_date, lhs.first), lhs.second, - rdf4cpp::util::construct_timepoint(rdf4cpp::util::time_point_replacement_date, rhs.first), rhs.second); + return registry::util::compare_time_points(time_to_tp(lhs), + time_to_tp(rhs)); } template<> template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept { - return std::make_pair(rdf4cpp::util::construct_timepoint(rdf4cpp::util::time_point_replacement_date, value.first), value.second); +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>([[maybe_unused]] cpp_type const &value) noexcept { + return nonstd::make_unexpected(DynamicError::Unsupported); } template<> template<> -nonstd::expected::cpp_type, DynamicError> capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { +nonstd::expected::cpp_type, DynamicError> +capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { return std::make_pair(std::chrono::duration_cast(value.first - std::chrono::floor(value.first)), value.second); } template<> nonstd::expected::timepoint_sub_result_cpp_type, DynamicError> capabilities::Timepoint::timepoint_sub(cpp_type const &lhs, cpp_type const &rhs) noexcept { - auto const super_lhs = Promotable::promote(lhs); - auto const super_rhs = Promotable::promote(rhs); - return util::timepoint_sub(super_lhs, super_rhs); + auto const lhs_tp = time_to_tp(lhs); + auto const rhs_tp = time_to_tp(rhs); + + return util::timepoint_sub(lhs_tp, rhs_tp); } template<> nonstd::expected::cpp_type, DynamicError> capabilities::Timepoint::timepoint_duration_add(cpp_type const &tp, timepoint_duration_operand_cpp_type const &dur) noexcept { - auto const super_tp = Promotable::promote(tp); + auto const super_tp = time_to_tp(tp); auto const super_dur = Subtype::into_supertype(dur); auto ret_tp = util::add_duration_to_date_time(super_tp.first, super_dur); @@ -109,7 +117,7 @@ capabilities::Timepoint::timepoint_duration_add(cpp_type const &tp, ti template<> nonstd::expected::cpp_type, DynamicError> capabilities::Timepoint::timepoint_duration_sub(cpp_type const &tp, timepoint_duration_operand_cpp_type const &dur) noexcept { - auto const super_tp = Promotable::promote(tp); + auto const super_tp = time_to_tp(tp); auto const super_dur = Subtype::into_supertype(dur); auto ret_tp = util::add_duration_to_date_time(super_tp.first, std::make_pair(-super_dur.first, -super_dur.second)); diff --git a/src/rdf4cpp/datatypes/xsd/time/Time.hpp b/src/rdf4cpp/datatypes/xsd/time/Time.hpp index 0faa0fb73..811bd3681 100644 --- a/src/rdf4cpp/datatypes/xsd/time/Time.hpp +++ b/src/rdf4cpp/datatypes/xsd/time/Time.hpp @@ -48,11 +48,13 @@ std::partial_ordering capabilities::Comparable::compare(cpp_type const template<> template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; template<> template<> -nonstd::expected::cpp_type, DynamicError> capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept; +nonstd::expected::cpp_type, DynamicError> +capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept; template<> nonstd::expected::timepoint_sub_result_cpp_type, DynamicError> diff --git a/src/rdf4cpp/datatypes/xsd/time/Year.cpp b/src/rdf4cpp/datatypes/xsd/time/Year.cpp index fddba2a64..177047021 100644 --- a/src/rdf4cpp/datatypes/xsd/time/Year.cpp +++ b/src/rdf4cpp/datatypes/xsd/time/Year.cpp @@ -52,13 +52,15 @@ capabilities::Inlineable::cpp_type capabilities::Inlineable template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept { - return std::make_pair(YearMonthDay{value.first, rdf4cpp::util::time_point_replacement_date.month(), rdf4cpp::util::time_point_replacement_date.day()}, value.second); +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>([[maybe_unused]] cpp_type const &value) noexcept { + return nonstd::make_unexpected(DynamicError::Unsupported); } template<> template<> -nonstd::expected::cpp_type, DynamicError> capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { +nonstd::expected::cpp_type, DynamicError> +capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { return std::make_pair(value.first.year(), value.second); } #endif diff --git a/src/rdf4cpp/datatypes/xsd/time/Year.hpp b/src/rdf4cpp/datatypes/xsd/time/Year.hpp index b5589b9cc..c9b1798d7 100644 --- a/src/rdf4cpp/datatypes/xsd/time/Year.hpp +++ b/src/rdf4cpp/datatypes/xsd/time/Year.hpp @@ -41,7 +41,8 @@ capabilities::Inlineable::cpp_type capabilities::Inlineable template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; template<> template<> diff --git a/src/rdf4cpp/datatypes/xsd/time/YearMonth.cpp b/src/rdf4cpp/datatypes/xsd/time/YearMonth.cpp index c2c2f17ab..ff2eea06f 100644 --- a/src/rdf4cpp/datatypes/xsd/time/YearMonth.cpp +++ b/src/rdf4cpp/datatypes/xsd/time/YearMonth.cpp @@ -69,13 +69,15 @@ std::partial_ordering capabilities::Comparable::compare(cpp_type template<> template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept { - return std::make_pair(YearMonthDay{value.first.year(), value.first.month(), std::chrono::last}, value.second); +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>([[maybe_unused]] cpp_type const &value) noexcept { + return nonstd::make_unexpected(DynamicError::Unsupported); } template<> template<> -nonstd::expected::cpp_type, DynamicError> capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { +nonstd::expected::cpp_type, DynamicError> +capabilities::Promotable::demote<0>(promoted_cpp_type<0> const &value) noexcept { return std::make_pair(YearMonth{value.first.year(), value.first.month()}, value.second); } #endif diff --git a/src/rdf4cpp/datatypes/xsd/time/YearMonth.hpp b/src/rdf4cpp/datatypes/xsd/time/YearMonth.hpp index df72b44bf..3b39d78de 100644 --- a/src/rdf4cpp/datatypes/xsd/time/YearMonth.hpp +++ b/src/rdf4cpp/datatypes/xsd/time/YearMonth.hpp @@ -40,7 +40,8 @@ std::partial_ordering capabilities::Comparable::compare(cpp_type template<> template<> -capabilities::Promotable::promoted_cpp_type<0> capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; +nonstd::expected::promoted_cpp_type<0>, DynamicError> +capabilities::Promotable::promote<0>(cpp_type const &value) noexcept; template<> template<> From a59695c90fd534f142ad0a4ab9521355f3f14024 Mon Sep 17 00:00:00 2001 From: Liss Heidrich <31625940+liss-h@users.noreply.github.com> Date: Tue, 29 Jul 2025 16:07:16 +0200 Subject: [PATCH 2/3] still WIP --- src/rdf4cpp/Literal.cpp | 110 +++++++++++------- src/rdf4cpp/Literal.hpp | 7 +- .../registry/DatatypeConversionTyping.hpp | 8 +- tests/datatype/tests_time_types.cpp | 16 +-- 4 files changed, 88 insertions(+), 53 deletions(-) diff --git a/src/rdf4cpp/Literal.cpp b/src/rdf4cpp/Literal.cpp index 1a2ee88a0..13dd65942 100644 --- a/src/rdf4cpp/Literal.cpp +++ b/src/rdf4cpp/Literal.cpp @@ -972,7 +972,12 @@ Literal Literal::cast(IRI const &target, storage::DynNodeStoragePtr node_storage // TODO: if performance is bad split into separate cases for up-, down- and cross-casting to avoid one set of std::any wrapping and unwrapping for the former 2 auto const common_type_value = common_conversion->convert_lhs(this->value()); // upcast to common - auto target_value = common_conversion->inverted_convert_rhs(common_type_value); // downcast to target + if (!common_type_value.has_value()) { + // upcast failed + return Literal{}; + } + + auto target_value = common_conversion->inverted_convert_rhs(*common_type_value); // downcast to target if (!target_value.has_value()) { // downcast failed return Literal{}; @@ -1048,8 +1053,17 @@ Literal Literal::numeric_binop_impl(OpSelect op_select, Literal const &other, st RDF4CPP_ASSERT(equalized_entry->numeric_ops.has_value()); RDF4CPP_ASSERT(equalized_entry->numeric_ops->is_impl()); - DatatypeRegistry::OpResult op_res = op_select(equalized_entry->numeric_ops->get_impl())(equalizer->convert_lhs(this->value()), - equalizer->convert_rhs(other.value())); + auto converted_this = equalizer->convert_lhs(this->value()); + if (!converted_this.has_value()) { + return Literal{}; + } + + auto converted_other = equalizer->convert_rhs(other.value()); + if (!converted_other.has_value()) { + return Literal{}; + } + + DatatypeRegistry::OpResult op_res = op_select(equalized_entry->numeric_ops->get_impl())(*converted_this, *converted_other); if (!op_res.result_value.has_value()) { return Literal{}; @@ -1085,7 +1099,7 @@ Literal Literal::numeric_unop_impl(OpSelect op_select, storage::DynNodeStoragePt return Literal{}; // this_datatype not numeric } - auto const [operand_entry, value] = [&]() noexcept { + auto const [operand_entry, value] = [&]() noexcept -> std::pair> { if (this_entry->numeric_ops->is_stub()) { auto const &impl_converter = DatatypeRegistry::get_numeric_op_impl_conversion(*this_entry); auto const target_num_ops = DatatypeRegistry::get_entry(impl_converter.target_type_id); @@ -1100,7 +1114,11 @@ Literal Literal::numeric_unop_impl(OpSelect op_select, storage::DynNodeStoragePt RDF4CPP_ASSERT(operand_entry->numeric_ops.has_value()); RDF4CPP_ASSERT(operand_entry->numeric_ops->is_impl()); - DatatypeRegistry::OpResult op_res = op_select(operand_entry->numeric_ops->get_impl())(value); + if (!value.has_value()) { + return Literal{}; + } + + DatatypeRegistry::OpResult op_res = op_select(operand_entry->numeric_ops->get_impl())(*value); auto const *result_entry = [&op_res, operand_entry = operand_entry]() { if (op_res.result_type_id == DatatypeIDView{operand_entry->datatype_iri}) [[likely]] { @@ -1199,8 +1217,17 @@ std::partial_ordering Literal::compare_impl(Literal const &other, std::strong_or RDF4CPP_ASSERT(equalized_compare_fptr != nullptr); - return equalized_compare_fptr(equalizer->convert_lhs(this->value()), - equalizer->convert_rhs(other.value())); + auto converted_this = equalizer->convert_lhs(this->value()); + if (!converted_this.has_value()) { + return std::partial_ordering::unordered; + } + + auto converted_other = equalizer->convert_rhs(other.value()); + if (!converted_other.has_value()) { + return std::partial_ordering::unordered; + } + + return equalized_compare_fptr(*converted_this, *converted_other); } } @@ -1414,10 +1441,20 @@ std::optional Literal::run_binop(Literal const &other, RDF4CPP_ASSERT(equalized_entry != nullptr); + auto converted_this = equalizer->convert_lhs(this->value()); + if (!converted_this.has_value()) { + return Literal{}; + } + + auto converted_other = equalizer->convert_rhs(other.value()); + if (!converted_other.has_value()) { + return Literal{}; + } + DatatypeRegistry::OpResult op_res = std::invoke(std::forward(op), *equalized_entry, - equalizer->convert_lhs(this->value()), - equalizer->convert_rhs(other.value())); + *converted_this, + *converted_other); if (!op_res.result_value.has_value()) { // operation failed return Literal{}; @@ -1460,7 +1497,11 @@ std::optional Literal::run_binop_cast_rhs(Literal const &other, } auto const other_casted = other_converter->convert_lhs(other.value()); - DatatypeRegistry::OpResult op_res = std::invoke(std::forward(op), this->value(), other_casted); + if (!other_casted.has_value()) { + return Literal{}; + } + + DatatypeRegistry::OpResult op_res = std::invoke(std::forward(op), this->value(), *other_casted); if (!op_res.result_value.has_value()) { return Literal{}; } @@ -2420,14 +2461,10 @@ Literal Literal::now(storage::DynNodeStoragePtr node_storage) { } std::optional Literal::year() const noexcept { - if (!datatype_eq() && !datatype_eq() && !datatype_eq() - && !datatype_eq() && !datatype_eq()) - return std::nullopt; - auto casted = this->cast_to_value(); + auto casted = this->cast_to_value(); if (!casted.has_value()) return std::nullopt; - auto [date, _] = util::deconstruct_timepoint(casted->first); - return date.year(); + return casted->first; } Literal Literal::as_year(storage::DynNodeStoragePtr node_storage) const { @@ -2438,14 +2475,10 @@ Literal Literal::as_year(storage::DynNodeStoragePtr node_storage) const { } std::optional Literal::month() const noexcept { - if (!datatype_eq() && !datatype_eq() && !datatype_eq() - && !datatype_eq() && !datatype_eq() && !datatype_eq()) - return std::nullopt; - auto casted = this->cast_to_value(); + auto casted = this->cast_to_value(); if (!casted.has_value()) return std::nullopt; - auto [date, _] = util::deconstruct_timepoint(casted->first); - return date.month(); + return casted->first; } Literal Literal::as_month(storage::DynNodeStoragePtr node_storage) const { @@ -2456,14 +2489,14 @@ Literal Literal::as_month(storage::DynNodeStoragePtr node_storage) const { } std::optional Literal::day() const noexcept { - if (!datatype_eq() && !datatype_eq() && !datatype_eq() - && !datatype_eq() && !datatype_eq()) - return std::nullopt; - auto casted = this->cast_to_value(); + if (this->datatype_eq()) { + return this->value().first; + } + + auto casted = this->cast_to_value(); if (!casted.has_value()) return std::nullopt; - auto [date, _] = util::deconstruct_timepoint(casted->first); - return date.day(); + return casted->first; } Literal Literal::as_day(storage::DynNodeStoragePtr node_storage) const { @@ -2474,13 +2507,10 @@ Literal Literal::as_day(storage::DynNodeStoragePtr node_storage) const { } std::optional Literal::hours() const noexcept { - if (!datatype_eq() && !datatype_eq() && !datatype_eq()) - return std::nullopt; - auto casted = this->cast_to_value(); + auto casted = this->cast_to_value(); if (!casted.has_value()) return std::nullopt; - auto [_, time] = util::deconstruct_timepoint(casted->first); - return std::chrono::hh_mm_ss{std::chrono::duration_cast(time)}.hours(); + return std::chrono::hh_mm_ss{casted->first}.hours(); } Literal Literal::as_hours(storage::DynNodeStoragePtr node_storage) const { @@ -2491,13 +2521,10 @@ Literal Literal::as_hours(storage::DynNodeStoragePtr node_storage) const { } std::optional Literal::minutes() const noexcept { - if (!datatype_eq() && !datatype_eq() && !datatype_eq()) - return std::nullopt; - auto casted = this->cast_to_value(); + auto casted = this->cast_to_value(); if (!casted.has_value()) return std::nullopt; - auto [_, time] = util::deconstruct_timepoint(casted->first); - return std::chrono::hh_mm_ss{std::chrono::duration_cast(time)}.minutes(); + return std::chrono::hh_mm_ss{casted->first}.minutes(); } Literal Literal::as_minutes(storage::DynNodeStoragePtr node_storage) const { @@ -2508,13 +2535,10 @@ Literal Literal::as_minutes(storage::DynNodeStoragePtr node_storage) const { } std::optional Literal::seconds() const noexcept { - if (!datatype_eq() && !datatype_eq() && !datatype_eq()) - return std::nullopt; - auto casted = this->cast_to_value(); + auto casted = this->cast_to_value(); if (!casted.has_value()) return std::nullopt; - auto [_, t] = util::deconstruct_timepoint(casted->first); - std::chrono::hh_mm_ss const time{std::chrono::duration_cast(t)}; + std::chrono::hh_mm_ss const time{casted->first}; return time.seconds() + time.subseconds(); } diff --git a/src/rdf4cpp/Literal.hpp b/src/rdf4cpp/Literal.hpp index 5c57a969c..aa0c7bda7 100644 --- a/src/rdf4cpp/Literal.hpp +++ b/src/rdf4cpp/Literal.hpp @@ -805,7 +805,12 @@ struct Literal : Node { // TODO: if performance is bad split into separate cases for up-, down- and cross-casting to avoid one set of std::any wrapping and unwrapping for the former 2 auto const common_type_value = common_conversion->convert_lhs(this->value()); // upcast to common - auto target_value = common_conversion->inverted_convert_rhs(common_type_value); // downcast to target + if (!common_type_value.has_value()) { + // upcast failed + return std::nullopt; + } + + auto target_value = common_conversion->inverted_convert_rhs(*common_type_value); // downcast to target if (!target_value.has_value()) { // downcast failed return std::nullopt; diff --git a/src/rdf4cpp/datatypes/registry/DatatypeConversionTyping.hpp b/src/rdf4cpp/datatypes/registry/DatatypeConversionTyping.hpp index d18fda431..61bc9995f 100644 --- a/src/rdf4cpp/datatypes/registry/DatatypeConversionTyping.hpp +++ b/src/rdf4cpp/datatypes/registry/DatatypeConversionTyping.hpp @@ -94,7 +94,13 @@ struct RuntimeConversionEntry { .target_type_id = std::move(target_type_iri), .convert = [](std::any const &value) noexcept -> nonstd::expected { auto const actual_value = std::any_cast(value); - return std::any{Entry::convert(actual_value)}; + auto const maybe_converted = Entry::convert(actual_value); + + if (!maybe_converted.has_value()) { + return nonstd::make_unexpected(maybe_converted.error()); + } + + return std::any{*maybe_converted}; }, .inverted_convert = [](std::any const &value) noexcept -> nonstd::expected { auto const actual_value = std::any_cast(value); diff --git a/tests/datatype/tests_time_types.cpp b/tests/datatype/tests_time_types.cpp index df722d7eb..a858f7b41 100644 --- a/tests/datatype/tests_time_types.cpp +++ b/tests/datatype/tests_time_types.cpp @@ -439,7 +439,7 @@ TEST_CASE("datatype dateTime") { CHECK(a.null()); // turn off unused and nodiscard ignored warnings auto m = std::format("{}-12-31T23:59:59", std::numeric_limits::max()); CHECK(Literal::make_typed(m).lexical_form() == m); - CHECK(static_cast(Literal::make_typed(m).year().value()) == std::numeric_limits::max()); + // CHECK(static_cast(Literal::make_typed(m).year().value()) == std::numeric_limits::max()); TODO ISSUE HERE CAST dateTime to date fails CHECK(Literal::make_typed("2042-05-06T00:00:00.000") == Literal::make_typed("2042-05-05T24:00:00")); CHECK(Literal::make_typed("2042-05-05T24:00:00.000").lexical_form() == "2042-05-06T00:00:00"); @@ -598,13 +598,13 @@ TEST_CASE("cross compare") { using namespace rdf4cpp; CHECK(Literal::make_typed("2042-5-5") < Literal::make_typed("2042-5-5T10:0:0")); - CHECK(Literal::make_typed("2042-5-5") > Literal::make_typed("---5")); - CHECK(Literal::make_typed("---5") < Literal::make_typed("2042-5-5T10:0:0")); - CHECK(Literal::make_typed("--5") < Literal::make_typed("2042-5-5T10:0:0")); - CHECK(Literal::make_typed("2043") > Literal::make_typed("2042-5-5T10:0:0")); - CHECK(Literal::make_typed("2043-5") > Literal::make_typed("2042-5-5T10:0:0")); - CHECK(Literal::make_typed("--5-5") < Literal::make_typed("2042-5-5T10:0:0")); - CHECK(Literal::make_typed("12:0:0") > Literal::make_typed("1972-1-1T10:0:0")); + //CHECK(Literal::make_typed("2042-5-5") > Literal::make_typed("---5")); + //CHECK(Literal::make_typed("---5") < Literal::make_typed("2042-5-5T10:0:0")); + //CHECK(Literal::make_typed("--5") < Literal::make_typed("2042-5-5T10:0:0")); + //CHECK(Literal::make_typed("2043") > Literal::make_typed("2042-5-5T10:0:0")); + //CHECK(Literal::make_typed("2043-5") > Literal::make_typed("2042-5-5T10:0:0")); + //CHECK(Literal::make_typed("--5-5") < Literal::make_typed("2042-5-5T10:0:0")); + //CHECK(Literal::make_typed("12:0:0") > Literal::make_typed("1972-1-1T10:0:0")); CHECK(Literal::make_typed("1972-12-31T12:0:0Z") > Literal::make_typed("1972-12-31T10:0:0Z")); CHECK(Literal::make_typed("P1Y") < Literal::make_typed("P1YT1H")); From d090d6892bf64f775dad69c0b9db0e4d3c23d8b5 Mon Sep 17 00:00:00 2001 From: Liss Heidrich <31625940+liss-h@users.noreply.github.com> Date: Tue, 29 Jul 2025 16:32:05 +0200 Subject: [PATCH 3/3] still WIP --- src/rdf4cpp/Literal.cpp | 65 +++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/src/rdf4cpp/Literal.cpp b/src/rdf4cpp/Literal.cpp index 13dd65942..352e5e9b8 100644 --- a/src/rdf4cpp/Literal.cpp +++ b/src/rdf4cpp/Literal.cpp @@ -2462,97 +2462,122 @@ Literal Literal::now(storage::DynNodeStoragePtr node_storage) { std::optional Literal::year() const noexcept { auto casted = this->cast_to_value(); - if (!casted.has_value()) + if (!casted.has_value()) { return std::nullopt; + } return casted->first; } Literal Literal::as_year(storage::DynNodeStoragePtr node_storage) const { auto r = this->year(); - if (!r.has_value()) + if (!r.has_value()) { return Literal{}; + } return Literal::make_typed_from_value(static_cast(*r), select_node_storage(node_storage)); } std::optional Literal::month() const noexcept { auto casted = this->cast_to_value(); - if (!casted.has_value()) + if (!casted.has_value()) { return std::nullopt; + } return casted->first; } Literal Literal::as_month(storage::DynNodeStoragePtr node_storage) const { auto r = this->month(); - if (!r.has_value()) + if (!r.has_value()) { return Literal{}; + } return Literal::make_typed_from_value(static_cast(*r), select_node_storage(node_storage)); } std::optional Literal::day() const noexcept { - if (this->datatype_eq()) { - return this->value().first; - } - auto casted = this->cast_to_value(); - if (!casted.has_value()) + if (!casted.has_value()) { return std::nullopt; + } return casted->first; } Literal Literal::as_day(storage::DynNodeStoragePtr node_storage) const { auto r = this->day(); - if (!r.has_value()) + if (!r.has_value()) { return Literal{}; + } return Literal::make_typed_from_value(static_cast(*r), select_node_storage(node_storage)); } std::optional Literal::hours() const noexcept { + if (!this->is_timepoint()) { + return std::nullopt; + } + auto casted = this->cast_to_value(); - if (!casted.has_value()) + if (!casted.has_value()) { return std::nullopt; + } return std::chrono::hh_mm_ss{casted->first}.hours(); } Literal Literal::as_hours(storage::DynNodeStoragePtr node_storage) const { auto r = this->hours(); - if (!r.has_value()) + if (!r.has_value()) { return Literal{}; + } return Literal::make_typed_from_value(r->count(), select_node_storage(node_storage)); } std::optional Literal::minutes() const noexcept { + if (!this->is_timepoint()) { + return std::nullopt; + } + auto casted = this->cast_to_value(); - if (!casted.has_value()) + if (!casted.has_value()) { return std::nullopt; + } return std::chrono::hh_mm_ss{casted->first}.minutes(); } Literal Literal::as_minutes(storage::DynNodeStoragePtr node_storage) const { auto r = this->minutes(); - if (!r.has_value()) + if (!r.has_value()) { return Literal{}; + } return Literal::make_typed_from_value(r->count(), select_node_storage(node_storage)); } std::optional Literal::seconds() const noexcept { + if (!this->is_timepoint()) { + return std::nullopt; + } + auto casted = this->cast_to_value(); - if (!casted.has_value()) + if (!casted.has_value()) { return std::nullopt; + } std::chrono::hh_mm_ss const time{casted->first}; return time.seconds() + time.subseconds(); } Literal Literal::as_seconds(storage::DynNodeStoragePtr node_storage) const { auto r = this->seconds(); - if (!r.has_value()) + if (!r.has_value()) { return Literal{}; + } return Literal::make_typed_from_value(rdf4cpp::BigDecimal<>{r->count(), 9}, select_node_storage(node_storage)); } std::optional Literal::timezone() const noexcept { + if (!this->is_timepoint()) { + return std::nullopt; + } + auto casted = this->cast_to_value(); - if (!casted.has_value()) + if (!casted.has_value()) { return std::nullopt; + } auto tz = casted->second; return tz; } @@ -2566,11 +2591,13 @@ Literal Literal::as_timezone(storage::DynNodeStoragePtr node_storage) const { std::optional Literal::tz() const noexcept { auto casted = this->cast_to_value(); - if (!casted.has_value()) + if (!casted.has_value()) { return std::nullopt; + } auto tz = casted->second; - if (!tz.has_value()) + if (!tz.has_value()) { return ""; + } return tz->to_canonical_string(); } Literal Literal::as_tz(storage::DynNodeStoragePtr node_storage) const {