review: iterators (sparse set/view)

This commit is contained in:
Michele Caini
2018-06-08 22:30:50 +02:00
parent 8600781bb6
commit dc4e5ddc3c
6 changed files with 440 additions and 207 deletions

3
TODO
View File

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

View File

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

View File

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

View File

@@ -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))... });
}
/**

View File

@@ -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) {

View File

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