From da31bbf96ab6e49509afe1d4f2ae0201b61f74e8 Mon Sep 17 00:00:00 2001 From: Folling Date: Fri, 24 Nov 2023 14:52:46 +0100 Subject: [PATCH] intermediate commit Signed-off-by: Folling --- include/ikarus/objects/object_type.h | 14 +- .../properties/settings/property_settings.h | 1 + src/id.cpp | 8 +- src/id.hpp | 2 + src/objects/blueprint.cpp | 132 ++++++++++++++++-- src/objects/property.cpp | 74 ---------- src/objects/property_info.hpp | 74 ---------- src/objects/property_source.hpp | 2 +- .../migrations/m1_initial_layout.sql | 4 +- src/values/value.cpp | 31 ++++ src/values/value.hpp | 8 ++ 11 files changed, 175 insertions(+), 175 deletions(-) delete mode 100644 src/objects/property_info.hpp create mode 100644 src/values/value.cpp create mode 100644 src/values/value.hpp diff --git a/include/ikarus/objects/object_type.h b/include/ikarus/objects/object_type.h index 2539e2d..578919a 100644 --- a/include/ikarus/objects/object_type.h +++ b/include/ikarus/objects/object_type.h @@ -14,18 +14,12 @@ IKARUS_BEGIN_HEADER enum IkarusObjectType { /// \brief Not an object or no object. IkarusObjectType_None = 0, - /// \brief An IkarusBlueprint. - IkarusObjectType_Blueprint = 0b00000001, - /// \brief An IkarusProperty. - IkarusObjectType_Property = 0b00000010, /// \brief An IkarusEntity. IkarusObjectType_Entity = 0b00000011, - /// \brief An IkarusBlueprintFolder - IkarusObjectType_BlueprintFolder = 0b01000001, - /// \brief An IkarusPropertyFolder - IkarusObjectType_PropertyFolder = 0b01000010, - /// \brief An IkarusEntityFolder - IkarusObjectType_EntityFolder = 0b01000011, + /// \brief An IkarusProperty. + IkarusObjectType_Property = 0b00000010, + /// \brief An IkarusBlueprint. + IkarusObjectType_Blueprint = 0b00000001, }; IKARUS_END_HEADER diff --git a/include/ikarus/objects/properties/settings/property_settings.h b/include/ikarus/objects/properties/settings/property_settings.h index 359097c..a47541e 100644 --- a/include/ikarus/objects/properties/settings/property_settings.h +++ b/include/ikarus/objects/properties/settings/property_settings.h @@ -79,6 +79,7 @@ IKA_API void ikarus_property_settings_visit( void * data ); +/// \see ikarus_property_settings_visit IKA_API void ikarus_property_settings_visit_const( struct IkarusPropertySettings const * settings, void (*toggle_property_visitor)(struct IkarusTogglePropertySettings const * settings, void * data), diff --git a/src/id.cpp b/src/id.cpp index cc3913f..7ec6491 100644 --- a/src/id.cpp +++ b/src/id.cpp @@ -7,12 +7,12 @@ uint64_t const IKARUS_ID_OBJECT_TYPE_BITS = 8; uint64_t const IKARUS_ID_OBJECT_RANDOM_BITS = sizeof(IkarusId) - IKARUS_ID_OBJECT_TYPE_BITS; -auto ikarus_id_get_object_type(IkarusId id) -> IkarusObjectType { - return static_cast(id >> IKARUS_ID_OBJECT_RANDOM_BITS); +auto from_data_and_type(int64_t data, IkarusObjectType type) -> IkarusId { + return data | (static_cast(type) << IKARUS_ID_OBJECT_RANDOM_BITS); } -auto ikarus_id_is_equal(IkarusId left, IkarusId right) -> bool { - return left == right; +auto ikarus_id_get_object_type(IkarusId id) -> IkarusObjectType { + return static_cast(id >> IKARUS_ID_OBJECT_RANDOM_BITS); } TEST_CASE("id_object_type", "[id]") { diff --git a/src/id.hpp b/src/id.hpp index 4499c17..fc61b05 100644 --- a/src/id.hpp +++ b/src/id.hpp @@ -30,6 +30,8 @@ IKARUS_BEGIN_HEADER /// - last 56 bits: incremented counter generated by the database using IkarusId = int64_t; +IKA_API IkarusId ikarus_id_from_data_and_type(int64_t data, IkarusObjectType type); + /// \brief Fetches the object type of the given id. /// \param id The id to fetch the object type for. /// \return The object type of the given id. diff --git a/src/objects/blueprint.cpp b/src/objects/blueprint.cpp index df059ac..d6a38b1 100644 --- a/src/objects/blueprint.cpp +++ b/src/objects/blueprint.cpp @@ -1,4 +1,4 @@ -#include "blueprint.hpp" +#include #include #include @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -18,7 +19,7 @@ IkarusBlueprint * ikarus_blueprint_create(struct IkarusProject * project, char c return nullptr; } - auto ctx = project->function_context(); + auto * ctx = project->function_context(); if (name == nullptr) { ctx->set_error("name is nullptr", true, IkarusErrorInfo_Source_Client, IkarusErrorInfo_Type_Client_Input); @@ -30,7 +31,7 @@ IkarusBlueprint * ikarus_blueprint_create(struct IkarusProject * project, char c return nullptr; } - LOG_VERBOSE("project={}; name={}", project->path().c_str(), name); + LOG_DEBUG("project={}; name={}", project->path().c_str(), name); VTRYRV( auto id, @@ -45,9 +46,9 @@ IkarusBlueprint * ikarus_blueprint_create(struct IkarusProject * project, char c name )); - auto id = db->last_insert_rowid(); + auto id = ikarus_id_from_data_and_type(db->last_insert_rowid(), IkarusObjectType_Blueprint); - LOG_VERBOSE("id is {}", id); + LOG_DEBUG("blueprint is {}", id); LOG_VERBOSE("inserting blueprint into blueprints table"); @@ -80,7 +81,7 @@ void ikarus_blueprint_delete(IkarusBlueprint * blueprint) { auto * ctx = blueprint->project->function_context(); - LOG_VERBOSE("blueprint={}", blueprint->id); + LOG_DEBUG("blueprint={}", blueprint->id); TRYRV( , @@ -113,13 +114,13 @@ size_t ikarus_blueprint_get_property_count(IkarusBlueprint const * blueprint) { auto * ctx = blueprint->project->function_context(); - LOG_VERBOSE("blueprint={}", blueprint->id); + LOG_DEBUG("blueprint={}", blueprint->id); VTRYRV( auto count, 0, blueprint->project->db() - ->query_one("SELECT COUNT(*) FROM `blueprint_properties` WHERE `blueprint_id` = ?;", blueprint->id) + ->query_one("SELECT COUNT(*) FROM `blueprint_properties` WHERE `blueprint` = ?;", blueprint->id) .on_error([ctx](auto const& err) { ctx->set_error( fmt::format("failed to fetch blueprint property count: {}", err), @@ -130,6 +131,10 @@ size_t ikarus_blueprint_get_property_count(IkarusBlueprint const * blueprint) { }) ); + LOG_DEBUG("blueprint property count: {}", count); + + LOG_VERBOSE("successfully fetched blueprint property count"); + return static_cast(count); } @@ -146,11 +151,11 @@ void ikarus_blueprint_get_properties( auto * ctx = blueprint->project->function_context(); if (properties_out == nullptr) { - LOG_ERROR("properties_out is nullptr"); + ctx->set_error("properties_out is null", true, IkarusErrorInfo_Source_Client, IkarusErrorInfo_Type_Client_Input); return; } - LOG_VERBOSE("blueprint={}; properties_out_size={}", blueprint->id, properties_out_size); + LOG_DEBUG("blueprint={}; properties_out_size={}", blueprint->id, properties_out_size); IkarusId ids[properties_out_size]; @@ -173,6 +178,8 @@ void ikarus_blueprint_get_properties( }) ); + LOG_DEBUG("blueprint properties: [{}]", fmt::join(ids, ids + properties_out_size, ", ")); + for (size_t i = 0; i < properties_out_size; ++i) { /// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) properties_out[i] = blueprint->project->get_property(ids[i]); @@ -180,3 +187,108 @@ void ikarus_blueprint_get_properties( LOG_VERBOSE("successfully fetched blueprint properties"); } + +size_t ikarus_blueprint_get_linked_entity_count(IkarusBlueprint const * blueprint) { + LOG_VERBOSE("fetching blueprint linked entity count"); + + if (blueprint == nullptr) { + LOG_ERROR("blueprint is nullptr"); + return 0; + } + + auto * ctx = blueprint->project->function_context(); + + LOG_DEBUG("blueprint={}", blueprint->id); + + VTRYRV( + auto count, + 0, + blueprint->project->db() + ->query_one("SELECT COUNT(*) FROM `entity_blueprint_links` WHERE `blueprint` = ?;", blueprint->id) + .on_error([ctx](auto const& err) { + ctx->set_error( + fmt::format("failed to fetch blueprint linked entity count: {}", err), + true, + IkarusErrorInfo_Source_SubSystem, + IkarusErrorInfo_Type_SubSystem_Database + ); + }) + ); + + LOG_DEBUG("blueprint linked entity count: {}", count); + + LOG_VERBOSE("successfully fetched blueprint linked entity count: {}", count); + + return static_cast(count); +} + +void ikarus_blueprint_get_linked_entities( + IkarusBlueprint const * blueprint, struct IkarusEntity ** entities_out, size_t entities_out_size +) { + LOG_VERBOSE("fetching blueprint linked entities"); + + if (blueprint == nullptr) { + LOG_ERROR("blueprint is nullptr"); + return; + } + + auto * ctx = blueprint->project->function_context(); + + if (entities_out == nullptr) { + ctx->set_error("entities_out is null", true, IkarusErrorInfo_Source_Client, IkarusErrorInfo_Type_Client_Input); + return; + } + + LOG_DEBUG("blueprint={}; entities_out_size={}", blueprint->id, entities_out_size); + + IkarusId ids[entities_out_size]; + + TRYRV( + , + blueprint->project->db() + ->query_many_buffered( + "SELECT `entity` FROM `entity_blueprint_links` WHERE `blueprint` = ?", + static_cast(ids), + entities_out_size, + blueprint->id + ) + .on_error([ctx](auto const& err) { + ctx->set_error( + fmt::format("failed to fetch blueprint linked entity ids: {}", err), + true, + IkarusErrorInfo_Source_SubSystem, + IkarusErrorInfo_Type_SubSystem_Database + ); + }) + ); + + LOG_DEBUG("blueprint linked entities: [{}]", fmt::join(ids, ids + entities_out_size, ", ")); + + for (size_t i = 0; i < entities_out_size; ++i) { + /// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + entities_out[i] = blueprint->project->get_entity(ids[i]); + } + + LOG_VERBOSE("successfully fetched blueprint linked entities"); +} + +IkarusObject * ikarus_blueprint_to_object(IkarusBlueprint * blueprint) { + return const_cast(ikarus_blueprint_to_object_const(blueprint)); +} + +IkarusObject const * ikarus_blueprint_to_object_const(IkarusBlueprint const * blueprint) { + LOG_VERBOSE("casting blueprint to object"); + + if (blueprint == nullptr) { + LOG_ERROR("blueprint is nullptr"); + return nullptr; + } + + // auto * ctx = blueprint->project->function_context(); + + LOG_DEBUG("blueprint={}", blueprint->id); + + LOG_VERBOSE("successfully casted blueprint to object"); + + return static_cast(blueprint); +} diff --git a/src/objects/property.cpp b/src/objects/property.cpp index ba11491..80d9031 100644 --- a/src/objects/property.cpp +++ b/src/objects/property.cpp @@ -9,79 +9,5 @@ #include #include #include -#include #include #include - -IkarusProperty * ikarus_property_create( - struct IkarusProject * project, - char const * name, - struct IkarusPropertySource * property_source, - struct IkarusPropertyInfo * property_info -) { - LOG_INFO("creating new property"); - - if (project == nullptr) { - LOG_ERROR("project is nullptr"); - return nullptr; - } - - auto ctx = project->function_context(); - - if (property_source == nullptr) { - ctx->set_error("property_source is nullptr", true, IkarusErrorInfo_Source_Client, IkarusErrorInfo_Type_Client_Input); - return nullptr; - } - - if (name == nullptr) { - ctx->set_error("name is nullptr", true, IkarusErrorInfo_Source_Client, IkarusErrorInfo_Type_Client_Input); - return nullptr; - } - - if (cppbase::is_empty_or_blank(name)) { - ctx->set_error("name is empty or blank", true, IkarusErrorInfo_Source_Client, IkarusErrorInfo_Type_Client_Input); - return nullptr; - } - - if (property_info == nullptr) { - ctx->set_error("property_info is nullptr", true, IkarusErrorInfo_Source_Client, IkarusErrorInfo_Type_Client_Input); - return nullptr; - } - - LOG_VERBOSE( - "project={}; name={}; property_source={}; property_info={}", - project->path().c_str(), - name, - std::visit( - cppbase::overload{ - [](IkarusBlueprint * blueprint) { return fmt::format("Blueprint({})", blueprint->id); }, - [](IkarusEntity * entity) { return fmt::format("Entity({})", entity->id); }}, - property_source->data - ), - std::visit( - cppbase::overload{ - [](IkarusTogglePropertyInfo * info) { - return fmt::format( - "Toggle(default_value={})", - cppbase::OwningString{ikarus_value_to_string(ikarus_toggle_value_to_entity_value(info->default_value))} - .data - ); - }, - [](IkarusNumberPropertyInfo * info) { - return fmt::format( - "Number(default_value={})", - cppbase::OwningString{ikarus_value_to_string(ikarus_number_value_to_entity_value(info->default_value))} - .data - ); - }, - [](IkarusTextPropertyInfo * info) { - return fmt::format( - "Text(default_value={})", - cppbase::OwningString{ikarus_value_to_string(ikarus_text_value_to_entity_value(info->default_value))} - .data - ); - }}, - property_info->data - ) - ); -} diff --git a/src/objects/property_info.hpp b/src/objects/property_info.hpp deleted file mode 100644 index 8c131f7..0000000 --- a/src/objects/property_info.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include - -#include - -#include -#include -#include - -// this looks a bit cursed, but there's reason to my madness: -// Let's go over the facts: -// 1. The client uses the concrete types (e.g. Ikarus"Toggle"PropertyInfo) -// 2. The API needs to accept a common type (i.e. IkarusPropertyInfo) -// 3. Casting between a concrete subtype and a common type is only defined behaviour if we use inheritance, otherwise an -// allocation is unavoidable -// 4. On the implementation side, we need to be able to distinguish between the concrete types -// -// There's a few ways to model this (using dynamic_casts, using an enum, a union, the visitor pattern, ...) but std::variant -// gives us the most type safety without any performance overhead - -/// \private -struct IkarusPropertyInfo { -public: - using IkarusPropertyInfoData = - std::variant; - -public: - inline explicit IkarusPropertyInfo( - std::variant data - ): - data{data} {} - -public: - [[nodiscard]] inline IkarusPropertyInfoData const& get_data() const { - return data; - } - -private: - IkarusPropertyInfoData data; -}; - -/// \private -struct IkarusTogglePropertyInfo : public IkarusPropertyInfo { -public: - inline IkarusTogglePropertyInfo(): - IkarusPropertyInfo{this} {} - -public: - [[nodiscard]] IkarusToggleValue * get_default_value() const {} - -private: - IkarusToggleValue * default_value{nullptr}; -}; - -/// \private -struct IkarusNumberPropertyInfo : public IkarusPropertyInfo { -public: - inline IkarusNumberPropertyInfo(): - IkarusPropertyInfo{this} {} - -private: - IkarusNumberValue * default_value{nullptr}; -}; - -/// \private -struct IkarusTextPropertyInfo : public IkarusPropertyInfo { -public: - inline IkarusTextPropertyInfo(): - IkarusPropertyInfo{this} {} - -private: - IkarusTextValue * default_value{nullptr}; -}; diff --git a/src/objects/property_source.hpp b/src/objects/property_source.hpp index 16fab4f..e2a2739 100644 --- a/src/objects/property_source.hpp +++ b/src/objects/property_source.hpp @@ -2,7 +2,7 @@ #include -#include +#include /// \private struct IkarusPropertySource { diff --git a/src/persistence/migrations/m1_initial_layout.sql b/src/persistence/migrations/m1_initial_layout.sql index 7b49cb6..d94fa10 100644 --- a/src/persistence/migrations/m1_initial_layout.sql +++ b/src/persistence/migrations/m1_initial_layout.sql @@ -39,7 +39,7 @@ CREATE TABLE `entities` FOREIGN KEY (`id`) REFERENCES `objects` (`id`) ON DELETE CASCADE ) WITHOUT ROWID, STRICT; -CREATE TABLE `entity_blueprints` +CREATE TABLE `entity_blueprint_links` ( `entity` INT NOT NULL, `blueprint` INT NOT NULL, @@ -50,7 +50,7 @@ CREATE TABLE `entity_blueprints` FOREIGN KEY (`blueprint`) REFERENCES `blueprints` (`id`) ON DELETE CASCADE ) WITHOUT ROWID, STRICT; -CREATE INDEX `entity_blueprints_blueprint` ON `entity_blueprints` (`blueprint`); +CREATE INDEX `entity_blueprints_blueprint` ON `entity_blueprint_links` (`blueprint`); CREATE TABLE `properties` ( diff --git a/src/values/value.cpp b/src/values/value.cpp new file mode 100644 index 0000000..52b4d18 --- /dev/null +++ b/src/values/value.cpp @@ -0,0 +1,31 @@ +#include "ikarus/values/value.h" + +#include + +#include + +#include +#include +#include +#include + +bool ikarus_value_is_indeterminate(IkarusValue const * value) { + return value->indeterminate; +} + +char const * ikarus_value_to_string(IkarusValue const * value) { + auto str = std::visit( + cppbase::overloaded{ + [](IkarusToggleValue const * toggle_value) -> std::string { return toggle_value->value ? "true" : "false"; }, + [](IkarusNumberValue const * number_value) -> std::string { return fmt::format("{}", number_value->value); }, + [](IkarusTextValue const * text_value) -> std::string { return fmt::format("{}", text_value->value); }, + }, + value->data + ); + + char * ret = new char[str.size() + 1]; + + std::strncpy(ret, str.data(), str.size() + 1); + + return ret; +} diff --git a/src/values/value.hpp b/src/values/value.hpp new file mode 100644 index 0000000..1d53154 --- /dev/null +++ b/src/values/value.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +struct IkarusValue { + bool indeterminate; + std::variant data; +};