diff --git a/include/ikarus/objects/entity.h b/include/ikarus/objects/entity.h index 2ac9087..5ce2266 100644 --- a/include/ikarus/objects/entity.h +++ b/include/ikarus/objects/entity.h @@ -112,7 +112,7 @@ IKA_API void ikarus_entity_get_properties( ); /// \brief Gets the value of a property of an entity. -/// \details If the entity has never set the value of the property, the default value is returned (which may be indeterminate). +/// \details If the entity has never set the value of the property, the default value is returned (which may be undefined). /// \param entity The entity to get the value of. /// \pre \li Must not be null. /// \pre \li Must exist. diff --git a/include/ikarus/values/number_value.h b/include/ikarus/values/number_value.h index 7049af8..cedd61d 100644 --- a/include/ikarus/values/number_value.h +++ b/include/ikarus/values/number_value.h @@ -25,7 +25,7 @@ IKA_API IkarusNumberValue * ikarus_number_value_create(); /// \param idx The index of the data to fetch. /// \pre \li Must be less than the size of the value. /// \return The underlying data or null if an error occurs or the value is undefined. -IKA_API long double const * ikarus_number_value_get(IkarusNumberValue * value, size_t idx); +IKA_API double const * ikarus_number_value_get(IkarusNumberValue * value, size_t idx); /// \brief Fetches the size of the underlying data of a number value. /// \param value The number value. @@ -39,7 +39,7 @@ IKA_API size_t ikarus_number_value_get_size(IkarusNumberValue const * value); /// \param idx The index of the data to set. /// \pre \li Must be less than the size of the value. /// \param new_data The new data. -IKA_API void ikarus_number_value_set(IkarusNumberValue * value, size_t idx, long double const * new_data); +IKA_API void ikarus_number_value_set(IkarusNumberValue * value, size_t idx, double const * new_data); /// \brief Removes a data from a number value. /// \param value The number value. @@ -54,7 +54,7 @@ IKA_API void ikarus_number_value_remove(IkarusNumberValue * value, size_t idx); /// \param idx The index of the data to insert. /// \pre \li Must be less than or equal to the size of the value. /// \param new_data The new data. -IKA_API void ikarus_number_value_insert(IkarusNumberValue * value, size_t idx, long double const * new_data); +IKA_API void ikarus_number_value_insert(IkarusNumberValue * value, size_t idx, double const * new_data); /// \brief Clears a number value. /// \param value The number value. diff --git a/src/objects/properties/property.cpp b/src/objects/properties/property.cpp index d1eb94a..00ab888 100644 --- a/src/objects/properties/property.cpp +++ b/src/objects/properties/property.cpp @@ -91,8 +91,9 @@ IkarusPropertySource const * ikarus_property_get_source(IkarusProperty const * p auto * ctx = property->get_project()->get_function_context(); - VTRY( + VTRYRV( auto const source, + nullptr, property->get_project() ->get_db() ->query_one("SELECT `source` FROM `properties` WHERE `id` = ?", property->get_id()) @@ -129,8 +130,9 @@ IkarusValue * ikarus_property_get_default_value(IkarusProperty const * property) auto * ctx = property->get_project()->get_function_context(); - VTRY( + VTRYRV( auto const value, + nullptr, property->get_project() ->get_db() ->query_one("SELECT `default_value` FROM `properties` WHERE `id` = ?", property->get_id()) @@ -144,7 +146,7 @@ IkarusValue * ikarus_property_get_default_value(IkarusProperty const * property) }) ); - return new IkarusValue(property->get_project(), value); + return IkarusValue::from_json(value).unwrap_value_or(nullptr); } void ikarus_property_visit( diff --git a/src/redirect/json.hpp b/src/redirect/json.hpp new file mode 100644 index 0000000..c45bde6 --- /dev/null +++ b/src/redirect/json.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/src/values/number_value.cpp b/src/values/number_value.cpp index cef3508..b408925 100644 --- a/src/values/number_value.cpp +++ b/src/values/number_value.cpp @@ -12,7 +12,7 @@ IkarusNumberValue * ikarus_number_value_create() { return new IkarusNumberValue{}; } -long double const * ikarus_number_value_get(IkarusNumberValue * value, size_t idx) { +double const * ikarus_number_value_get(IkarusNumberValue * value, size_t idx) { return ikarus_value_base_get(value, idx); } @@ -20,7 +20,7 @@ size_t ikarus_number_value_get_size(IkarusNumberValue const * value) { return ikarus_value_base_get_size(value); } -void ikarus_number_value_set(IkarusNumberValue * value, size_t idx, long double new_data) { +void ikarus_number_value_set(IkarusNumberValue * value, size_t idx, double new_data) { return ikarus_value_base_set(value, idx, new_data); } @@ -45,12 +45,7 @@ void ikarus_number_value_set_undefined(IkarusNumberValue * value, bool undefined } char const * ikarus_number_value_to_string(IkarusNumberValue const * value) { - return boost::variant2::visit( - boost::make_overloaded_function( - [](boost::variant2::monostate const&) { return nullptr; }, [](auto const& data) { return fmt::join(data, ", "); } - ), - value->data - ); + return ikarus_value_base_to_string(value, [](auto const& value) { return value; }); } bool ikarus_number_value_is_equal(IkarusNumberValue const * lhs, IkarusNumberValue const * rhs) { diff --git a/src/values/number_value.hpp b/src/values/number_value.hpp index 6cad130..16f99c7 100644 --- a/src/values/number_value.hpp +++ b/src/values/number_value.hpp @@ -1,13 +1,13 @@ #pragma once -#include +#include #include #include struct IkarusNumberValue final : IkarusValue { public: - using data_type = long double; + using data_type = double; public: explicit IkarusNumberValue(); @@ -21,7 +21,6 @@ public: ~IkarusNumberValue() override = default; public: - boost::variant2:: - variant> - data{}; + boost::variant2::variant> data{ + }; }; diff --git a/src/values/text_value.cpp b/src/values/text_value.cpp index 08ad03a..ff09770 100644 --- a/src/values/text_value.cpp +++ b/src/values/text_value.cpp @@ -1,5 +1,6 @@ #include "ikarus/values/text_value.h" +#include #include #include @@ -45,12 +46,7 @@ void ikarus_text_value_set_undefined(IkarusTextValue * value, bool undefined) { } char const * ikarus_text_value_to_string(IkarusTextValue const * value) { - return boost::variant2::visit( - boost::make_overloaded_function( - [](boost::variant2::monostate const&) { return nullptr; }, [](auto const& data) { return fmt::join(data, ", "); } - ), - value->data - ); + return ikarus_value_base_to_string(value, [](auto const& value) { return value; }); } bool ikarus_text_value_is_equal(IkarusTextValue const * lhs, IkarusTextValue const * rhs) { diff --git a/src/values/text_value.hpp b/src/values/text_value.hpp index 8d063f2..1ff74ac 100644 --- a/src/values/text_value.hpp +++ b/src/values/text_value.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include diff --git a/src/values/toggle_value.cpp b/src/values/toggle_value.cpp index 37b2069..c5ced27 100644 --- a/src/values/toggle_value.cpp +++ b/src/values/toggle_value.cpp @@ -46,17 +46,7 @@ void ikarus_toggle_value_set_undefined(IkarusToggleValue * value, bool undefined } char const * ikarus_toggle_value_to_string(IkarusToggleValue const * value) { - return boost::variant2::visit( - boost::make_overloaded_function( - [](boost::variant2::monostate const&) { return nullptr; }, - [](auto const& data) { - return fmt::join( - data | boost::adaptors::transformed([](auto const& bool_value) { return bool_value ? "✓" : "✗"; }), ", " - ); - } - ), - value->data - ); + return ikarus_value_base_to_string(value, [](auto const& value) { return value ? "✓" : "✗"; }); } bool ikarus_toggle_value_is_equal(IkarusToggleValue const * lhs, IkarusToggleValue const * rhs) { diff --git a/src/values/toggle_value.hpp b/src/values/toggle_value.hpp index 6506dda..20c579c 100644 --- a/src/values/toggle_value.hpp +++ b/src/values/toggle_value.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include diff --git a/src/values/value.cpp b/src/values/value.cpp index b9a53a7..81cdaa9 100644 --- a/src/values/value.cpp +++ b/src/values/value.cpp @@ -2,10 +2,11 @@ #include +#include #include -#include -#include +// required for header-only inclusion +#include #include @@ -17,7 +18,7 @@ IkarusValue::IkarusValue(Data data): data(data) {} -cppbase::Result IkarusValue::from_json(boost::json::value const& json) { +cppbase::Result IkarusValue::from_json(boost::json::value const& json) { if (auto const * obj = json.if_object(); obj == nullptr) { return cppbase::err(FromJsonError{}); } else { @@ -35,15 +36,23 @@ cppbase::Result IkarusValue::from_json( } auto create_value = [data]() -> cppbase::Result { - auto * ret = new T{}; - auto res = boost::json::try_value_to>(*data); + T * ret = nullptr; - if (res.has_error()) { - return cppbase::err(FromJsonError{}); + if (data->is_null()) { + ret = new T{}; + ret->data = boost::variant2::monostate{}; + } else { + auto res = boost::json::try_value_to< + boost::container::small_vector>(*data); + + if (res.has_error()) { + return cppbase::err(FromJsonError{}); + } + + ret = new T{}; + ret->data = std::move(res.value()); } - ret->data = std::move(res.value()); - return cppbase::ok(ret); }; @@ -74,7 +83,18 @@ boost::json::value IkarusValue::to_json() const { data ); - auto data_json = boost::variant2::visit([](auto const * value) { return boost::json::value_from(value->data); }, data); + auto data_json = boost::variant2::visit( + [](T const * value) -> boost::json::value { + return boost::variant2::visit( + boost::make_overloaded_function( + []([[maybe_unused]] boost::variant2::monostate const& data) -> boost::json::value { return nullptr; }, + [](auto const& data) -> boost::json::value { return boost::json::value_from(data); } + ), + value->data + ); + }, + data + ); return { {"type", type}, diff --git a/src/values/value.hpp b/src/values/value.hpp index 14c2a73..20b4717 100644 --- a/src/values/value.hpp +++ b/src/values/value.hpp @@ -8,7 +8,7 @@ struct IkarusValue { public: using Data = boost::variant2::variant; - constexpr auto SMALL_VEC_VALUE_SIZE = 8; + constexpr static auto SMALL_VEC_VALUE_SIZE = 8; public: explicit IkarusValue(Data data); @@ -24,7 +24,7 @@ public: public: struct FromJsonError {}; - [[nodiscard]] static cppbase::Result from_json(boost::json::value const& json); + [[nodiscard]] static cppbase::Result from_json(boost::json::value const& json); [[nodiscard]] boost::json::value to_json() const; public: diff --git a/src/values/value_base.hpp b/src/values/value_base.hpp index 04bad48..416be34 100644 --- a/src/values/value_base.hpp +++ b/src/values/value_base.hpp @@ -1,8 +1,19 @@ #pragma once +#include +#include + +#include +#include +#include + template typename V::data_type const * ikarus_value_base_get(V * value, size_t idx) { - if (auto * data = value->data.template get_if>(); data != nullptr) { + if (auto * data = + boost::variant2::get_if>( + &value->data + ); + data != nullptr) { return &(*data)[idx]; } @@ -11,7 +22,11 @@ typename V::data_type const * ikarus_value_base_get(V * value, size_t idx) { template size_t ikarus_value_base_get_size(V const * value) { - if (auto * data = value->data.template get_if>(); data != nullptr) { + if (auto * data = + boost::variant2::get_if>( + &value->data + ); + data != nullptr) { return data->size(); } @@ -20,28 +35,44 @@ size_t ikarus_value_base_get_size(V const * value) { template void ikarus_value_base_set(V * value, size_t idx, typename V::data_type new_data) { - if (auto * data = value->data.template get_if>(); data != nullptr) { + if (auto * data = + boost::variant2::get_if>( + &value->data + ); + data != nullptr) { (*data)[idx] = new_data; } } template void ikarus_value_base_remove(V * value, size_t idx) { - if (auto * data = value->data.template get_if>(); data != nullptr) { + if (auto * data = + boost::variant2::get_if>( + &value->data + ); + data != nullptr) { data->erase(data->begin() + idx); } } template void ikarus_value_base_insert(V * value, size_t idx, typename V::data_type new_data) { - if (auto * data = value->data.template get_if>(); data != nullptr) { + if (auto * data = + boost::variant2::get_if>( + &value->data + ); + data != nullptr) { data->insert(data->begin() + idx, new_data); } } template void ikarus_value_base_clear(V * value) { - if (auto * data = value->data.template get_if>(); data != nullptr) { + if (auto * data = + boost::variant2::get_if>( + &value->data + ); + data != nullptr) { data->clear(); } } @@ -56,10 +87,32 @@ void ikarus_value_base_set_undefined(V * value, bool undefined) { if (undefined) { value->data = boost::variant2::monostate{}; } else { - value->data = typename V::data_type{}; + value->data = boost::container::small_vector{}; } } +template F> +char const * ikarus_value_base_to_string(V const * value, F transformer) { + return boost::variant2::visit( + boost::make_overloaded_function( + [](boost::variant2::monostate const&) -> char const * { return nullptr; }, + [&transformer](boost::container::small_vector const& data + ) -> char const * { + auto buffer = fmt::memory_buffer{}; + + fmt::format_to( + std::back_inserter(buffer), + "{}", + fmt::join(data | std::views::transform(std::forward(transformer)), ", ") + ); + + return buffer.data(); + } + ), + value->data + ); +} + template bool ikarus_value_base_is_equal(V const * lhs, V const * rhs) { return lhs->data == rhs->data;