view: shared implementation for storage views
This commit is contained in:
@@ -570,98 +570,31 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Storage view specialization.
|
||||
*
|
||||
* This specialization offers a boost in terms of performance. It can access the
|
||||
* underlying data structure directly and avoid superfluous checks.
|
||||
*
|
||||
* @sa basic_view
|
||||
*
|
||||
* @tparam Get Type of storage iterated by the view.
|
||||
* @brief Basic storage view implementation.
|
||||
* @warning For internal use only, backward compatibility not guaranteed.
|
||||
* @tparam Type Common type among all storage types.
|
||||
*/
|
||||
template<typename Get>
|
||||
class basic_view<get_t<Get>, exclude_t<>, std::void_t<std::enable_if_t<!Get::traits_type::in_place_delete>>> {
|
||||
public:
|
||||
template<typename Type>
|
||||
struct basic_storage_view {
|
||||
/*! @brief Common type among all storage types. */
|
||||
using common_type = typename Get::base_type;
|
||||
using common_type = Type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename Get::entity_type;
|
||||
using entity_type = typename common_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = typename common_type::iterator;
|
||||
/*! @brief Reversed iterator type. */
|
||||
using reverse_iterator = typename common_type::reverse_iterator;
|
||||
/*! @brief Iterable view type. */
|
||||
using iterable = decltype(std::declval<Get>().each());
|
||||
|
||||
/*! @brief Default constructor to use to create empty, invalid views. */
|
||||
basic_view() noexcept
|
||||
: view{} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a view from a storage class.
|
||||
* @param value The storage for the type to iterate.
|
||||
*/
|
||||
basic_view(Get &value) noexcept
|
||||
: view{&value} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a view from a storage class.
|
||||
* @param value The storage for the type to iterate.
|
||||
*/
|
||||
basic_view(std::tuple<Get &> value, std::tuple<> = {}) noexcept
|
||||
: basic_view{std::get<0>(value)} {}
|
||||
|
||||
/**
|
||||
* @brief Returns the leading storage of a view, if any.
|
||||
* @return The leading storage of the view.
|
||||
*/
|
||||
[[nodiscard]] const common_type *handle() const noexcept {
|
||||
return storage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the storage for a given component type, if any.
|
||||
* @tparam Type Type of component of which to return the storage.
|
||||
* @return The storage for the given component type.
|
||||
*/
|
||||
template<typename Type = typename Get::value_type>
|
||||
[[nodiscard]] auto *storage() const noexcept {
|
||||
static_assert(std::is_same_v<std::remove_const_t<Type>, typename Get::value_type>, "Invalid component type");
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the storage for a given index, if any.
|
||||
* @tparam Index Index of the storage to return.
|
||||
* @return The storage for the given index.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
[[nodiscard]] auto *storage() const noexcept {
|
||||
static_assert(Index == 0u, "Index out of bounds");
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a storage to a view.
|
||||
* @param elem A storage to assign to the view.
|
||||
*/
|
||||
void storage(Get &elem) noexcept {
|
||||
view = &elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a storage to a view.
|
||||
* @tparam Index Index of the storage to assign to the view.
|
||||
* @param elem A storage to assign to the view.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
void storage(Get &elem) noexcept {
|
||||
static_assert(Index == 0u, "Index out of bounds");
|
||||
view = &elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of entities that have the given component.
|
||||
* @return Number of entities that have the given component.
|
||||
@@ -686,7 +619,7 @@ public:
|
||||
* @return An iterator to the first entity of the view.
|
||||
*/
|
||||
[[nodiscard]] iterator begin() const noexcept {
|
||||
return view ? view->common_type::begin() : iterator{};
|
||||
return view ? view->begin() : iterator{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -694,7 +627,7 @@ public:
|
||||
* @return An iterator to the entity following the last entity of the view.
|
||||
*/
|
||||
[[nodiscard]] iterator end() const noexcept {
|
||||
return view ? view->common_type::end() : iterator{};
|
||||
return view ? view->end() : iterator{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -705,7 +638,7 @@ public:
|
||||
* @return An iterator to the first entity of the reversed view.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterator rbegin() const noexcept {
|
||||
return view ? view->common_type::rbegin() : reverse_iterator{};
|
||||
return view ? view->rbegin() : reverse_iterator{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -715,7 +648,7 @@ public:
|
||||
* reversed view.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterator rend() const noexcept {
|
||||
return view ? view->common_type::rend() : reverse_iterator{};
|
||||
return view ? view->rend() : reverse_iterator{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -724,7 +657,7 @@ public:
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] entity_type front() const noexcept {
|
||||
return empty() ? null : *view->common_type::begin();
|
||||
return empty() ? null : *view->begin();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -733,7 +666,7 @@ public:
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] entity_type back() const noexcept {
|
||||
return empty() ? null : *view->common_type::rbegin();
|
||||
return empty() ? null : *view->rbegin();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -755,15 +688,6 @@ public:
|
||||
return begin()[pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the component assigned to the given entity.
|
||||
* @param entt A valid identifier.
|
||||
* @return The component assigned to the given entity.
|
||||
*/
|
||||
[[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
|
||||
return storage()->get(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a view is fully initialized.
|
||||
* @return True if the view is fully initialized, false otherwise.
|
||||
@@ -781,6 +705,117 @@ public:
|
||||
return view && view->contains(entt);
|
||||
}
|
||||
|
||||
protected:
|
||||
const common_type *view{};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Storage view specialization.
|
||||
*
|
||||
* This specialization offers a boost in terms of performance. It can access the
|
||||
* underlying data structure directly and avoid superfluous checks.
|
||||
*
|
||||
* @sa basic_view
|
||||
*
|
||||
* @tparam Get Type of storage iterated by the view.
|
||||
*/
|
||||
template<typename Get>
|
||||
class basic_view<get_t<Get>, exclude_t<>, std::void_t<std::enable_if_t<!Get::traits_type::in_place_delete>>>: public basic_storage_view<typename Get::base_type> {
|
||||
using base_type = basic_storage_view<typename Get::base_type>;
|
||||
|
||||
public:
|
||||
/*! @brief Common type among all storage types. */
|
||||
using common_type = typename base_type::common_type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename base_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename base_type::size_type;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = typename base_type::iterator;
|
||||
/*! @brief Reversed iterator type. */
|
||||
using reverse_iterator = typename base_type::reverse_iterator;
|
||||
/*! @brief Iterable view type. */
|
||||
using iterable = decltype(std::declval<Get>().each());
|
||||
|
||||
/*! @brief Default constructor to use to create empty, invalid views. */
|
||||
basic_view() noexcept
|
||||
: base_type{} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a view from a storage class.
|
||||
* @param value The storage for the type to iterate.
|
||||
*/
|
||||
basic_view(Get &value) noexcept
|
||||
: basic_view{} {
|
||||
this->view = &value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a view from a storage class.
|
||||
* @param value The storage for the type to iterate.
|
||||
*/
|
||||
basic_view(std::tuple<Get &> value, std::tuple<> = {}) noexcept
|
||||
: basic_view{std::get<0>(value)} {}
|
||||
|
||||
/**
|
||||
* @brief Returns the storage for a given component type, if any.
|
||||
* @tparam Type Type of component of which to return the storage.
|
||||
* @return The storage for the given component type.
|
||||
*/
|
||||
template<typename Type = typename Get::value_type>
|
||||
[[nodiscard]] auto *storage() const noexcept {
|
||||
static_assert(std::is_same_v<std::remove_const_t<Type>, typename Get::value_type>, "Invalid component type");
|
||||
return storage<0>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the storage for a given index, if any.
|
||||
* @tparam Index Index of the storage to return.
|
||||
* @return The storage for the given index.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
[[nodiscard]] auto *storage() const noexcept {
|
||||
static_assert(Index == 0u, "Index out of bounds");
|
||||
return static_cast<Get *>(const_cast<constness_as_t<common_type, Get> *>(this->view));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a storage to a view.
|
||||
* @param elem A storage to assign to the view.
|
||||
*/
|
||||
void storage(Get &elem) noexcept {
|
||||
this->view = &elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a storage to a view.
|
||||
* @tparam Index Index of the storage to assign to the view.
|
||||
* @param elem A storage to assign to the view.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
void storage(Get &elem) noexcept {
|
||||
static_assert(Index == 0u, "Index out of bounds");
|
||||
this->view = &elem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the component assigned to the given entity.
|
||||
* @param entt A valid identifier.
|
||||
* @return The component assigned to the given entity.
|
||||
*/
|
||||
[[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
|
||||
return storage()->get(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the identifier that occupies the given position.
|
||||
* @param pos Position of the element to return.
|
||||
* @return The identifier that occupies the given position.
|
||||
*/
|
||||
[[nodiscard]] entity_type operator[](const size_type pos) const {
|
||||
return this->base_type::operator[](pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the component assigned to the given entity.
|
||||
* @tparam Elem Type of the component to get.
|
||||
@@ -825,17 +860,17 @@ public:
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
if(view) {
|
||||
if constexpr(is_applicable_v<Func, decltype(*view->each().begin())>) {
|
||||
for(const auto pack: view->each()) {
|
||||
if(auto *elem = storage(); elem) {
|
||||
if constexpr(is_applicable_v<Func, decltype(*elem->each().begin())>) {
|
||||
for(const auto pack: elem->each()) {
|
||||
std::apply(func, pack);
|
||||
}
|
||||
} else if constexpr(std::is_invocable_v<Func, decltype(*view->begin())>) {
|
||||
for(auto &&component: *view) {
|
||||
} else if constexpr(std::is_invocable_v<Func, decltype(*elem->begin())>) {
|
||||
for(auto &&component: *elem) {
|
||||
func(component);
|
||||
}
|
||||
} else {
|
||||
for(size_type pos = view->size(); pos; --pos) {
|
||||
for(size_type pos = elem->size(); pos; --pos) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
@@ -852,7 +887,7 @@ public:
|
||||
* @return An iterable object to use to _visit_ the view.
|
||||
*/
|
||||
[[nodiscard]] iterable each() const noexcept {
|
||||
return storage() ? storage()->each() : iterable{};
|
||||
return this->view ? storage()->each() : iterable{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -867,9 +902,6 @@ public:
|
||||
return internal::view_pack<basic_view<get_t<Get, OGet...>, exclude_t<OExclude...>>>(
|
||||
*this, other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
|
||||
}
|
||||
|
||||
private:
|
||||
Get *view;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user