From fa59f6101e45b0af4bc6f54e3fb60f416f7ab9f4 Mon Sep 17 00:00:00 2001 From: Ricardo Antunes Date: Thu, 28 Sep 2023 08:30:16 +0100 Subject: [PATCH] refactor(core): add ArrayTrait::{View, ConstView} --- .../cubos/core/reflection/traits/array.hpp | 131 ++++++++++++------ core/samples/reflection/traits/array/main.cpp | 7 +- .../cubos/core/reflection/traits/array.cpp | 97 +++++++------ core/tests/reflection/traits/array.hpp | 28 ++-- 4 files changed, 158 insertions(+), 105 deletions(-) diff --git a/core/include/cubos/core/reflection/traits/array.hpp b/core/include/cubos/core/reflection/traits/array.hpp index 082042fa4..aaf70a1bc 100644 --- a/core/include/cubos/core/reflection/traits/array.hpp +++ b/core/include/cubos/core/reflection/traits/array.hpp @@ -17,6 +17,12 @@ namespace cubos::core::reflection class ArrayTrait final { public: + /// @brief Provides mutable access to an array. + class View; + + /// @brief Provides immutable access to an array. + class ConstView; + /// @brief Function pointer to get the length of an array instance. /// @param instance Pointer to the instance. using Length = std::size_t (*)(const void* instance); @@ -70,50 +76,6 @@ namespace cubos::core::reflection /// @param erase Function pointer. void setErase(Erase erase); - /// @brief Returns the element type of the array. - /// @return Element type. - const Type& elementType() const; - - /// @brief Returns the length of the given array. - /// @param instance Pointer to the array instance. - /// @return Array length. - std::size_t length(const void* instance) const; - - /// @brief Gets a pointer to the element with the given index on the given array. - /// @param instance Pointer to the array instance. - /// @param index Element index. - /// @return Pointer to the element. - void* get(void* instance, std::size_t index) const; - - /// @copydoc get(void*, std::size_t) const - const void* get(const void* instance, std::size_t index) const; - - /// @brief Inserts a default-constructed element into the array. - /// @param instance Pointer to the array instance. - /// @param index Element index. - /// @return Whether the operation is supported. - bool insertDefault(void* instance, std::size_t index) const; - - /// @brief Inserts a copy-constructed element into the array. - /// @param instance Pointer to the array instance. - /// @param index Element index. - /// @param value Value. - /// @return Whether the operation is supported. - bool insertCopy(void* instance, std::size_t index, const void* value) const; - - /// @brief Inserts a move-constructed element into the array. - /// @param instance Pointer to the array instance. - /// @param index Element index. - /// @param value Value. - /// @return Whether the operation is supported. - bool insertMove(void* instance, std::size_t index, void* value) const; - - /// @brief Removes an element of the array. - /// @param instance Pointer to the array instance. - /// @param index Element index. - /// @return Whether the operation is supported. - bool erase(void* instance, std::size_t index) const; - /// @brief Checks if default-construct insert is supported. /// @return Whether the operation is supported. bool hasInsertDefault() const; @@ -130,7 +92,22 @@ namespace cubos::core::reflection /// @return Whether the operation is supported. bool hasErase() const; + /// @brief Returns the element type of the array. + /// @return Element type. + const Type& elementType() const; + + /// @brief Returns a view of the given array instance. + /// @param instance Array instance. + /// @return Array view. + View view(void* instance) const; + + /// @copydoc view(void*) const + ConstView view(const void* instance) const; + private: + friend View; + friend ConstView; + const Type& mElementType; Length mLength; AddressOf mAddressOf; @@ -139,4 +116,70 @@ namespace cubos::core::reflection InsertMove mInsertMove{nullptr}; Erase mErase{nullptr}; }; + + class ArrayTrait::View final + { + public: + /// @brief Constructs. + /// @param trait Trait. + /// @param instance Instance. + View(const ArrayTrait& trait, void* instance); + + /// @brief Returns the length of the array. + /// @return Array length. + std::size_t length() const; + + /// @brief Gets a pointer to the element with the given index. + /// @param index Element index. + /// @return Pointer to the element. + void* get(std::size_t index) const; + + /// @brief Inserts a default-constructed element. + /// @note Aborts if @ref ArrayTrait::hasInsertDefault() returns false. + /// @param index Element index. + void insertDefault(std::size_t index) const; + + /// @brief Inserts a copy-constructed element. + /// @note Aborts if @ref ArrayTrait::hasInsertCopy() returns false. + /// @param index Element index. + /// @param value Value. + void insertCopy(std::size_t index, const void* value) const; + + /// @brief Inserts a move-constructed element. + /// @note Aborts if @ref ArrayTrait::hasInsertMove() returns false. + /// @param index Element index. + /// @param value Value. + void insertMove(std::size_t index, void* value) const; + + /// @brief Removes an element. + /// @note Aborts if @ref ArrayTrait::hasErase() returns false. + /// @param index Element index. + void erase(std::size_t index) const; + + private: + const ArrayTrait& mTrait; + void* mInstance; + }; + + class ArrayTrait::ConstView final + { + public: + /// @brief Constructs. + /// @param trait Trait. + /// @param instance Instance. + ConstView(const ArrayTrait& trait, const void* instance); + + /// @brief Returns the length of the array. + /// @return Array length. + std::size_t length() const; + + /// @brief Gets a pointer to the element with the given index. + /// @param index Element index. + /// @return Pointer to the element. + const void* get(std::size_t index) const; + + private: + const ArrayTrait& mTrait; + const void* mInstance; + }; } // namespace cubos::core::reflection diff --git a/core/samples/reflection/traits/array/main.cpp b/core/samples/reflection/traits/array/main.cpp index 8ed3a57f2..d01bd3ca5 100644 --- a/core/samples/reflection/traits/array/main.cpp +++ b/core/samples/reflection/traits/array/main.cpp @@ -13,7 +13,8 @@ void printArray(const Type& type, const void* instance) /// [Printing any array] /// [Getting array length and type] - CUBOS_INFO("Array with {} elements of type {}", arrayTrait.length(instance), arrayTrait.elementType().name()); + auto arrayView = arrayTrait.view(instance); + CUBOS_INFO("Array with {} elements of type {}", arrayView.length(), arrayTrait.elementType().name()); /// [Getting array length and type] /// [Getting array elements] @@ -23,9 +24,9 @@ void printArray(const Type& type, const void* instance) return; } - for (std::size_t i = 0; i < arrayTrait.length(instance); ++i) + for (std::size_t i = 0; i < arrayView.length(); ++i) { - CUBOS_INFO("Element {}: {}", i, *static_cast(arrayTrait.get(instance, i))); + CUBOS_INFO("Element {}: {}", i, *static_cast(arrayView.get(i))); } } /// [Getting array elements] diff --git a/core/src/cubos/core/reflection/traits/array.cpp b/core/src/cubos/core/reflection/traits/array.cpp index 96ec2aaca..6001de94e 100644 --- a/core/src/cubos/core/reflection/traits/array.cpp +++ b/core/src/cubos/core/reflection/traits/array.cpp @@ -35,86 +35,95 @@ void ArrayTrait::setErase(Erase erase) mErase = erase; } -const Type& ArrayTrait::elementType() const +bool ArrayTrait::hasInsertDefault() const { - return mElementType; + return mInsertDefault != nullptr; } -std::size_t ArrayTrait::length(const void* instance) const +bool ArrayTrait::hasInsertCopy() const { - return mLength(instance); + return mInsertCopy != nullptr; } -void* ArrayTrait::get(void* instance, std::size_t index) const +bool ArrayTrait::hasInsertMove() const { - return reinterpret_cast(mAddressOf(instance, index)); + return mInsertMove != nullptr; } -const void* ArrayTrait::get(const void* instance, std::size_t index) const +bool ArrayTrait::hasErase() const { - return reinterpret_cast(mAddressOf(instance, index)); + return mErase != nullptr; } -bool ArrayTrait::insertDefault(void* instance, std::size_t index) const +const Type& ArrayTrait::elementType() const { - if (mInsertDefault != nullptr) - { - mInsertDefault(instance, index); - return true; - } + return mElementType; +} - return false; +ArrayTrait::View ArrayTrait::view(void* instance) const +{ + return View{*this, instance}; } -bool ArrayTrait::insertCopy(void* instance, std::size_t index, const void* value) const +ArrayTrait::ConstView ArrayTrait::view(const void* instance) const { - if (mInsertCopy != nullptr) - { - mInsertCopy(instance, index, value); - return true; - } + return ConstView{*this, instance}; +} - return false; +ArrayTrait::View::View(const ArrayTrait& trait, void* instance) + : mTrait(trait) + , mInstance(instance) +{ + CUBOS_ASSERT(mInstance != nullptr, "Instance must not be null"); } -bool ArrayTrait::insertMove(void* instance, std::size_t index, void* value) const +std::size_t ArrayTrait::View::length() const { - if (mInsertMove != nullptr) - { - mInsertMove(instance, index, value); - return true; - } + return mTrait.mLength(mInstance); +} - return false; +void* ArrayTrait::View::get(std::size_t index) const +{ + return reinterpret_cast(mTrait.mAddressOf(mInstance, index)); } -bool ArrayTrait::erase(void* instance, std::size_t index) const +void ArrayTrait::View::insertDefault(std::size_t index) const { - if (mErase != nullptr) - { - mErase(instance, index); - return true; - } + CUBOS_ASSERT(mTrait.hasInsertDefault(), "Insert default not supported"); + mTrait.mInsertDefault(mInstance, index); +} - return false; +void ArrayTrait::View::insertCopy(std::size_t index, const void* value) const +{ + CUBOS_ASSERT(mTrait.hasInsertCopy(), "Insert copy not supported"); + mTrait.mInsertCopy(mInstance, index, value); } -bool ArrayTrait::hasInsertDefault() const +void ArrayTrait::View::insertMove(std::size_t index, void* value) const { - return mInsertDefault != nullptr; + CUBOS_ASSERT(mTrait.hasInsertMove(), "Insert move not supported"); + mTrait.mInsertMove(mInstance, index, value); } -bool ArrayTrait::hasInsertCopy() const +void ArrayTrait::View::erase(std::size_t index) const { - return mInsertCopy != nullptr; + CUBOS_ASSERT(mTrait.hasErase(), "Erase not supported"); + mTrait.mErase(mInstance, index); } -bool ArrayTrait::hasInsertMove() const +ArrayTrait::ConstView::ConstView(const ArrayTrait& trait, const void* instance) + : mTrait(trait) + , mInstance(instance) { - return mInsertMove != nullptr; + CUBOS_ASSERT(mInstance != nullptr, "Instance must not be null"); } -bool ArrayTrait::hasErase() const +std::size_t ArrayTrait::ConstView::length() const { - return mErase != nullptr; + return mTrait.mLength(mInstance); +} + +const void* ArrayTrait::ConstView::get(std::size_t index) const +{ + return reinterpret_cast(mTrait.mAddressOf(mInstance, index)); } diff --git a/core/tests/reflection/traits/array.hpp b/core/tests/reflection/traits/array.hpp index 173ac5199..25c50fdfe 100644 --- a/core/tests/reflection/traits/array.hpp +++ b/core/tests/reflection/traits/array.hpp @@ -22,21 +22,21 @@ void testArray(T& value, std::size_t length, E* inserted = nullptr) REQUIRE(type.has()); const ArrayTrait& trait = type.get(); - REQUIRE(trait.length(&value) == length); + REQUIRE(trait.view(&value).length() == length); REQUIRE(trait.elementType().is()); if (trait.hasInsertDefault()) { - trait.insertDefault(&value, length); - CHECK(trait.length(&value) == length + 1); - trait.insertDefault(&value, 0); - CHECK(trait.length(&value) == length + 2); + trait.view(&value).insertDefault(length); + CHECK(trait.view(&value).length() == length + 1); + trait.view(&value).insertDefault(0); + CHECK(trait.view(static_cast(&value)).length() == length + 2); length += 2; if constexpr (std::equality_comparable && std::default_initializable) { - CHECK(*reinterpret_cast(trait.get(&value, 0)) == E{}); - CHECK(*reinterpret_cast(trait.get(static_cast(&value), length - 1)) == E{}); + CHECK(*reinterpret_cast(trait.view(&value).get(0)) == E{}); + CHECK(*reinterpret_cast(trait.view(static_cast(&value)).get(length - 1)) == E{}); } } @@ -44,8 +44,8 @@ void testArray(T& value, std::size_t length, E* inserted = nullptr) { for (; length > 0; --length) { - trait.erase(&value, length - 1); - CHECK(trait.length(&value) == length - 1); + trait.view(&value).erase(length - 1); + CHECK(trait.view(&value).length() == length - 1); } } @@ -53,20 +53,20 @@ void testArray(T& value, std::size_t length, E* inserted = nullptr) { if (trait.hasInsertCopy()) { - trait.insertCopy(&value, 0, inserted); - CHECK(trait.length(&value) == length + 1); + trait.view(&value).insertCopy(0, inserted); + CHECK(trait.view(&value).length() == length + 1); length += 1; if constexpr (std::equality_comparable) { - CHECK(*reinterpret_cast(trait.get(&value, 0)) == *inserted); + CHECK(*reinterpret_cast(trait.view(&value).get(0)) == *inserted); } } if (trait.hasInsertMove()) { - trait.insertMove(&value, (length + 1) / 2, inserted); - CHECK(trait.length(&value) == length + 1); + trait.view(&value).insertMove((length + 1) / 2, inserted); + CHECK(trait.view(&value).length() == length + 1); length += 1; } }