From 20d1cf826408894f0765410fa9d72494959a7905 Mon Sep 17 00:00:00 2001 From: folling Date: Thu, 24 Aug 2023 16:40:54 +0200 Subject: [PATCH] id interface Signed-off-by: Folling --- include/ikarus/stdtypes.h | 1 + include/ikarus/types/id.h | 19 +++++++--- include/ikarus/types/object_type.h | 28 +++++++-------- src/types/id.cpp | 56 ++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 19 deletions(-) create mode 100644 src/types/id.cpp diff --git a/include/ikarus/stdtypes.h b/include/ikarus/stdtypes.h index 2f467cf..d5f7ab2 100644 --- a/include/ikarus/stdtypes.h +++ b/include/ikarus/stdtypes.h @@ -1,6 +1,7 @@ #pragma once #ifdef __cplusplus +#include #include using std::size_t; #else diff --git a/include/ikarus/types/id.h b/include/ikarus/types/id.h index a205e43..e2ca0b5 100644 --- a/include/ikarus/types/id.h +++ b/include/ikarus/types/id.h @@ -6,10 +6,10 @@ #pragma once #include +#include IKARUS_BEGIN_HEADER -#include #include /// \defgroup id Ids @@ -21,11 +21,13 @@ IKARUS_BEGIN_HEADER /// \brief A wrapper around a 64 bit integer that represents the id of an object. /// \details They are stored as 64 bit integers with the following layout: -/// - first 8 bits: #IkarusObjectType - 255 possible values, 0 for special values +/// - first bit: ignored, technically we could use it, but SQLite doesn't support u64 integers. +/// To avoid ordering fiascos and potential index performance degradation we just skip the first bit. +/// - next 7 bits: #IkarusObjectType - 127 possible values, 0 for special values /// - last 56 bits: incremented counter generated by the database struct IkarusId { /// \private \brief The value of the id. - uint64_t value; + int64_t data; }; /// \brief A special id returned by failed functions. @@ -34,9 +36,16 @@ IkarusId const IKARUS_ID_NONE{0}; IkarusId const IKARUS_ID_UNSPECIFIED{1}; /// \private \brief Generates a new id for the given object type. -/// \param object_type The type of the object to generate an id for. +/// \param data The data from which the id will be constructed. /// \return The generated id. -IkarusId ikarus_id_from_integer(IkarusObjectType object_type); +/// \pre data must be valid under the format described in Id. It should also point to an object in the database. +IkarusId ikarus_id_from_data(int64_t data); + +/// \brief Checkes whether two ids are equal +/// \param left the left side of the comparison +/// \param right the right side of the comparison +/// \return True if the bits from the left id are equal to the bits of the right id +bool ikarus_id_is_equal(IkarusId left, IkarusId right); /// \brief Fetches the object type of the given id. /// \param id The id to fetch the object type for. diff --git a/include/ikarus/types/object_type.h b/include/ikarus/types/object_type.h index ca3dfb0..1c0cf9d 100644 --- a/include/ikarus/types/object_type.h +++ b/include/ikarus/types/object_type.h @@ -25,37 +25,37 @@ enum IkarusFolderType { /// \remark folders have the first bit set and then mirror the object type of the underlying object enum IkarusObjectType { /// \brief Not an object or no object. - ObjectType_None = 0, + IkarusObjectType_None = 0, /// \brief An IkarusBlueprint. - ObjectType_Blueprint = 0b0000'0001, + IkarusObjectType_Blueprint = 0b0000'0001, /// \brief An IkarusProperty. - ObjectType_Property = 0b0000'0010, + IkarusObjectType_Property = 0b0000'0010, /// \brief An IkarusEntity. - ObjectType_Entity = 0b0000'0011, + IkarusObjectType_Entity = 0b0000'0011, /// \brief An IkarusBlueprintFolder - ObjectType_BlueprintFolder = 0b1000'0001, + IkarusObjectType_BlueprintFolder = 0b1000'0001, /// \brief An IkarusPropertyFolder - ObjectType_PropertyFolder = 0b1000'0010, + IkarusObjectType_PropertyFolder = 0b1000'0010, /// \brief An IkarusEntityFolder - ObjectType_EntityFolder = 0b1000'0011, + IkarusObjectType_EntityFolder = 0b1000'0011, }; /// \brief A bitset of IkarusObjectType%s. enum ObjectTypes { /// \brief No object type. - ObjectTypes_None = 0, + IkarusObjectTypes_None = 0, /// \brief An IkarusBlueprint. - ObjectTypes_Blueprint = 1 << ObjectType_Blueprint, + IkarusObjectTypes_Blueprint = 1 << IkarusObjectType_Blueprint, /// \brief An IkarusProperty. - ObjectTypes_Property = 1 << ObjectType_Property, + IkarusObjectTypes_Property = 1 << IkarusObjectType_Property, /// \brief An IkarusEntity. - ObjectTypes_Entity = 1 << ObjectType_Entity, + IkarusObjectTypes_Entity = 1 << IkarusObjectType_Entity, /// \brief An IkarusBlueprintFolder - ObjectTypes_BlueprintFolder = 1 << ObjectType_BlueprintFolder, + IkarusObjectTypes_BlueprintFolder = 1 << IkarusObjectType_BlueprintFolder, /// \brief An IkarusPropertyFolder - ObjectTypes_PropertyFolder = 1 << ObjectType_PropertyFolder, + IkarusObjectTypes_PropertyFolder = 1 << IkarusObjectType_PropertyFolder, /// \brief An IkarusEntityFolder - ObjectTypes_EntityFolder = 1 << ObjectType_EntityFolder, + IkarusObjectTypes_EntityFolder = 1 << IkarusObjectType_EntityFolder, }; // @} diff --git a/src/types/id.cpp b/src/types/id.cpp new file mode 100644 index 0000000..53f2689 --- /dev/null +++ b/src/types/id.cpp @@ -0,0 +1,56 @@ +#include "ikarus/types/id.h" + +#include + +IkarusId ikarus_id_from_data(int64_t data) { + return IkarusId { + .data = data + }; +} + +IkarusObjectType ikarus_id_get_object_type(IkarusId id) { + return static_cast(id.data >> 56); +} + +bool ikarus_id_is_equal(IkarusId left, IkarusId right) { + return left.data == right.data; +} + +bool ikarus_id_is_none(IkarusId id) { + return ikarus_id_is_equal(id, IKARUS_ID_NONE); +} + +bool ikarus_id_is_unspecified(IkarusId id) { + return ikarus_id_is_equal(id, IKARUS_ID_UNSPECIFIED); +} + +TEST_CASE("id_object_type", "[id]") { + auto id = ikarus_id_from_data(static_cast(IkarusObjectType_Blueprint) << 56); + + REQUIRE(ikarus_id_get_object_type(id) == IkarusObjectType_Blueprint); + REQUIRE(!ikarus_id_is_none(id) == IkarusObjectType_Blueprint); + REQUIRE(!ikarus_id_is_unspecified(id) == IkarusObjectType_Blueprint); +} + +TEST_CASE("id_equal", "[id]") { + auto id = ikarus_id_from_data(static_cast(IkarusObjectType_Blueprint) << 56); + auto copy = id; + auto third = ikarus_id_from_data(static_cast(IkarusObjectType_Property) << 56); + + REQUIRE(ikarus_id_is_equal(id, copy)); + REQUIRE(!ikarus_id_is_equal(id, third)); +} + +TEST_CASE("id_none", "[id]") { + auto id = IKARUS_ID_NONE; + + REQUIRE(ikarus_id_is_none(id)); + REQUIRE(!ikarus_id_is_unspecified(id)); +} + +TEST_CASE("id_unspecified", "[id]") { + auto id = IKARUS_ID_UNSPECIFIED; + + REQUIRE(!ikarus_id_is_none(id)); + REQUIRE(ikarus_id_is_unspecified(id)); +}