Add fn to Manager allowing iterable indices as sig
As an alternative to forMatchingSignatures, which calls the given function on entities matching the given Components/Tags in the signature, forMatchingIterable allows filtering entities by an iterable of indices that corresponds to Components/Tags.
This commit is contained in:
parent
50a84f5c8c
commit
4db5e0caed
3 changed files with 288 additions and 0 deletions
|
@ -75,6 +75,28 @@ namespace EC
|
|||
|
||||
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];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1649,6 +1649,73 @@ namespace EC
|
|||
deletedSet.clear();
|
||||
resize(EC_INIT_ENTITIES_SIZE);
|
||||
}
|
||||
|
||||
typedef void ForMatchingIterableFn(std::size_t, Manager<ComponentsList, TagsList>*, void*);
|
||||
|
||||
/*!
|
||||
* \brief Similar to forMatchingSignature(), but with a collection of Component/Tag indices
|
||||
*
|
||||
* This function works like forMatchingSignature(), but instead of
|
||||
* providing template types that filter out non-matching entities, an
|
||||
* iterable of indices must be provided which correlate to matching
|
||||
* Component/Tag indices. The function given must match the previously
|
||||
* defined typedef of type ForMatchingIterableFn.
|
||||
*/
|
||||
template <typename Iterable>
|
||||
void forMatchingIterable(Iterable iterable, ForMatchingIterableFn 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} 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 ListCombinedComponentsTags = EC::Meta::Combine<ListComponentsAll, ListTagsAll>;
|
||||
|
||||
typedef std::unique_ptr<C0> C0Ptr;
|
||||
|
||||
struct Base
|
||||
|
@ -1074,3 +1076,200 @@ TEST(EC, FunctionStorageOrder)
|
|||
EXPECT_EQ(5, v.at(4));
|
||||
EXPECT_EQ(6, v.at(5));
|
||||
}
|
||||
|
||||
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