review: iterators (sparse set/view)
This commit is contained in:
3
TODO
3
TODO
@@ -10,4 +10,7 @@
|
||||
* improve CMake interface, see mail from Malte
|
||||
* is registry/utility.hpp really required?
|
||||
* "singleton mode" for tags (see #66)
|
||||
* add a shortcut to destroy all the entities that have components X, Y, Z (view and registry?)
|
||||
* add operator[] to views if possible
|
||||
* C++17. That's all.
|
||||
* AOB
|
||||
|
||||
@@ -32,6 +32,8 @@ struct entt_traits<std::uint16_t> {
|
||||
using entity_type = std::uint16_t;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = std::uint8_t;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::int32_t;
|
||||
|
||||
/*! @brief Mask to use to get the entity number out of an identifier. */
|
||||
static constexpr auto entity_mask = 0xFFF;
|
||||
@@ -56,6 +58,8 @@ struct entt_traits<std::uint32_t> {
|
||||
using entity_type = std::uint32_t;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = std::uint16_t;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::int64_t;
|
||||
|
||||
/*! @brief Mask to use to get the entity number out of an identifier. */
|
||||
static constexpr auto entity_mask = 0xFFFFF;
|
||||
@@ -71,8 +75,8 @@ struct entt_traits<std::uint32_t> {
|
||||
*
|
||||
* A 64 bits entity identifier guarantees:
|
||||
*
|
||||
* * 40 bits for the entity number (an indecently large number).
|
||||
* * 24 bit for the version (an indecently large number).
|
||||
* * 32 bits for the entity number (an indecently large number).
|
||||
* * 32 bit for the version (an indecently large number).
|
||||
*/
|
||||
template<>
|
||||
struct entt_traits<std::uint64_t> {
|
||||
@@ -80,13 +84,15 @@ struct entt_traits<std::uint64_t> {
|
||||
using entity_type = std::uint64_t;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = std::uint32_t;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::int64_t;
|
||||
|
||||
/*! @brief Mask to use to get the entity number out of an identifier. */
|
||||
static constexpr auto entity_mask = 0xFFFFFFFFFF;
|
||||
static constexpr auto entity_mask = 0xFFFFFFFF;
|
||||
/*! @brief Mask to use to get the version out of an identifier. */
|
||||
static constexpr auto version_mask = 0xFFFFFF;
|
||||
static constexpr auto version_mask = 0xFFFFFFFF;
|
||||
/*! @brief Extent of the entity number within an identifier. */
|
||||
static constexpr auto entity_shift = 40;
|
||||
static constexpr auto entity_shift = 32;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -59,17 +59,34 @@ template<typename Entity>
|
||||
class SparseSet<Entity> {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
|
||||
struct Iterator final {
|
||||
using difference_type = std::size_t;
|
||||
using value_type = Entity;
|
||||
using pointer = const value_type *;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
class Iterator final {
|
||||
friend class SparseSet<Entity>;
|
||||
|
||||
Iterator(pointer direct, std::size_t pos)
|
||||
using entity_type = Entity;
|
||||
using pos_type = typename traits_type::difference_type;
|
||||
|
||||
Iterator(const entity_type *direct, pos_type pos) ENTT_NOEXCEPT
|
||||
: direct{direct}, pos{pos}
|
||||
{}
|
||||
|
||||
public:
|
||||
using difference_type = pos_type;
|
||||
using value_type = const entity_type;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
Iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
Iterator(const Iterator &) ENTT_NOEXCEPT = default;
|
||||
Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default;
|
||||
|
||||
friend void swap(Iterator &lhs, Iterator &rhs) ENTT_NOEXCEPT {
|
||||
using std::swap;
|
||||
swap(lhs.direct, rhs.direct);
|
||||
swap(lhs.pos, rhs.pos);
|
||||
}
|
||||
|
||||
Iterator & operator++() ENTT_NOEXCEPT {
|
||||
return --pos, *this;
|
||||
}
|
||||
@@ -79,6 +96,15 @@ class SparseSet<Entity> {
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
Iterator & operator--() ENTT_NOEXCEPT {
|
||||
return ++pos, *this;
|
||||
}
|
||||
|
||||
Iterator operator--(int) ENTT_NOEXCEPT {
|
||||
Iterator orig = *this;
|
||||
return --(*this), orig;
|
||||
}
|
||||
|
||||
Iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
|
||||
pos -= value;
|
||||
return *this;
|
||||
@@ -88,6 +114,22 @@ class SparseSet<Entity> {
|
||||
return Iterator{direct, pos-value};
|
||||
}
|
||||
|
||||
inline Iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
|
||||
return (*this += -value);
|
||||
}
|
||||
|
||||
inline Iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
|
||||
return (*this + -value);
|
||||
}
|
||||
|
||||
difference_type operator-(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.pos - pos;
|
||||
}
|
||||
|
||||
reference operator[](const difference_type value) const ENTT_NOEXCEPT {
|
||||
return direct[pos-value-1];
|
||||
}
|
||||
|
||||
bool operator==(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.pos == pos;
|
||||
}
|
||||
@@ -96,13 +138,33 @@ class SparseSet<Entity> {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference operator*() const ENTT_NOEXCEPT {
|
||||
return direct[pos-1];
|
||||
bool operator<(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return pos > other.pos;
|
||||
}
|
||||
|
||||
bool operator>(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return pos < other.pos;
|
||||
}
|
||||
|
||||
inline bool operator<=(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this > other);
|
||||
}
|
||||
|
||||
inline bool operator>=(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
pointer operator->() const ENTT_NOEXCEPT {
|
||||
return (direct+pos-1);
|
||||
}
|
||||
|
||||
inline reference operator*() const ENTT_NOEXCEPT {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
pointer direct;
|
||||
std::size_t pos;
|
||||
pos_type pos;
|
||||
};
|
||||
|
||||
static constexpr auto pending = ~typename traits_type::entity_type{};
|
||||
@@ -215,7 +277,8 @@ public:
|
||||
* @return An iterator to the first entity of the internal packed array.
|
||||
*/
|
||||
const_iterator_type cbegin() const ENTT_NOEXCEPT {
|
||||
return const_iterator_type{direct.data(), direct.size()};
|
||||
const typename traits_type::difference_type pos = direct.size();
|
||||
return const_iterator_type{direct.data(), pos};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -500,19 +563,37 @@ private:
|
||||
template<typename Entity, typename Type>
|
||||
class SparseSet<Entity, Type>: public SparseSet<Entity> {
|
||||
using underlying_type = SparseSet<Entity>;
|
||||
using traits_type = entt_traits<Entity>;
|
||||
|
||||
template<bool Const>
|
||||
struct Iterator final {
|
||||
using difference_type = std::size_t;
|
||||
using value_type = std::conditional_t<Const, const Type, Type>;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
class Iterator final {
|
||||
friend class SparseSet<Entity, Type>;
|
||||
|
||||
Iterator(pointer instances, std::size_t pos)
|
||||
using instance_type = std::conditional_t<Const, const Type, Type>;
|
||||
using pos_type = typename traits_type::difference_type;
|
||||
|
||||
Iterator(instance_type *instances, pos_type pos) ENTT_NOEXCEPT
|
||||
: instances{instances}, pos{pos}
|
||||
{}
|
||||
|
||||
public:
|
||||
using difference_type = pos_type;
|
||||
using value_type = instance_type;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
Iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
Iterator(const Iterator &) ENTT_NOEXCEPT = default;
|
||||
Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default;
|
||||
|
||||
friend void swap(Iterator &lhs, Iterator &rhs) ENTT_NOEXCEPT {
|
||||
using std::swap;
|
||||
swap(lhs.instances, rhs.instances);
|
||||
swap(lhs.pos, rhs.pos);
|
||||
}
|
||||
|
||||
Iterator & operator++() ENTT_NOEXCEPT {
|
||||
return --pos, *this;
|
||||
}
|
||||
@@ -522,6 +603,15 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
Iterator & operator--() ENTT_NOEXCEPT {
|
||||
return ++pos, *this;
|
||||
}
|
||||
|
||||
Iterator operator--(int) ENTT_NOEXCEPT {
|
||||
Iterator orig = *this;
|
||||
return --(*this), orig;
|
||||
}
|
||||
|
||||
Iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
|
||||
pos -= value;
|
||||
return *this;
|
||||
@@ -531,6 +621,22 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
|
||||
return Iterator{instances, pos-value};
|
||||
}
|
||||
|
||||
inline Iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
|
||||
return (*this += -value);
|
||||
}
|
||||
|
||||
inline Iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
|
||||
return (*this + -value);
|
||||
}
|
||||
|
||||
difference_type operator-(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.pos - pos;
|
||||
}
|
||||
|
||||
reference operator[](const difference_type value) const ENTT_NOEXCEPT {
|
||||
return instances[pos-value-1];
|
||||
}
|
||||
|
||||
bool operator==(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.pos == pos;
|
||||
}
|
||||
@@ -539,17 +645,33 @@ class SparseSet<Entity, Type>: public SparseSet<Entity> {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
reference operator*() const ENTT_NOEXCEPT {
|
||||
return instances[pos-1];
|
||||
bool operator<(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return pos > other.pos;
|
||||
}
|
||||
|
||||
bool operator>(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return pos < other.pos;
|
||||
}
|
||||
|
||||
inline bool operator<=(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this > other);
|
||||
}
|
||||
|
||||
inline bool operator>=(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
pointer operator->() const ENTT_NOEXCEPT {
|
||||
return (instances+pos-1);
|
||||
}
|
||||
|
||||
inline reference operator*() const ENTT_NOEXCEPT {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
pointer instances;
|
||||
std::size_t pos;
|
||||
difference_type pos;
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -643,7 +765,8 @@ public:
|
||||
* @return An iterator to the first instance of the given type.
|
||||
*/
|
||||
const_iterator_type cbegin() const ENTT_NOEXCEPT {
|
||||
return const_iterator_type{instances.data(), instances.size()};
|
||||
const typename traits_type::difference_type pos = instances.size();
|
||||
return const_iterator_type{instances.data(), pos};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -675,7 +798,8 @@ public:
|
||||
* @return An iterator to the first instance of the given type.
|
||||
*/
|
||||
iterator_type begin() ENTT_NOEXCEPT {
|
||||
return iterator_type{instances.data(), instances.size()};
|
||||
const typename traits_type::difference_type pos = instances.size();
|
||||
return iterator_type{instances.data(), pos};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define ENTT_ENTITY_VIEW_HPP
|
||||
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
@@ -469,8 +470,26 @@ class View final {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
|
||||
class Iterator {
|
||||
friend class View<Entity, Component...>;
|
||||
|
||||
using size_type = typename view_type::size_type;
|
||||
|
||||
Iterator(unchecked_type unchecked, underlying_iterator_type begin, underlying_iterator_type end) ENTT_NOEXCEPT
|
||||
: unchecked{unchecked},
|
||||
begin{begin},
|
||||
end{end},
|
||||
extent{min(std::make_index_sequence<unchecked.size()>{})}
|
||||
{
|
||||
if(begin != end && !valid()) {
|
||||
++(*this);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t... Indexes>
|
||||
size_type min(std::index_sequence<Indexes...>) const ENTT_NOEXCEPT {
|
||||
return std::min({ std::get<Indexes>(unchecked)->extent()... });
|
||||
}
|
||||
|
||||
bool valid() const ENTT_NOEXCEPT {
|
||||
const auto entity = *begin;
|
||||
const auto sz = size_type(entity & traits_type::entity_mask);
|
||||
@@ -485,17 +504,19 @@ class View final {
|
||||
using value_type = typename underlying_iterator_type::value_type;
|
||||
using pointer = typename underlying_iterator_type::pointer;
|
||||
using reference = typename underlying_iterator_type::reference;
|
||||
using iterator_category = typename underlying_iterator_type::iterator_category;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
Iterator(unchecked_type unchecked, size_type extent, underlying_iterator_type begin, underlying_iterator_type end) ENTT_NOEXCEPT
|
||||
: unchecked{unchecked},
|
||||
extent{extent},
|
||||
begin{begin},
|
||||
end{end}
|
||||
{
|
||||
if(begin != end && !valid()) {
|
||||
++(*this);
|
||||
}
|
||||
Iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
Iterator(const Iterator &) ENTT_NOEXCEPT = default;
|
||||
Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default;
|
||||
|
||||
friend void swap(Iterator &lhs, Iterator &rhs) ENTT_NOEXCEPT {
|
||||
using std::swap;
|
||||
swap(lhs.unchecked, rhs.unchecked);
|
||||
swap(lhs.extent, rhs.extent);
|
||||
swap(lhs.begin, rhs.begin);
|
||||
swap(lhs.end, rhs.end);
|
||||
}
|
||||
|
||||
Iterator & operator++() ENTT_NOEXCEPT {
|
||||
@@ -507,14 +528,6 @@ class View final {
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
Iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
|
||||
return ((begin += value) != end && !valid()) ? ++(*this) : *this;
|
||||
}
|
||||
|
||||
Iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
|
||||
return Iterator{unchecked, extent, begin+value, end};
|
||||
}
|
||||
|
||||
bool operator==(const Iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.begin == begin;
|
||||
}
|
||||
@@ -523,15 +536,19 @@ class View final {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
value_type operator*() const ENTT_NOEXCEPT {
|
||||
return *begin;
|
||||
pointer operator->() const ENTT_NOEXCEPT {
|
||||
return begin.operator->();
|
||||
}
|
||||
|
||||
inline reference operator*() const ENTT_NOEXCEPT {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
const unchecked_type unchecked;
|
||||
const size_type extent;
|
||||
unchecked_type unchecked;
|
||||
underlying_iterator_type begin;
|
||||
underlying_iterator_type end;
|
||||
size_type extent;
|
||||
};
|
||||
|
||||
View(pool_type<Component> &... pools) ENTT_NOEXCEPT
|
||||
@@ -563,10 +580,6 @@ class View final {
|
||||
return other;
|
||||
}
|
||||
|
||||
typename view_type::size_type extent() const ENTT_NOEXCEPT {
|
||||
return std::min({ pool<Component>().extent()... });
|
||||
}
|
||||
|
||||
template<typename Comp, typename Other>
|
||||
inline std::enable_if_t<std::is_same<Comp, Other>::value, const Other &>
|
||||
get(const component_iterator_type<Comp> &it, const Entity) const ENTT_NOEXCEPT { return *it; }
|
||||
@@ -592,15 +605,15 @@ class View final {
|
||||
}
|
||||
}
|
||||
|
||||
const auto extent = std::min({ pool<Component>().extent()... });
|
||||
auto it = std::get<component_iterator_type<Comp>>(raw);
|
||||
const auto ext = extent();
|
||||
|
||||
// fallback to visit what remains using indirections
|
||||
for(; data[0] != end; ++data[0], ++it) {
|
||||
const auto entity = *data[0];
|
||||
const auto sz = size_type(entity & traits_type::entity_mask);
|
||||
|
||||
if(sz < ext && std::all_of(other.cbegin(), other.cend(), [entity](const view_type *view) { return view->fast(entity); })) {
|
||||
if(sz < extent && std::all_of(other.cbegin(), other.cend(), [entity](const view_type *view) { return view->fast(entity); })) {
|
||||
// avoided at least the indirection due to the sparse set for the pivot type (see get for more details)
|
||||
func(entity, get<Comp, Component>(it, entity)...);
|
||||
}
|
||||
@@ -649,7 +662,7 @@ public:
|
||||
*/
|
||||
const_iterator_type cbegin() const ENTT_NOEXCEPT {
|
||||
const auto *view = candidate();
|
||||
return iterator_type{ unchecked(view), extent(), view->cbegin(), view->cend() };
|
||||
return iterator_type{ unchecked(view), view->cbegin(), view->cend() };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -705,7 +718,7 @@ public:
|
||||
*/
|
||||
const_iterator_type cend() const ENTT_NOEXCEPT {
|
||||
const auto *view = candidate();
|
||||
return iterator_type{ unchecked(view), extent(), view->cend(), view->cend() };
|
||||
return iterator_type{ unchecked(view), view->cend(), view->cend() };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -753,7 +766,8 @@ public:
|
||||
*/
|
||||
bool contains(const entity_type entity) const ENTT_NOEXCEPT {
|
||||
const auto sz = size_type(entity & traits_type::entity_mask);
|
||||
return sz < extent() && std::min({ (pool<Component>().has(entity) && (pool<Component>().data()[pool<Component>().view_type::get(entity)] == entity))... });
|
||||
const auto extent = std::min({ pool<Component>().extent()... });
|
||||
return sz < extent && std::min({ (pool<Component>().has(entity) && (pool<Component>().data()[pool<Component>().view_type::get(entity)] == entity))... });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/sparse_set.hpp>
|
||||
|
||||
struct Type {
|
||||
int value;
|
||||
};
|
||||
|
||||
TEST(SparseSetNoType, Functionalities) {
|
||||
entt::SparseSet<unsigned int> set;
|
||||
const auto &cset = set;
|
||||
@@ -54,7 +58,97 @@ TEST(SparseSetNoType, Functionalities) {
|
||||
other = std::move(set);
|
||||
}
|
||||
|
||||
TEST(SparseSetNoType, DataBeginEnd) {
|
||||
TEST(SparseSetNoType, Iterator) {
|
||||
using iterator_type = typename entt::SparseSet<unsigned int>::iterator_type;
|
||||
|
||||
entt::SparseSet<unsigned int> set;
|
||||
set.construct(3);
|
||||
|
||||
iterator_type end{set.begin()};
|
||||
iterator_type begin{};
|
||||
begin = set.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, set.begin());
|
||||
ASSERT_EQ(end, set.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, set.begin());
|
||||
ASSERT_EQ(begin--, set.end());
|
||||
|
||||
ASSERT_EQ(begin+1, set.end());
|
||||
ASSERT_EQ(end-1, set.begin());
|
||||
|
||||
ASSERT_EQ(++begin, set.end());
|
||||
ASSERT_EQ(--begin, set.begin());
|
||||
|
||||
ASSERT_EQ(begin += 1, set.end());
|
||||
ASSERT_EQ(begin -= 1, set.begin());
|
||||
|
||||
ASSERT_EQ(begin + (end - begin), set.end());
|
||||
ASSERT_EQ(begin - (begin - end), set.end());
|
||||
|
||||
ASSERT_EQ(end - (end - begin), set.begin());
|
||||
ASSERT_EQ(end + (begin - end), set.begin());
|
||||
|
||||
ASSERT_EQ(begin[0], *set.begin());
|
||||
|
||||
ASSERT_LT(begin, end);
|
||||
ASSERT_LE(begin, set.begin());
|
||||
|
||||
ASSERT_GT(end, begin);
|
||||
ASSERT_GE(end, set.end());
|
||||
|
||||
ASSERT_EQ(*begin, 3);
|
||||
ASSERT_EQ(*begin.operator->(), 3);
|
||||
}
|
||||
|
||||
TEST(SparseSetNoType, ConstIterator) {
|
||||
using iterator_type = typename entt::SparseSet<unsigned int>::const_iterator_type;
|
||||
|
||||
entt::SparseSet<unsigned int> set;
|
||||
set.construct(3);
|
||||
|
||||
iterator_type cend{set.cbegin()};
|
||||
iterator_type cbegin{};
|
||||
cbegin = set.cend();
|
||||
std::swap(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin, set.cbegin());
|
||||
ASSERT_EQ(cend, set.cend());
|
||||
ASSERT_NE(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin++, set.cbegin());
|
||||
ASSERT_EQ(cbegin--, set.cend());
|
||||
|
||||
ASSERT_EQ(cbegin+1, set.cend());
|
||||
ASSERT_EQ(cend-1, set.cbegin());
|
||||
|
||||
ASSERT_EQ(++cbegin, set.cend());
|
||||
ASSERT_EQ(--cbegin, set.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin += 1, set.cend());
|
||||
ASSERT_EQ(cbegin -= 1, set.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin + (cend - cbegin), set.cend());
|
||||
ASSERT_EQ(cbegin - (cbegin - cend), set.cend());
|
||||
|
||||
ASSERT_EQ(cend - (cend - cbegin), set.cbegin());
|
||||
ASSERT_EQ(cend + (cbegin - cend), set.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin[0], *set.cbegin());
|
||||
|
||||
ASSERT_LT(cbegin, cend);
|
||||
ASSERT_LE(cbegin, set.cbegin());
|
||||
|
||||
ASSERT_GT(cend, cbegin);
|
||||
ASSERT_GE(cend, set.cend());
|
||||
|
||||
ASSERT_EQ(*cbegin, 3);
|
||||
ASSERT_EQ(*cbegin.operator->(), 3);
|
||||
}
|
||||
|
||||
TEST(SparseSetNoType, Data) {
|
||||
entt::SparseSet<unsigned int> set;
|
||||
|
||||
set.construct(3);
|
||||
@@ -68,31 +162,6 @@ TEST(SparseSetNoType, DataBeginEnd) {
|
||||
ASSERT_EQ(*(set.data() + 0u), 3u);
|
||||
ASSERT_EQ(*(set.data() + 1u), 12u);
|
||||
ASSERT_EQ(*(set.data() + 2u), 42u);
|
||||
|
||||
auto it = set.begin();
|
||||
|
||||
ASSERT_EQ(*it, 42u);
|
||||
ASSERT_EQ(*(it+1), 12u);
|
||||
ASSERT_EQ(*(it+2), 3u);
|
||||
ASSERT_EQ(it += 3, set.end());
|
||||
|
||||
auto begin = set.begin();
|
||||
auto end = set.end();
|
||||
|
||||
ASSERT_EQ(*(begin++), 42u);
|
||||
ASSERT_EQ(*(begin++), 12u);
|
||||
ASSERT_EQ(*(begin++), 3u);
|
||||
|
||||
ASSERT_EQ(begin, end);
|
||||
|
||||
auto cbegin = set.cbegin();
|
||||
auto cend = set.cend();
|
||||
|
||||
ASSERT_NE(cbegin, cend);
|
||||
ASSERT_EQ(cbegin+3, cend);
|
||||
ASSERT_NE(cbegin, cend);
|
||||
ASSERT_EQ(cbegin += 3, cend);
|
||||
ASSERT_EQ(cbegin, cend);
|
||||
}
|
||||
|
||||
TEST(SparseSetNoType, RespectDisjoint) {
|
||||
@@ -320,7 +389,91 @@ TEST(SparseSetWithType, TypesFromStandardTemplateLibraryMustWork) {
|
||||
set.destroy(0);
|
||||
}
|
||||
|
||||
TEST(SparseSetWithType, RawBeginEnd) {
|
||||
TEST(SparseSetWithType, Iterator) {
|
||||
using iterator_type = typename entt::SparseSet<unsigned int, Type>::iterator_type;
|
||||
|
||||
entt::SparseSet<unsigned int, Type> set;
|
||||
set.construct(3, 42);
|
||||
|
||||
iterator_type end{set.begin()};
|
||||
iterator_type begin{};
|
||||
begin = set.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, set.begin());
|
||||
ASSERT_EQ(end, set.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, set.begin());
|
||||
ASSERT_EQ(begin--, set.end());
|
||||
|
||||
ASSERT_EQ(begin+1, set.end());
|
||||
ASSERT_EQ(end-1, set.begin());
|
||||
|
||||
ASSERT_EQ(++begin, set.end());
|
||||
ASSERT_EQ(--begin, set.begin());
|
||||
|
||||
ASSERT_EQ(begin += 1, set.end());
|
||||
ASSERT_EQ(begin -= 1, set.begin());
|
||||
|
||||
ASSERT_EQ(begin + (end - begin), set.end());
|
||||
ASSERT_EQ(begin - (begin - end), set.end());
|
||||
|
||||
ASSERT_EQ(end - (end - begin), set.begin());
|
||||
ASSERT_EQ(end + (begin - end), set.begin());
|
||||
|
||||
ASSERT_EQ(begin[0].value, set.begin()->value);
|
||||
|
||||
ASSERT_LT(begin, end);
|
||||
ASSERT_LE(begin, set.begin());
|
||||
|
||||
ASSERT_GT(end, begin);
|
||||
ASSERT_GE(end, set.end());
|
||||
}
|
||||
|
||||
TEST(SparseSetWithType, ConstIterator) {
|
||||
using iterator_type = typename entt::SparseSet<unsigned int, Type>::const_iterator_type;
|
||||
|
||||
entt::SparseSet<unsigned int, Type> set;
|
||||
set.construct(3, 42);
|
||||
|
||||
iterator_type cend{set.cbegin()};
|
||||
iterator_type cbegin{};
|
||||
cbegin = set.cend();
|
||||
std::swap(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin, set.cbegin());
|
||||
ASSERT_EQ(cend, set.cend());
|
||||
ASSERT_NE(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin++, set.cbegin());
|
||||
ASSERT_EQ(cbegin--, set.cend());
|
||||
|
||||
ASSERT_EQ(cbegin+1, set.cend());
|
||||
ASSERT_EQ(cend-1, set.cbegin());
|
||||
|
||||
ASSERT_EQ(++cbegin, set.cend());
|
||||
ASSERT_EQ(--cbegin, set.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin += 1, set.cend());
|
||||
ASSERT_EQ(cbegin -= 1, set.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin + (cend - cbegin), set.cend());
|
||||
ASSERT_EQ(cbegin - (cbegin - cend), set.cend());
|
||||
|
||||
ASSERT_EQ(cend - (cend - cbegin), set.cbegin());
|
||||
ASSERT_EQ(cend + (cbegin - cend), set.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin[0].value, set.cbegin()->value);
|
||||
|
||||
ASSERT_LT(cbegin, cend);
|
||||
ASSERT_LE(cbegin, set.cbegin());
|
||||
|
||||
ASSERT_GT(cend, cbegin);
|
||||
ASSERT_GE(cend, set.cend());
|
||||
}
|
||||
|
||||
TEST(SparseSetWithType, Raw) {
|
||||
entt::SparseSet<unsigned int, int> set;
|
||||
|
||||
set.construct(3, 3);
|
||||
@@ -334,23 +487,6 @@ TEST(SparseSetWithType, RawBeginEnd) {
|
||||
ASSERT_EQ(*(set.raw() + 0u), 3);
|
||||
ASSERT_EQ(*(set.raw() + 1u), 6);
|
||||
ASSERT_EQ(*(set.raw() + 2u), 9);
|
||||
|
||||
auto begin = set.begin();
|
||||
auto end = set.end();
|
||||
|
||||
ASSERT_EQ(*(begin++), 9);
|
||||
ASSERT_EQ(*(begin++), 6);
|
||||
ASSERT_EQ(*(begin++), 3);
|
||||
ASSERT_EQ(begin, end);
|
||||
|
||||
auto cbegin = set.cbegin();
|
||||
auto cend = set.cend();
|
||||
|
||||
ASSERT_NE(cbegin, cend);
|
||||
ASSERT_EQ(cbegin+3, cend);
|
||||
ASSERT_NE(cbegin, cend);
|
||||
ASSERT_EQ(cbegin += 3, cend);
|
||||
ASSERT_EQ(cbegin, cend);
|
||||
}
|
||||
|
||||
TEST(SparseSetWithType, SortOrdered) {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/view.hpp>
|
||||
|
||||
TEST(View, SingleComponent) {
|
||||
TEST(SingleComponentView, Functionalities) {
|
||||
entt::DefaultRegistry registry;
|
||||
auto view = registry.view<char>();
|
||||
|
||||
@@ -43,34 +44,11 @@ TEST(View, SingleComponent) {
|
||||
registry.remove<char>(e1);
|
||||
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_EQ(view.cbegin(), view.cend());
|
||||
ASSERT_TRUE(view.empty());
|
||||
}
|
||||
|
||||
TEST(View, SingleComponentBeginEnd) {
|
||||
entt::DefaultRegistry registry;
|
||||
auto view = registry.view<int>();
|
||||
const auto &cview = view;
|
||||
|
||||
for(auto i = 0; i < 3; ++i) {
|
||||
registry.assign<int>(registry.create());
|
||||
}
|
||||
|
||||
auto test = [](auto begin, auto end) {
|
||||
ASSERT_NE(begin, end);
|
||||
ASSERT_NE(++begin, end);
|
||||
ASSERT_NE(begin++, end);
|
||||
ASSERT_EQ(begin+1, end);
|
||||
ASSERT_NE(begin, end);
|
||||
ASSERT_EQ((begin += 1), end);
|
||||
ASSERT_EQ(begin, end);
|
||||
};
|
||||
|
||||
test(view.begin(), view.end());
|
||||
test(cview.begin(), cview.end());
|
||||
test(view.cbegin(), view.cend());
|
||||
}
|
||||
|
||||
TEST(View, SingleComponentContains) {
|
||||
TEST(SingleComponentView, Contains) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
@@ -87,7 +65,7 @@ TEST(View, SingleComponentContains) {
|
||||
ASSERT_TRUE(view.contains(e1));
|
||||
}
|
||||
|
||||
TEST(View, SingleComponentEmpty) {
|
||||
TEST(SingleComponentView, Empty) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
@@ -107,7 +85,7 @@ TEST(View, SingleComponentEmpty) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(View, SingleComponentEach) {
|
||||
TEST(SingleComponentView, Each) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
registry.assign<int>(registry.create());
|
||||
@@ -126,7 +104,7 @@ TEST(View, SingleComponentEach) {
|
||||
ASSERT_EQ(cnt, std::size_t{0});
|
||||
}
|
||||
|
||||
TEST(View, MultipleComponent) {
|
||||
TEST(MultipleComponentView, Functionalities) {
|
||||
entt::DefaultRegistry registry;
|
||||
auto view = registry.view<int, char>();
|
||||
|
||||
@@ -152,7 +130,6 @@ TEST(View, MultipleComponent) {
|
||||
ASSERT_NO_THROW((++registry.view<int, char>().begin()));
|
||||
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_EQ(view.begin()+1, view.end());
|
||||
ASSERT_EQ(view.size(), decltype(view.size()){1});
|
||||
|
||||
registry.get<char>(e0) = '1';
|
||||
@@ -170,33 +147,53 @@ TEST(View, MultipleComponent) {
|
||||
registry.remove<char>(e1);
|
||||
}
|
||||
|
||||
TEST(View, MultipleComponentBeginEnd) {
|
||||
TEST(MultipleComponentView, Iterator) {
|
||||
using iterator_type = typename decltype(std::declval<entt::DefaultRegistry>().view<int, char>())::iterator_type;
|
||||
|
||||
entt::DefaultRegistry registry;
|
||||
auto view = registry.view<int, char>();
|
||||
const auto &cview = view;
|
||||
const auto entity = registry.create();
|
||||
registry.assign<int>(entity);
|
||||
registry.assign<char>(entity);
|
||||
|
||||
for(auto i = 0; i < 3; ++i) {
|
||||
const auto entity = registry.create();
|
||||
registry.assign<int>(entity);
|
||||
registry.assign<char>(entity);
|
||||
}
|
||||
const auto view = registry.view<int, char>();
|
||||
|
||||
auto test = [](auto begin, auto end) {
|
||||
ASSERT_NE(begin, end);
|
||||
ASSERT_NE(++begin, end);
|
||||
ASSERT_NE(begin++, end);
|
||||
ASSERT_EQ(begin+1, end);
|
||||
ASSERT_NE(begin, end);
|
||||
ASSERT_EQ((begin += 1), end);
|
||||
ASSERT_EQ(begin, end);
|
||||
};
|
||||
iterator_type end{view.begin()};
|
||||
iterator_type begin{};
|
||||
begin = view.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
test(cview.begin(), cview.end());
|
||||
test(view.begin(), view.end());
|
||||
test(view.cbegin(), view.cend());
|
||||
ASSERT_EQ(begin, view.begin());
|
||||
ASSERT_EQ(end, view.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(view.begin()++, view.begin());
|
||||
ASSERT_EQ(++view.begin(), view.end());
|
||||
}
|
||||
|
||||
TEST(View, MultipleComponentContains) {
|
||||
TEST(MultipleComponentView, ConstIterator) {
|
||||
using iterator_type = typename decltype(std::declval<entt::DefaultRegistry>().view<int, char>())::const_iterator_type;
|
||||
|
||||
entt::DefaultRegistry registry;
|
||||
const auto entity = registry.create();
|
||||
registry.assign<int>(entity);
|
||||
registry.assign<char>(entity);
|
||||
|
||||
const auto view = registry.view<int, char>();
|
||||
|
||||
iterator_type cend{view.cbegin()};
|
||||
iterator_type cbegin{};
|
||||
cbegin = view.cend();
|
||||
std::swap(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin, view.cbegin());
|
||||
ASSERT_EQ(cend, view.cend());
|
||||
ASSERT_NE(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(view.cbegin()++, view.cbegin());
|
||||
ASSERT_EQ(++view.cbegin(), view.cend());
|
||||
}
|
||||
|
||||
TEST(MultipleComponentView, Contains) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
@@ -215,7 +212,7 @@ TEST(View, MultipleComponentContains) {
|
||||
ASSERT_TRUE(view.contains(e1));
|
||||
}
|
||||
|
||||
TEST(View, MultipleComponentEmpty) {
|
||||
TEST(MultipleComponentView, Empty) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
@@ -235,7 +232,7 @@ TEST(View, MultipleComponentEmpty) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(View, MultipleComponentEach) {
|
||||
TEST(MultipleComponentView, Each) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
@@ -259,7 +256,7 @@ TEST(View, MultipleComponentEach) {
|
||||
ASSERT_EQ(cnt, std::size_t{0});
|
||||
}
|
||||
|
||||
TEST(View, MultipleComponentEachWithHoles) {
|
||||
TEST(MultipleComponentView, EachWithHoles) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
@@ -330,6 +327,7 @@ TEST(PersistentView, Prepare) {
|
||||
registry.remove<char>(e1);
|
||||
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_EQ(view.cbegin(), view.cend());
|
||||
ASSERT_TRUE(view.empty());
|
||||
}
|
||||
|
||||
@@ -378,35 +376,10 @@ TEST(PersistentView, NoPrepare) {
|
||||
registry.remove<char>(e1);
|
||||
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_EQ(view.cbegin(), view.cend());
|
||||
ASSERT_TRUE(view.empty());
|
||||
}
|
||||
|
||||
TEST(PersistentView, BeginEnd) {
|
||||
entt::DefaultRegistry registry;
|
||||
auto view = registry.view<int, char>(entt::persistent_t{});
|
||||
const auto &cview = view;
|
||||
|
||||
for(auto i = 0; i < 3; ++i) {
|
||||
const auto entity = registry.create();
|
||||
registry.assign<int>(entity);
|
||||
registry.assign<char>(entity);
|
||||
}
|
||||
|
||||
auto test = [](auto begin, auto end) {
|
||||
ASSERT_NE(begin, end);
|
||||
ASSERT_NE(++begin, end);
|
||||
ASSERT_NE(begin++, end);
|
||||
ASSERT_EQ(begin+1, end);
|
||||
ASSERT_NE(begin, end);
|
||||
ASSERT_EQ((begin += 1), end);
|
||||
ASSERT_EQ(begin, end);
|
||||
};
|
||||
|
||||
test(cview.begin(), cview.end());
|
||||
test(view.begin(), view.end());
|
||||
test(view.cbegin(), view.cend());
|
||||
}
|
||||
|
||||
TEST(PersistentView, Contains) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
@@ -558,33 +531,10 @@ TEST(RawView, Functionalities) {
|
||||
registry.remove<char>(e1);
|
||||
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_EQ(view.cbegin(), view.cend());
|
||||
ASSERT_TRUE(view.empty());
|
||||
}
|
||||
|
||||
TEST(RawView, BeginEnd) {
|
||||
entt::DefaultRegistry registry;
|
||||
auto view = registry.view<int>(entt::raw_t{});
|
||||
const auto &cview = view;
|
||||
|
||||
for(auto i = 0; i < 3; ++i) {
|
||||
registry.assign<int>(registry.create());
|
||||
}
|
||||
|
||||
auto test = [](auto begin, auto end) {
|
||||
ASSERT_NE(begin, end);
|
||||
ASSERT_NE(++begin, end);
|
||||
ASSERT_NE(begin++, end);
|
||||
ASSERT_EQ(begin+1, end);
|
||||
ASSERT_NE(begin, end);
|
||||
ASSERT_EQ((begin += 1), end);
|
||||
ASSERT_EQ(begin, end);
|
||||
};
|
||||
|
||||
test(cview.begin(), cview.end());
|
||||
test(view.begin(), view.end());
|
||||
test(view.cbegin(), view.cend());
|
||||
}
|
||||
|
||||
TEST(RawView, Empty) {
|
||||
entt::DefaultRegistry registry;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user