Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ArrayTrait #546

Merged
merged 14 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ set(CUBOS_CORE_SOURCE
"src/cubos/core/reflection/type.cpp"
"src/cubos/core/reflection/traits/constructible.cpp"
"src/cubos/core/reflection/traits/fields.cpp"
"src/cubos/core/reflection/traits/array.cpp"
"src/cubos/core/reflection/external/primitives.cpp"

"src/cubos/core/data/serializer.cpp"
Expand Down
59 changes: 59 additions & 0 deletions core/include/cubos/core/reflection/external/vector.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/// @file
/// @brief Reflection declaration for `std::vector`.
/// @ingroup core-reflection

#pragma once

#include <vector>

#include <cubos/core/reflection/traits/array.hpp>
#include <cubos/core/reflection/traits/constructible_utils.hpp>
#include <cubos/core/reflection/type.hpp>

CUBOS_REFLECT_EXTERNAL_TEMPLATE((typename T), (std::vector<T>))
{
// This is a bit scary but isn't doing anything too crazy.
// We are supplying, first, the element type, and then a getter for the length and another for
// the address of an element.

auto arrayTrait = ArrayTrait(
reflect<T>(),
[](const void* instance) -> std::size_t { return static_cast<const std::vector<T>*>(instance)->size(); },
[](const void* instance, std::size_t index) -> uintptr_t {
return reinterpret_cast<uintptr_t>(static_cast<const std::vector<T>*>(instance)->data() + index);
});

// We supply the insert functions depending on the constructibility of the element type.

if constexpr (std::is_default_constructible<T>::value)
{
arrayTrait.setInsertDefault([](void* instance, std::size_t index) {
auto* vec = static_cast<std::vector<T>*>(instance);
vec->emplace(vec->begin() + static_cast<std::ptrdiff_t>(index));
});
}

if constexpr (std::is_copy_constructible<T>::value)
{
arrayTrait.setInsertCopy([](void* instance, std::size_t index, const void* value) {
auto* vec = static_cast<std::vector<T>*>(instance);
vec->emplace(vec->begin() + static_cast<std::ptrdiff_t>(index), *static_cast<const T*>(value));
});
}

// Since T must be moveable for all std::vector<T>, we always supply this function.
arrayTrait.setInsertMove([](void* instance, std::size_t index, void* value) {
auto* vec = static_cast<std::vector<T>*>(instance);
vec->emplace(vec->begin() + static_cast<std::ptrdiff_t>(index), std::move(*static_cast<T*>(value)));
});

// We supply the erase function always, as it is always possible to erase an element of a vector.
arrayTrait.setErase([](void* instance, std::size_t index) {
auto* vec = static_cast<std::vector<T>*>(instance);
vec->erase(vec->begin() + static_cast<std::ptrdiff_t>(index));
});

return Type::create("std::vector<" + reflect<T>().name() + ">")
.with(arrayTrait)
.with(autoConstructibleTrait<std::vector<T>>());
}
279 changes: 279 additions & 0 deletions core/include/cubos/core/reflection/traits/array.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
/// @file
/// @brief Class @ref cubos::core::reflection::ArrayTrait.
/// @ingroup core-reflection

#pragma once

#include <cstddef>
#include <cstdint>

#include <cubos/core/reflection/reflect.hpp>

namespace cubos::core::reflection
{
/// @brief Exposes array-like functionality of a type.
/// @see See @ref examples-core-reflection-traits-array for an example of using this trait.
/// @ingroup 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);

/// @brief Function pointer to get the address of an element in an array instance.
/// @param instance Pointer to the instance.
/// @param index Element index.
using AddressOf = uintptr_t (*)(const void* instance, std::size_t index);

/// @brief Function pointer to insert a default value into the array.
/// @param instance Pointer to the instance.
/// @param index Element index.
using InsertDefault = void (*)(void* instance, std::size_t index);

/// @brief Function pointer to insert a copy of the given value into the array.
/// @param instance Pointer to the instance.
/// @param index Element index.
/// @param value Value.
using InsertCopy = void (*)(void* instance, std::size_t index, const void* value);

/// @brief Function pointer to move the given value into the array.
/// @param instance Pointer to the instance.
/// @param index Element index.
/// @param value Value.
using InsertMove = void (*)(void* instance, std::size_t index, void* value);

/// @brief Function pointer to remove an element of the array.
/// @param instance Pointer to the instance.
/// @param index Element index.
using Erase = void (*)(void* instance, std::size_t index);

/// @brief Constructs.
/// @param elementType Element type of the array.
/// @param length Function used to get the length of an array.
/// @param addressOf Function used to address an element in an array.
ArrayTrait(const Type& elementType, Length length, AddressOf addressOf);

/// @brief Sets the default-construct insert operation to the trait.
/// @param insertDefault Function pointer.
void setInsertDefault(InsertDefault insertDefault);

/// @brief Sets the copy-construct insert operation to the trait.
/// @param insertCopy Function pointer.
void setInsertCopy(InsertCopy insertCopy);

/// @brief Sets the move-construct insert operation to the trait.
/// @param insertMove Function pointer.
void setInsertMove(InsertMove insertMove);

/// @brief Sets the erase operation to the trait.
/// @param erase Function pointer.
void setErase(Erase erase);

/// @brief Checks if default-construct insert is supported.
/// @return Whether the operation is supported.
bool hasInsertDefault() const;

/// @brief Checks if copy-construct insert is supported.
/// @return Whether the operation is supported.
bool hasInsertCopy() const;

/// @brief Checks if move-construct insert is supported.
/// @return Whether the operation is supported.
bool hasInsertMove() const;

/// @brief Checks if erase is supported.
/// @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;
InsertDefault mInsertDefault{nullptr};
InsertCopy mInsertCopy{nullptr};
InsertMove mInsertMove{nullptr};
Erase mErase{nullptr};
};

class ArrayTrait::View final
{
public:
/// @brief Used to iterate over the elements of an array.
class Iterator;

/// @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;

/// @brief Gets an iterator to the first element.
/// @return Iterator.
Iterator begin() const;

/// @brief Gets an iterator to the element after the last element.
/// @return Iterator.
Iterator end() const;

private:
const ArrayTrait& mTrait;
void* mInstance;
};

class ArrayTrait::ConstView final
{
public:
/// @brief Used to iterate over the elements of an array.
class Iterator;

/// @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;

/// @brief Gets an iterator to the first element.
/// @return Iterator.
Iterator begin() const;

/// @brief Gets an iterator to the element after the last element.
/// @return Iterator.
Iterator end() const;

private:
const ArrayTrait& mTrait;
const void* mInstance;
};

class ArrayTrait::View::Iterator final
{
public:
/// @brief Constructs.
/// @param view Array view.
/// @param index Element index.
Iterator(const View& view, std::size_t index);

/// @brief Copy constructs.
/// @param iterator Iterator.
Iterator(const Iterator& iterator) = default;

Iterator& operator=(const Iterator&) = default;
bool operator==(const Iterator&) const = default;
bool operator!=(const Iterator&) const = default;

/// @brief Accesses the element referenced by this iterator.
/// @note Aborts if out of bounds.
/// @return Element.
void* operator*() const;

/// @brief Accesses the element referenced by this iterator.
/// @note Aborts if out of bounds.
/// @return Element.
void* operator->() const;

/// @brief Advances the iterator.
/// @note Aborts if out of bounds.
/// @return Reference to this.
Iterator& operator++();

private:
const View* mView;
std::size_t mIndex;
};

class ArrayTrait::ConstView::Iterator final
{
public:
/// @brief Constructs.
/// @param view Array view.
/// @param index Element index.
Iterator(const ConstView& view, std::size_t index);

/// @brief Copy constructs.
/// @param iterator Iterator.
Iterator(const Iterator& iterator) = default;

Iterator& operator=(const Iterator&) = default;
bool operator==(const Iterator&) const = default;
bool operator!=(const Iterator&) const = default;

/// @brief Accesses the element referenced by this iterator.
/// @note Aborts if out of bounds.
/// @return Element.
const void* operator*() const;

/// @brief Accesses the element referenced by this iterator.
/// @note Aborts if out of bounds.
/// @return Element.
const void* operator->() const;

/// @brief Advances the iterator.
/// @note Aborts if out of bounds.
/// @return Reference to this.
Iterator& operator++();

private:
const ConstView* mView;
std::size_t mIndex;
};
} // namespace cubos::core::reflection
1 change: 1 addition & 0 deletions core/samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ make_sample(DIR "logging")
make_sample(DIR "reflection/basic")
make_sample(DIR "reflection/traits/constructible")
make_sample(DIR "reflection/traits/fields")
make_sample(DIR "reflection/traits/array")
make_sample(DIR "data/fs/embedded_archive" SOURCES "embed.cpp")
make_sample(DIR "data/fs/standard_archive")
make_sample(DIR "data/serialization")
Expand Down
1 change: 1 addition & 0 deletions core/samples/reflection/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
- @subpage examples-core-reflection-basic - @copybrief examples-core-reflection-basic
- @subpage examples-core-reflection-traits-constructible - @copybrief examples-core-reflection-traits-constructible
- @subpage examples-core-reflection-traits-fields - @copybrief examples-core-reflection-traits-fields
- @subpage examples-core-reflection-traits-array - @copybrief examples-core-reflection-traits-array
Loading
Loading