Merge branch 'master' into cxx17
This commit is contained in:
commit
25c864dd8a
4 changed files with 433 additions and 22 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@ build*/
|
||||||
doxygen_html/
|
doxygen_html/
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
tags
|
tags
|
||||||
|
.clangd/
|
||||||
|
|
|
@ -75,6 +75,28 @@ namespace EC
|
||||||
|
|
||||||
return bitset;
|
return bitset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename IntegralType>
|
||||||
|
auto getCombinedBit(const IntegralType& i) {
|
||||||
|
static_assert(std::is_integral<IntegralType>::value,
|
||||||
|
"Parameter must be an integral type");
|
||||||
|
if(i >= Combined::size || i < 0) {
|
||||||
|
return (*this)[Combined::size];
|
||||||
|
} else {
|
||||||
|
return (*this)[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IntegralType>
|
||||||
|
auto getCombinedBit(const IntegralType& i) const {
|
||||||
|
static_assert(std::is_integral<IntegralType>::value,
|
||||||
|
"Parameter must be an integral type");
|
||||||
|
if(i >= Combined::size || i < 0) {
|
||||||
|
return (*this)[Combined::size];
|
||||||
|
} else {
|
||||||
|
return (*this)[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -66,14 +67,14 @@ namespace EC
|
||||||
template <typename... Types>
|
template <typename... Types>
|
||||||
struct Storage
|
struct Storage
|
||||||
{
|
{
|
||||||
using type = std::tuple<std::vector<Types>...>;
|
using type = std::tuple<std::deque<Types>...>;
|
||||||
};
|
};
|
||||||
using ComponentsStorage =
|
using ComponentsStorage =
|
||||||
typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
|
typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
|
||||||
|
|
||||||
// Entity: isAlive, ComponentsTags Info
|
// Entity: isAlive, ComponentsTags Info
|
||||||
using EntitiesTupleType = std::tuple<bool, BitsetType>;
|
using EntitiesTupleType = std::tuple<bool, BitsetType>;
|
||||||
using EntitiesType = std::vector<EntitiesTupleType>;
|
using EntitiesType = std::deque<EntitiesTupleType>;
|
||||||
|
|
||||||
EntitiesType entities;
|
EntitiesType entities;
|
||||||
ComponentsStorage componentsStorage;
|
ComponentsStorage componentsStorage;
|
||||||
|
@ -102,7 +103,7 @@ namespace EC
|
||||||
}
|
}
|
||||||
|
|
||||||
EC::Meta::forEach<ComponentsList>([this, newCapacity] (auto t) {
|
EC::Meta::forEach<ComponentsList>([this, newCapacity] (auto t) {
|
||||||
std::get<std::vector<decltype(t)> >(
|
std::get<std::deque<decltype(t)> >(
|
||||||
this->componentsStorage).resize(newCapacity);
|
this->componentsStorage).resize(newCapacity);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -243,7 +244,7 @@ namespace EC
|
||||||
{
|
{
|
||||||
if constexpr (EC::Meta::Contains<Component, Components>::value)
|
if constexpr (EC::Meta::Contains<Component, Components>::value)
|
||||||
{
|
{
|
||||||
return &std::get<std::vector<Component> >(componentsStorage)
|
return &std::get<std::deque<Component> >(componentsStorage)
|
||||||
.at(index);
|
.at(index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -291,7 +292,7 @@ namespace EC
|
||||||
{
|
{
|
||||||
if constexpr (EC::Meta::Contains<Component, Components>::value)
|
if constexpr (EC::Meta::Contains<Component, Components>::value)
|
||||||
{
|
{
|
||||||
return &std::get<std::vector<Component> >(componentsStorage)
|
return &std::get<std::deque<Component> >(componentsStorage)
|
||||||
.at(index);
|
.at(index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -400,7 +401,7 @@ namespace EC
|
||||||
entities[entityID]
|
entities[entityID]
|
||||||
).template getComponentBit<Component>() = true;
|
).template getComponentBit<Component>() = true;
|
||||||
|
|
||||||
std::get<std::vector<Component> >(componentsStorage)[entityID]
|
std::get<std::deque<Component> >(componentsStorage)[entityID]
|
||||||
= std::move(component);
|
= std::move(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -491,6 +492,23 @@ namespace EC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Resets the Manager, removing all entities.
|
||||||
|
|
||||||
|
Some data may persist but will be overwritten when new entities
|
||||||
|
are added. Thus, do not depend on data to persist after a call to
|
||||||
|
reset().
|
||||||
|
*/
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
clearForMatchingFunctions();
|
||||||
|
|
||||||
|
currentSize = 0;
|
||||||
|
currentCapacity = 0;
|
||||||
|
deletedSet.clear();
|
||||||
|
resize(EC_INIT_ENTITIES_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename... Types>
|
template <typename... Types>
|
||||||
struct ForMatchingSignatureHelper
|
struct ForMatchingSignatureHelper
|
||||||
|
@ -566,7 +584,7 @@ namespace EC
|
||||||
The second parameter is default nullptr and will be passed to the
|
The second parameter is default nullptr and will be passed to the
|
||||||
function call as the second parameter as a means of providing
|
function call as the second parameter as a means of providing
|
||||||
context (useful when the function is not a lambda function). The
|
context (useful when the function is not a lambda function). The
|
||||||
third parameter is default 1 (not multi-threaded). If the third
|
third parameter is default 1 (not multi-threaded). If the third
|
||||||
parameter threadCount is set to a value greater than 1, then
|
parameter threadCount is set to a value greater than 1, then
|
||||||
threadCount threads will be used. Note that multi-threading is
|
threadCount threads will be used. Note that multi-threading is
|
||||||
based on splitting the task of calling the function across sections
|
based on splitting the task of calling the function across sections
|
||||||
|
@ -867,7 +885,7 @@ namespace EC
|
||||||
std::make_tuple(
|
std::make_tuple(
|
||||||
signatureBitset,
|
signatureBitset,
|
||||||
context,
|
context,
|
||||||
[function, helper, this]
|
[function, helper, this]
|
||||||
(std::size_t threadCount,
|
(std::size_t threadCount,
|
||||||
std::vector<std::size_t> matching,
|
std::vector<std::size_t> matching,
|
||||||
void* context)
|
void* context)
|
||||||
|
@ -1369,7 +1387,7 @@ namespace EC
|
||||||
threads[i].join();
|
threads[i].join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// call functions on matching entities
|
// call functions on matching entities
|
||||||
EC::Meta::forEachDoubleTuple(
|
EC::Meta::forEachDoubleTuple(
|
||||||
EC::Meta::Morph<SigList, std::tuple<> >{},
|
EC::Meta::Morph<SigList, std::tuple<> >{},
|
||||||
|
@ -1565,7 +1583,7 @@ namespace EC
|
||||||
threads[i].join();
|
threads[i].join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// call functions on matching entities
|
// call functions on matching entities
|
||||||
EC::Meta::forEachDoubleTuple(
|
EC::Meta::forEachDoubleTuple(
|
||||||
EC::Meta::Morph<SigList, std::tuple<> >{},
|
EC::Meta::Morph<SigList, std::tuple<> >{},
|
||||||
|
@ -1635,21 +1653,126 @@ namespace EC
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef void ForMatchingFn(std::size_t, Manager<ComponentsList, TagsList>*, void*);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Resets the Manager, removing all entities.
|
* \brief A simple version of forMatchingSignature()
|
||||||
|
*
|
||||||
|
* This function behaves like forMatchingSignature(), but instead of
|
||||||
|
* providing a function with each requested component as a parameter,
|
||||||
|
* the function receives a pointer to the manager itself, with which to
|
||||||
|
* query component/tag data.
|
||||||
|
*/
|
||||||
|
template <typename Signature>
|
||||||
|
void forMatchingSimple(ForMatchingFn fn, void *userData = nullptr, std::size_t threadCount = 1) {
|
||||||
|
const BitsetType signatureBitset = BitsetType::template generateBitset<Signature>();
|
||||||
|
if(threadCount <= 1) {
|
||||||
|
for(std::size_t i = 0; i < currentSize; ++i) {
|
||||||
|
if(!std::get<bool>(entities[i])) {
|
||||||
|
continue;
|
||||||
|
} else if((signatureBitset & std::get<BitsetType>(entities[i])) == signatureBitset) {
|
||||||
|
fn(i, this, userData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::vector<std::thread> threads(threadCount);
|
||||||
|
const std::size_t s = currentSize / threadCount;
|
||||||
|
for(std::size_t i = 0; i < threadCount; ++i) {
|
||||||
|
const std::size_t begin = s * i;
|
||||||
|
const std::size_t end =
|
||||||
|
i == threadCount - 1 ?
|
||||||
|
currentSize :
|
||||||
|
s * (i + 1);
|
||||||
|
threads[i] = std::thread(
|
||||||
|
[this] (const std::size_t begin,
|
||||||
|
const std::size_t end,
|
||||||
|
const BitsetType signatureBitset,
|
||||||
|
ForMatchingFn fn,
|
||||||
|
void *userData) {
|
||||||
|
for(std::size_t i = begin; i < end; ++i) {
|
||||||
|
if(!std::get<bool>(entities[i])) {
|
||||||
|
continue;
|
||||||
|
} else if((signatureBitset & std::get<BitsetType>(entities[i])) == signatureBitset) {
|
||||||
|
fn(i, this, userData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
begin,
|
||||||
|
end,
|
||||||
|
signatureBitset,
|
||||||
|
fn,
|
||||||
|
userData);
|
||||||
|
}
|
||||||
|
for(std::size_t i = 0; i < threadCount; ++i) {
|
||||||
|
threads[i].join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Some data may persist but will be overwritten when new entities
|
/*!
|
||||||
are added. Thus, do not depend on data to persist after a call to
|
* \brief Similar to forMatchingSimple(), but with a collection of Component/Tag indices
|
||||||
reset().
|
*
|
||||||
*/
|
* This function works like forMatchingSimple(), but instead of
|
||||||
void reset()
|
* providing template types that filter out non-matching entities, an
|
||||||
{
|
* iterable of indices must be provided which correlate to matching
|
||||||
clearForMatchingFunctions();
|
* Component/Tag indices. The function given must match the previously
|
||||||
|
* defined typedef of type ForMatchingFn.
|
||||||
|
*/
|
||||||
|
template <typename Iterable>
|
||||||
|
void forMatchingIterable(Iterable iterable, ForMatchingFn fn, void* userPtr = nullptr, std::size_t threadCount = 1) {
|
||||||
|
if(threadCount <= 1) {
|
||||||
|
bool isValid;
|
||||||
|
for(std::size_t i = 0; i < currentSize; ++i) {
|
||||||
|
if(!std::get<bool>(entities[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
currentSize = 0;
|
isValid = true;
|
||||||
currentCapacity = 0;
|
for(const auto& integralValue : iterable) {
|
||||||
deletedSet.clear();
|
if(!std::get<BitsetType>(entities[i]).getCombinedBit(integralValue)) {
|
||||||
resize(EC_INIT_ENTITIES_SIZE);
|
isValid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!isValid) { continue; }
|
||||||
|
|
||||||
|
fn(i, this, userPtr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::vector<std::thread> threads(threadCount);
|
||||||
|
std::size_t s = currentSize / threadCount;
|
||||||
|
for(std::size_t i = 0; i < threadCount; ++i) {
|
||||||
|
std::size_t begin = s * i;
|
||||||
|
std::size_t end =
|
||||||
|
i == threadCount - 1 ?
|
||||||
|
currentSize :
|
||||||
|
s * (i + 1);
|
||||||
|
threads[i] = std::thread(
|
||||||
|
[this, &fn, &iterable, userPtr] (std::size_t begin, std::size_t end) {
|
||||||
|
bool isValid;
|
||||||
|
for(std::size_t i = begin; i < end; ++i) {
|
||||||
|
if(!std::get<bool>(this->entities[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid = true;
|
||||||
|
for(const auto& integralValue : iterable) {
|
||||||
|
if(!std::get<BitsetType>(entities[i]).getCombinedBit(integralValue)) {
|
||||||
|
isValid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!isValid) { continue; }
|
||||||
|
|
||||||
|
fn(i, this, userPtr);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
begin, end);
|
||||||
|
}
|
||||||
|
for(std::size_t i = 0; i < threadCount; ++i) {
|
||||||
|
threads[i].join();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,8 @@ using EmptyList = EC::Meta::TypeList<>;
|
||||||
|
|
||||||
using MixedList = EC::Meta::TypeList<C2, T1>;
|
using MixedList = EC::Meta::TypeList<C2, T1>;
|
||||||
|
|
||||||
|
using ListCombinedComponentsTags = EC::Meta::Combine<ListComponentsAll, ListTagsAll>;
|
||||||
|
|
||||||
typedef std::unique_ptr<C0> C0Ptr;
|
typedef std::unique_ptr<C0> C0Ptr;
|
||||||
|
|
||||||
struct Base
|
struct Base
|
||||||
|
@ -1074,3 +1076,266 @@ TEST(EC, FunctionStorageOrder)
|
||||||
EXPECT_EQ(5, v.at(4));
|
EXPECT_EQ(5, v.at(4));
|
||||||
EXPECT_EQ(6, v.at(5));
|
EXPECT_EQ(6, v.at(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(EC, forMatchingSimple) {
|
||||||
|
EC::Manager<ListComponentsAll, ListTagsAll> manager;
|
||||||
|
|
||||||
|
auto e0 = manager.addEntity();
|
||||||
|
manager.addComponent<C0>(e0, 0, 1);
|
||||||
|
|
||||||
|
auto e1 = manager.addEntity();
|
||||||
|
manager.addComponent<C0>(e1, 2, 3);
|
||||||
|
manager.addTag<T0>(e1);
|
||||||
|
|
||||||
|
auto e2 = manager.addEntity();
|
||||||
|
manager.addComponent<C0>(e2, 4, 5);
|
||||||
|
manager.addTag<T0>(e2);
|
||||||
|
manager.addTag<T1>(e2);
|
||||||
|
|
||||||
|
// add 10 to C0 components
|
||||||
|
manager.forMatchingSimple<EC::Meta::TypeList<C0>>(
|
||||||
|
[] (std::size_t id, decltype(manager) *manager, void *) {
|
||||||
|
C0 *c0 = manager->getEntityData<C0>(id);
|
||||||
|
c0->x += 10;
|
||||||
|
c0->y += 10;
|
||||||
|
}, nullptr, 3);
|
||||||
|
|
||||||
|
// verify
|
||||||
|
{
|
||||||
|
C0 *c0 = manager.getEntityData<C0>(e0);
|
||||||
|
EXPECT_EQ(c0->x, 10);
|
||||||
|
EXPECT_EQ(c0->y, 11);
|
||||||
|
c0 = manager.getEntityData<C0>(e1);
|
||||||
|
EXPECT_EQ(c0->x, 12);
|
||||||
|
EXPECT_EQ(c0->y, 13);
|
||||||
|
c0 = manager.getEntityData<C0>(e2);
|
||||||
|
EXPECT_EQ(c0->x, 14);
|
||||||
|
EXPECT_EQ(c0->y, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto e3 = manager.addEntity();
|
||||||
|
manager.addComponent<C0>(e3, 6, 7);
|
||||||
|
manager.addTag<T0>(e3);
|
||||||
|
manager.addTag<T1>(e3);
|
||||||
|
|
||||||
|
// add 100 to entities with C0,T1
|
||||||
|
manager.forMatchingSimple<EC::Meta::TypeList<C0, T1>>(
|
||||||
|
[] (std::size_t id, decltype(manager) *manager, void *) {
|
||||||
|
C0 *c0 = manager->getEntityData<C0>(id);
|
||||||
|
c0->x += 100;
|
||||||
|
c0->y += 100;
|
||||||
|
});
|
||||||
|
|
||||||
|
// verify
|
||||||
|
{
|
||||||
|
C0 *c0 = manager.getEntityData<C0>(e0);
|
||||||
|
EXPECT_EQ(c0->x, 10);
|
||||||
|
EXPECT_EQ(c0->y, 11);
|
||||||
|
c0 = manager.getEntityData<C0>(e1);
|
||||||
|
EXPECT_EQ(c0->x, 12);
|
||||||
|
EXPECT_EQ(c0->y, 13);
|
||||||
|
c0 = manager.getEntityData<C0>(e2);
|
||||||
|
EXPECT_EQ(c0->x, 114);
|
||||||
|
EXPECT_EQ(c0->y, 115);
|
||||||
|
c0 = manager.getEntityData<C0>(e3);
|
||||||
|
EXPECT_EQ(c0->x, 106);
|
||||||
|
EXPECT_EQ(c0->y, 107);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EC, forMatchingIterableFn)
|
||||||
|
{
|
||||||
|
EC::Manager<ListComponentsAll, ListTagsAll> manager;
|
||||||
|
auto e0 = manager.addEntity();
|
||||||
|
manager.addComponent<C0>(e0, 0, 1);
|
||||||
|
|
||||||
|
auto e1 = manager.addEntity();
|
||||||
|
manager.addComponent<C0>(e1, 2, 3);
|
||||||
|
manager.addTag<T0>(e1);
|
||||||
|
|
||||||
|
auto e2 = manager.addEntity();
|
||||||
|
manager.addComponent<C0>(e2, 4, 5);
|
||||||
|
manager.addTag<T0>(e2);
|
||||||
|
manager.addTag<T1>(e2);
|
||||||
|
|
||||||
|
auto c0Index = EC::Meta::IndexOf<C0, ListCombinedComponentsTags>::value;
|
||||||
|
auto c1Index = EC::Meta::IndexOf<C1, ListCombinedComponentsTags>::value;
|
||||||
|
auto t0Index = EC::Meta::IndexOf<T0, ListCombinedComponentsTags>::value;
|
||||||
|
auto t1Index = EC::Meta::IndexOf<T1, ListCombinedComponentsTags>::value;
|
||||||
|
|
||||||
|
{
|
||||||
|
// test valid indices
|
||||||
|
auto iterable = {c0Index};
|
||||||
|
auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
|
||||||
|
auto* c = m->getEntityComponent<C0>(i);
|
||||||
|
c->x += 1;
|
||||||
|
c->y += 1;
|
||||||
|
};
|
||||||
|
manager.forMatchingIterable(iterable, fn, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto* c = manager.getEntityComponent<C0>(e0);
|
||||||
|
EXPECT_EQ(c->x, 1);
|
||||||
|
EXPECT_EQ(c->y, 2);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e1);
|
||||||
|
EXPECT_EQ(c->x, 3);
|
||||||
|
EXPECT_EQ(c->y, 4);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e2);
|
||||||
|
EXPECT_EQ(c->x, 5);
|
||||||
|
EXPECT_EQ(c->y, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// test invalid indices
|
||||||
|
auto iterable = {c0Index, c1Index};
|
||||||
|
auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
|
||||||
|
auto* c = m->getEntityComponent<C0>(i);
|
||||||
|
c->x += 1;
|
||||||
|
c->y += 1;
|
||||||
|
};
|
||||||
|
manager.forMatchingIterable(iterable, fn, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto* c = manager.getEntityComponent<C0>(e0);
|
||||||
|
EXPECT_EQ(c->x, 1);
|
||||||
|
EXPECT_EQ(c->y, 2);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e1);
|
||||||
|
EXPECT_EQ(c->x, 3);
|
||||||
|
EXPECT_EQ(c->y, 4);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e2);
|
||||||
|
EXPECT_EQ(c->x, 5);
|
||||||
|
EXPECT_EQ(c->y, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// test partially valid indices
|
||||||
|
auto iterable = {c0Index, t1Index};
|
||||||
|
auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
|
||||||
|
auto* c = m->getEntityComponent<C0>(i);
|
||||||
|
c->x += 1;
|
||||||
|
c->y += 1;
|
||||||
|
};
|
||||||
|
manager.forMatchingIterable(iterable, fn, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto* c = manager.getEntityComponent<C0>(e0);
|
||||||
|
EXPECT_EQ(c->x, 1);
|
||||||
|
EXPECT_EQ(c->y, 2);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e1);
|
||||||
|
EXPECT_EQ(c->x, 3);
|
||||||
|
EXPECT_EQ(c->y, 4);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e2);
|
||||||
|
EXPECT_EQ(c->x, 6);
|
||||||
|
EXPECT_EQ(c->y, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// test partially valid indices
|
||||||
|
auto iterable = {c0Index, t0Index};
|
||||||
|
auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
|
||||||
|
auto* c = m->getEntityComponent<C0>(i);
|
||||||
|
c->x += 10;
|
||||||
|
c->y += 10;
|
||||||
|
};
|
||||||
|
manager.forMatchingIterable(iterable, fn, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto* c = manager.getEntityComponent<C0>(e0);
|
||||||
|
EXPECT_EQ(c->x, 1);
|
||||||
|
EXPECT_EQ(c->y, 2);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e1);
|
||||||
|
EXPECT_EQ(c->x, 13);
|
||||||
|
EXPECT_EQ(c->y, 14);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e2);
|
||||||
|
EXPECT_EQ(c->x, 16);
|
||||||
|
EXPECT_EQ(c->y, 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// test invalid indices
|
||||||
|
auto iterable = {(unsigned int)c0Index, 1000u};
|
||||||
|
auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
|
||||||
|
auto* c = m->getEntityComponent<C0>(i);
|
||||||
|
c->x += 1000;
|
||||||
|
c->y += 1000;
|
||||||
|
};
|
||||||
|
manager.forMatchingIterable(iterable, fn, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto* c = manager.getEntityComponent<C0>(e0);
|
||||||
|
EXPECT_EQ(c->x, 1);
|
||||||
|
EXPECT_EQ(c->y, 2);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e1);
|
||||||
|
EXPECT_EQ(c->x, 13);
|
||||||
|
EXPECT_EQ(c->y, 14);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e2);
|
||||||
|
EXPECT_EQ(c->x, 16);
|
||||||
|
EXPECT_EQ(c->y, 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// test concurrent update
|
||||||
|
auto iterable = {c0Index};
|
||||||
|
auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
|
||||||
|
auto *c = m->getEntityComponent<C0>(i);
|
||||||
|
c->x += 100;
|
||||||
|
c->y += 100;
|
||||||
|
};
|
||||||
|
manager.forMatchingIterable(iterable, fn, nullptr, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto* c = manager.getEntityComponent<C0>(e0);
|
||||||
|
EXPECT_EQ(c->x, 101);
|
||||||
|
EXPECT_EQ(c->y, 102);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e1);
|
||||||
|
EXPECT_EQ(c->x, 113);
|
||||||
|
EXPECT_EQ(c->y, 114);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e2);
|
||||||
|
EXPECT_EQ(c->x, 116);
|
||||||
|
EXPECT_EQ(c->y, 117);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
// test invalid concurrent update
|
||||||
|
auto iterable = {(unsigned int)c0Index, 1000u};
|
||||||
|
auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
|
||||||
|
auto *c = m->getEntityComponent<C0>(i);
|
||||||
|
c->x += 1000;
|
||||||
|
c->y += 1000;
|
||||||
|
};
|
||||||
|
manager.forMatchingIterable(iterable, fn, nullptr, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto* c = manager.getEntityComponent<C0>(e0);
|
||||||
|
EXPECT_EQ(c->x, 101);
|
||||||
|
EXPECT_EQ(c->y, 102);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e1);
|
||||||
|
EXPECT_EQ(c->x, 113);
|
||||||
|
EXPECT_EQ(c->y, 114);
|
||||||
|
|
||||||
|
c = manager.getEntityComponent<C0>(e2);
|
||||||
|
EXPECT_EQ(c->x, 116);
|
||||||
|
EXPECT_EQ(c->y, 117);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue