Skip to content

Commit

Permalink
refactor(core): add ArrayTrait::{View, ConstView}
Browse files Browse the repository at this point in the history
  • Loading branch information
RiscadoA committed Sep 28, 2023
1 parent 70779c0 commit fa59f61
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 105 deletions.
131 changes: 87 additions & 44 deletions core/include/cubos/core/reflection/traits/array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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
7 changes: 4 additions & 3 deletions core/samples/reflection/traits/array/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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<const int*>(arrayTrait.get(instance, i)));
CUBOS_INFO("Element {}: {}", i, *static_cast<const int*>(arrayView.get(i)));
}
}
/// [Getting array elements]
Expand Down
97 changes: 53 additions & 44 deletions core/src/cubos/core/reflection/traits/array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void*>(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<const void*>(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<void*>(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<const void*>(mTrait.mAddressOf(mInstance, index));
}
28 changes: 14 additions & 14 deletions core/tests/reflection/traits/array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,51 +22,51 @@ void testArray(T& value, std::size_t length, E* inserted = nullptr)
REQUIRE(type.has<ArrayTrait>());
const ArrayTrait& trait = type.get<ArrayTrait>();

REQUIRE(trait.length(&value) == length);
REQUIRE(trait.view(&value).length() == length);
REQUIRE(trait.elementType().is<E>());

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<const void*>(&value)).length() == length + 2);
length += 2;

if constexpr (std::equality_comparable<E> && std::default_initializable<E>)
{
CHECK(*reinterpret_cast<E*>(trait.get(&value, 0)) == E{});
CHECK(*reinterpret_cast<const E*>(trait.get(static_cast<const void*>(&value), length - 1)) == E{});
CHECK(*reinterpret_cast<E*>(trait.view(&value).get(0)) == E{});
CHECK(*reinterpret_cast<const E*>(trait.view(static_cast<const void*>(&value)).get(length - 1)) == E{});
}
}

if (trait.hasErase())
{
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);
}
}

if (inserted)
{
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<E>)
{
CHECK(*reinterpret_cast<E*>(trait.get(&value, 0)) == *inserted);
CHECK(*reinterpret_cast<E*>(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;
}
}
Expand Down

0 comments on commit fa59f61

Please sign in to comment.