Merge branch 'master' into cxx17

This commit is contained in:
Stephen Seo 2021-09-07 18:16:29 +09:00
commit 155df42657
2 changed files with 288 additions and 185 deletions

View file

@ -58,7 +58,9 @@ namespace EC
EC::Manager<TypeList<C0, C1, C2>, TypeList<T0, T1>> manager; EC::Manager<TypeList<C0, C1, C2>, TypeList<T0, T1>> manager;
\endcode \endcode
*/ */
template <typename ComponentsList, typename TagsList, unsigned int ThreadCount = 4> template <typename ComponentsList,
typename TagsList,
unsigned int ThreadCount = 4>
struct Manager struct Manager
{ {
public: public:
@ -93,6 +95,72 @@ namespace EC
std::unique_ptr<ThreadPool<ThreadCount> > threadPool; std::unique_ptr<ThreadPool<ThreadCount> > threadPool;
public: public:
// section for "temporary" structures {{{
struct TPFnDataStructZero {
std::array<std::size_t, 2> range;
Manager *manager;
EntitiesType *entities;
const BitsetType *signature;
void *userData;
};
template <typename Function>
struct TPFnDataStructOne {
std::array<std::size_t, 2> range;
Manager *manager;
EntitiesType *entities;
BitsetType *signature;
void *userData;
Function *fn;
};
struct TPFnDataStructTwo {
std::array<std::size_t, 2> range;
Manager *manager;
EntitiesType *entities;
void *userData;
const std::vector<std::size_t> *matching;
};
struct TPFnDataStructThree {
std::array<std::size_t, 2> range;
Manager *manager;
std::vector<std::vector<std::size_t> > *matchingV;
const std::vector<BitsetType*> *bitsets;
EntitiesType *entities;
std::mutex *mutex;
};
struct TPFnDataStructFour {
std::array<std::size_t, 2> range;
Manager *manager;
std::vector<std::vector<std::size_t> >*
multiMatchingEntities;
BitsetType *signatures;
std::mutex *mutex;
};
struct TPFnDataStructFive {
std::array<std::size_t, 2> range;
std::size_t index;
Manager *manager;
void *userData;
std::vector<std::vector<std::size_t> >*
multiMatchingEntities;
};
struct TPFnDataStructSix {
std::array<std::size_t, 2> range;
Manager *manager;
std::vector<std::vector<std::size_t> > *
multiMatchingEntities;
BitsetType *bitsets;
std::mutex *mutex;
};
template <typename Iterable>
struct TPFnDataStructSeven {
std::array<std::size_t, 2> range;
Manager *manager;
EntitiesType *entities;
Iterable *iterable;
void *userData;
};
// end section for "temporary" structures }}}
/*! /*!
\brief Initializes the manager with a default capacity. \brief Initializes the manager with a default capacity.
@ -656,8 +724,7 @@ namespace EC
} }
else else
{ {
using TPFnDataType = std::tuple<Manager*, EntitiesType*, BitsetType*, std::array<std::size_t, 2>, void*>; std::array<TPFnDataStructZero, ThreadCount> fnDataAr;
std::array<TPFnDataType, ThreadCount> fnDataAr;
std::size_t s = currentSize / ThreadCount; std::size_t s = currentSize / ThreadCount;
for(std::size_t i = 0; i < ThreadCount; ++i) { for(std::size_t i = 0; i < ThreadCount; ++i) {
@ -671,33 +738,37 @@ namespace EC
if(begin == end) { if(begin == end) {
continue; continue;
} }
std::get<0>(fnDataAr.at(i)) = this; fnDataAr[i].range = {begin, end};
std::get<1>(fnDataAr.at(i)) = &entities; fnDataAr[i].manager = this;
std::get<2>(fnDataAr.at(i)) = &signatureBitset; fnDataAr[i].entities = &entities;
std::get<3>(fnDataAr.at(i)) = {begin, end}; fnDataAr[i].signature = &signatureBitset;
std::get<4>(fnDataAr.at(i)) = userData; fnDataAr[i].userData = userData;
threadPool->queueFn([&function] (void *ud) { threadPool->queueFn([&function] (void *ud) {
auto *data = static_cast<TPFnDataType*>(ud); auto *data = static_cast<TPFnDataStructZero*>(ud);
for(std::size_t i = std::get<3>(*data).at(0); for(std::size_t i = data->range[0]; i < data->range[1];
i < std::get<3>(*data).at(1);
++i) { ++i) {
if(!std::get<0>(*data)->isAlive(i)) { if(!data->manager->isAlive(i)) {
continue; continue;
} }
if((*std::get<2>(*data) if(((*data->signature)
& std::get<BitsetType>( & std::get<BitsetType>(
std::get<1>(*data)->at(i))) data->entities->at(i)))
== *std::get<2>(*data)) { == *data->signature) {
Helper::call(i, *std::get<0>(*data), std::forward<Function>(function), std::get<4>(*data)); Helper::call(i,
*data->manager,
std::forward<Function>(function),
data->userData);
} }
} }
}, &fnDataAr.at(i)); }, &fnDataAr[i]);
} }
threadPool->wakeThreads(); threadPool->wakeThreads();
do { do {
std::this_thread::sleep_for(std::chrono::microseconds(200)); std::this_thread::sleep_for(std::chrono::microseconds(200));
} while(!threadPool->isQueueEmpty() || !threadPool->isAllThreadsWaiting()); } while(!threadPool->isQueueEmpty()
|| !threadPool->isAllThreadsWaiting());
} }
} }
@ -774,8 +845,7 @@ namespace EC
} }
else else
{ {
using TPFnDataType = std::tuple<Manager*, EntitiesType*, BitsetType*, std::array<std::size_t, 2>, void*, Function*>; std::array<TPFnDataStructOne<Function>, ThreadCount> fnDataAr;
std::array<TPFnDataType, ThreadCount> fnDataAr;
std::size_t s = currentSize / ThreadCount; std::size_t s = currentSize / ThreadCount;
for(std::size_t i = 0; i < ThreadCount; ++i) { for(std::size_t i = 0; i < ThreadCount; ++i) {
@ -789,34 +859,37 @@ namespace EC
if(begin == end) { if(begin == end) {
continue; continue;
} }
std::get<0>(fnDataAr.at(i)) = this; fnDataAr[i].range = {begin, end};
std::get<1>(fnDataAr.at(i)) = &entities; fnDataAr[i].manager = this;
std::get<2>(fnDataAr.at(i)) = &signatureBitset; fnDataAr[i].entities = &entities;
std::get<3>(fnDataAr.at(i)) = {begin, end}; fnDataAr[i].signature = &signatureBitset;
std::get<4>(fnDataAr.at(i)) = userData; fnDataAr[i].userData = userData;
std::get<5>(fnDataAr.at(i)) = function; fnDataAr[i].fn = function;
threadPool->queueFn([] (void *ud) { threadPool->queueFn([] (void *ud) {
auto *data = static_cast<TPFnDataType*>(ud); auto *data = static_cast<TPFnDataStructOne<Function>*>(ud);
for(std::size_t i = std::get<3>(*data).at(0); for(std::size_t i = data->range[0]; i < data->range[1];
i < std::get<3>(*data).at(1);
++i) { ++i) {
if(!std::get<0>(*data)->isAlive(i)) { if(!data->manager->isAlive(i)) {
continue; continue;
} }
if((*std::get<2>(*data) if(((*data->signature)
& std::get<BitsetType>( & std::get<BitsetType>(
std::get<1>(*data)->at(i))) data->entities->at(i)))
== *std::get<2>(*data)) { == *data->signature) {
Helper::callPtr(i, *std::get<0>(*data), std::get<5>(*data), std::get<4>(*data)); Helper::callPtr(i,
*data->manager,
data->fn,
data->userData);
} }
} }
}, &fnDataAr.at(i)); }, &fnDataAr[i]);
} }
threadPool->wakeThreads(); threadPool->wakeThreads();
do { do {
std::this_thread::sleep_for(std::chrono::microseconds(200)); std::this_thread::sleep_for(std::chrono::microseconds(200));
} while(!threadPool->isQueueEmpty() || !threadPool->isAllThreadsWaiting()); } while(!threadPool->isQueueEmpty()
|| !threadPool->isAllThreadsWaiting());
} }
} }
@ -922,8 +995,7 @@ namespace EC
} }
else else
{ {
using TPFnDataType = std::tuple<Manager*, EntitiesType*, std::array<std::size_t, 2>, void*, const std::vector<std::size_t>*>; std::array<TPFnDataStructTwo, ThreadCount> fnDataAr;
std::array<TPFnDataType, ThreadCount> fnDataAr;
std::size_t s = matching.size() / ThreadCount; std::size_t s = matching.size() / ThreadCount;
for(std::size_t i = 0; i < ThreadCount; ++i) { for(std::size_t i = 0; i < ThreadCount; ++i) {
@ -937,30 +1009,33 @@ namespace EC
if(begin == end) { if(begin == end) {
continue; continue;
} }
std::get<0>(fnDataAr.at(i)) = this; fnDataAr[i].range = {begin, end};
std::get<1>(fnDataAr.at(i)) = &entities; fnDataAr[i].manager = this;
std::get<2>(fnDataAr.at(i)) = {begin, end}; fnDataAr[i].entities = &entities;
std::get<3>(fnDataAr.at(i)) = userData; fnDataAr[i].userData = userData;
std::get<4>(fnDataAr.at(i)) = &matching; fnDataAr[i].matching = &matching;
threadPool->queueFn([function, helper] (void* ud) { threadPool->queueFn([&function, helper] (void* ud) {
auto *data = static_cast<TPFnDataType*>(ud); auto *data = static_cast<TPFnDataStructTwo*>(ud);
for(std::size_t i = std::get<2>(*data).at(0); for(std::size_t i = data->range[0];
i < std::get<2>(*data).at(1); i < data->range[1];
++i) { ++i) {
if(std::get<0>(*data)->isAlive(std::get<4>(*data)->at(i))) { if(data->manager->isAlive(
data->matching->at(i))) {
helper.callInstancePtr( helper.callInstancePtr(
std::get<4>(*data)->at(i), data->matching->at(i),
*std::get<0>(*data), *data->manager,
&function, &function,
std::get<3>(*data)); data->userData);
} }
} }
}, &fnDataAr.at(i)); }, &fnDataAr[i]);
} }
threadPool->wakeThreads(); threadPool->wakeThreads();
do { do {
std::this_thread::sleep_for(std::chrono::microseconds(200)); std::this_thread::sleep_for(
} while(!threadPool->isQueueEmpty() || !threadPool->isAllThreadsWaiting()); std::chrono::microseconds(200));
} while(!threadPool->isQueueEmpty()
|| !threadPool->isAllThreadsWaiting());
} }
}))); })));
@ -993,8 +1068,7 @@ namespace EC
} }
else else
{ {
using TPFnDataType = std::tuple<Manager*, std::array<std::size_t, 2>, std::vector<std::vector<std::size_t> >*, const std::vector<BitsetType*>*, EntitiesType*, std::mutex*>; std::array<TPFnDataStructThree, ThreadCount> fnDataAr;
std::array<TPFnDataType, ThreadCount> fnDataAr;
std::size_t s = currentSize / ThreadCount; std::size_t s = currentSize / ThreadCount;
std::mutex mutex; std::mutex mutex;
@ -1009,37 +1083,38 @@ namespace EC
if(begin == end) { if(begin == end) {
continue; continue;
} }
std::get<0>(fnDataAr.at(i)) = this; fnDataAr[i].range = {begin, end};
std::get<1>(fnDataAr.at(i)) = {begin, end}; fnDataAr[i].manager = this;
std::get<2>(fnDataAr.at(i)) = &matchingV; fnDataAr[i].matchingV = &matchingV;
std::get<3>(fnDataAr.at(i)) = &bitsets; fnDataAr[i].bitsets = &bitsets;
std::get<4>(fnDataAr.at(i)) = &entities; fnDataAr[i].entities = &entities;
std::get<5>(fnDataAr.at(i)) = &mutex; fnDataAr[i].mutex = &mutex;
threadPool->queueFn([] (void *ud) { threadPool->queueFn([] (void *ud) {
auto *data = static_cast<TPFnDataType*>(ud); auto *data = static_cast<TPFnDataStructThree*>(ud);
for(std::size_t i = std::get<1>(*data).at(0); for(std::size_t i = data->range[0]; i < data->range[1];
i < std::get<1>(*data).at(1);
++i) { ++i) {
if(!std::get<0>(*data)->isAlive(i)) { if(!data->manager->isAlive(i)) {
continue; continue;
} }
for(std::size_t j = 0; for(std::size_t j = 0; j < data->bitsets->size();
j < std::get<3>(*data)->size();
++j) { ++j) {
if(((*std::get<3>(*data)->at(j)) if((*data->bitsets->at(j)
& std::get<BitsetType>(std::get<4>(*data)->at(i))) & std::get<BitsetType>(
== (*std::get<3>(*data)->at(j))) { data->entities->at(i)))
std::lock_guard<std::mutex> lock(*std::get<5>(*data)); == *data->bitsets->at(j)) {
std::get<2>(*data)->at(j).push_back(i); std::lock_guard<std::mutex> lock(
*data->mutex);
data->matchingV->at(j).push_back(i);
} }
} }
} }
}, &fnDataAr.at(i)); }, &fnDataAr[i]);
} }
threadPool->wakeThreads(); threadPool->wakeThreads();
do { do {
std::this_thread::sleep_for(std::chrono::microseconds(200)); std::this_thread::sleep_for(std::chrono::microseconds(200));
} while(!threadPool->isQueueEmpty() || !threadPool->isAllThreadsWaiting()); } while(!threadPool->isQueueEmpty()
|| !threadPool->isAllThreadsWaiting());
} }
return matchingV; return matchingV;
@ -1383,8 +1458,7 @@ namespace EC
} }
else else
{ {
using TPFnDataType = std::tuple<Manager*, std::array<std::size_t, 2>, std::vector<std::vector<std::size_t> >*, BitsetType*, std::mutex*>; std::array<TPFnDataStructFour, ThreadCount> fnDataAr;
std::array<TPFnDataType, ThreadCount> fnDataAr;
std::mutex mutex; std::mutex mutex;
std::size_t s = currentSize / ThreadCount; std::size_t s = currentSize / ThreadCount;
@ -1399,34 +1473,38 @@ namespace EC
if(begin == end) { if(begin == end) {
continue; continue;
} }
std::get<0>(fnDataAr.at(i)) = this; fnDataAr[i].range = {begin, end};
std::get<1>(fnDataAr.at(i)) = {begin, end}; fnDataAr[i].manager = this;
std::get<2>(fnDataAr.at(i)) = &multiMatchingEntities; fnDataAr[i].multiMatchingEntities = &multiMatchingEntities;
std::get<3>(fnDataAr.at(i)) = signatureBitsets; fnDataAr[i].signatures = signatureBitsets;
std::get<4>(fnDataAr.at(i)) = &mutex; fnDataAr[i].mutex = &mutex;
threadPool->queueFn([] (void *ud) { threadPool->queueFn([] (void *ud) {
auto *data = static_cast<TPFnDataType*>(ud); auto *data = static_cast<TPFnDataStructFour*>(ud);
for(std::size_t i = std::get<1>(*data).at(0); for(std::size_t i = data->range[0]; i < data->range[1];
i < std::get<1>(*data).at(1);
++i) { ++i) {
if(!std::get<0>(*data)->isAlive(i)) { if(!data->manager->isAlive(i)) {
continue; continue;
} }
for(std::size_t j = 0; j < SigList::size; ++j) { for(std::size_t j = 0; j < SigList::size; ++j) {
if((std::get<3>(*data)[j] & std::get<BitsetType>(std::get<0>(*data)->entities[i])) if((data->signatures[j]
== std::get<3>(*data)[j]) { & std::get<BitsetType>(
std::lock_guard<std::mutex> lock(*std::get<4>(*data)); data->manager->entities[i]))
std::get<2>(*data)->at(j).push_back(i); == data->signatures[j]) {
std::lock_guard<std::mutex> lock(
*data->mutex);
data->multiMatchingEntities->at(j)
.push_back(i);
} }
} }
} }
}, &fnDataAr.at(i)); }, &fnDataAr[i]);
} }
threadPool->wakeThreads(); threadPool->wakeThreads();
do { do {
std::this_thread::sleep_for(std::chrono::microseconds(200)); std::this_thread::sleep_for(std::chrono::microseconds(200));
} while(!threadPool->isQueueEmpty() || !threadPool->isAllThreadsWaiting()); } while(!threadPool->isQueueEmpty()
|| !threadPool->isAllThreadsWaiting());
} }
// call functions on matching entities // call functions on matching entities
@ -1450,8 +1528,7 @@ namespace EC
} }
} }
} else { } else {
using TPFnType = std::tuple<Manager*, void*, std::array<std::size_t, 2>, std::vector<std::vector<std::size_t> > *, std::size_t>; std::array<TPFnDataStructFive, ThreadCount> fnDataAr;
std::array<TPFnType, ThreadCount> fnDataAr;
std::size_t s = multiMatchingEntities[index].size() std::size_t s = multiMatchingEntities[index].size()
/ ThreadCount; / ThreadCount;
for(unsigned int i = 0; i < ThreadCount; ++i) { for(unsigned int i = 0; i < ThreadCount; ++i) {
@ -1465,30 +1542,35 @@ namespace EC
if(begin == end) { if(begin == end) {
continue; continue;
} }
std::get<0>(fnDataAr.at(i)) = this; fnDataAr[i].range = {begin, end};
std::get<1>(fnDataAr.at(i)) = userData; fnDataAr[i].index = index;
std::get<2>(fnDataAr.at(i)) = {begin, end}; fnDataAr[i].manager = this;
std::get<3>(fnDataAr.at(i)) = &multiMatchingEntities; fnDataAr[i].userData = userData;
std::get<4>(fnDataAr.at(i)) = index; fnDataAr[i].multiMatchingEntities =
&multiMatchingEntities;
threadPool->queueFn([&func] (void *ud) { threadPool->queueFn([&func] (void *ud) {
auto *data = static_cast<TPFnType*>(ud); auto *data = static_cast<TPFnDataStructFive*>(ud);
for(std::size_t i = std::get<2>(*data).at(0); for(std::size_t i = data->range[0];
i < std::get<2>(*data).at(1); i < data->range[1]; ++i) {
++i) { if(data->manager->isAlive(
if(std::get<0>(*data)->isAlive(std::get<3>(*data)->at(std::get<4>(*data)).at(i))) { data->multiMatchingEntities
->at(data->index).at(i))) {
Helper::call( Helper::call(
std::get<3>(*data)->at(std::get<4>(*data)).at(i), data->multiMatchingEntities
*std::get<0>(*data), ->at(data->index).at(i),
*data->manager,
func, func,
std::get<1>(*data)); data->userData);
} }
} }
}, &fnDataAr.at(i)); }, &fnDataAr[i]);
} }
threadPool->wakeThreads(); threadPool->wakeThreads();
do { do {
std::this_thread::sleep_for(std::chrono::microseconds(200)); std::this_thread::sleep_for(
} while(!threadPool->isQueueEmpty() || !threadPool->isAllThreadsWaiting()); std::chrono::microseconds(200));
} while(!threadPool->isQueueEmpty()
|| !threadPool->isAllThreadsWaiting());
} }
} }
); );
@ -1584,8 +1666,7 @@ namespace EC
} }
else else
{ {
using TPFnDataType = std::tuple<Manager*, std::array<std::size_t, 2>, std::vector<std::vector<std::size_t> >*, BitsetType*, std::mutex*>; std::array<TPFnDataStructSix, ThreadCount> fnDataAr;
std::array<TPFnDataType, ThreadCount> fnDataAr;
std::mutex mutex; std::mutex mutex;
std::size_t s = currentSize / ThreadCount; std::size_t s = currentSize / ThreadCount;
@ -1600,34 +1681,38 @@ namespace EC
if(begin == end) { if(begin == end) {
continue; continue;
} }
std::get<0>(fnDataAr.at(i)) = this; fnDataAr[i].range = {begin, end};
std::get<1>(fnDataAr.at(i)) = {begin, end}; fnDataAr[i].manager = this;
std::get<2>(fnDataAr.at(i)) = &multiMatchingEntities; fnDataAr[i].multiMatchingEntities = &multiMatchingEntities;
std::get<3>(fnDataAr.at(i)) = signatureBitsets; fnDataAr[i].bitsets = signatureBitsets;
std::get<4>(fnDataAr.at(i)) = &mutex; fnDataAr[i].mutex = &mutex;
threadPool->queueFn([] (void *ud) { threadPool->queueFn([] (void *ud) {
auto *data = static_cast<TPFnDataType*>(ud); auto *data = static_cast<TPFnDataStructSix*>(ud);
for(std::size_t i = std::get<1>(*data).at(0); for(std::size_t i = data->range[0]; i < data->range[1];
i < std::get<1>(*data).at(1);
++i) { ++i) {
if(!std::get<0>(*data)->isAlive(i)) { if(!data->manager->isAlive(i)) {
continue; continue;
} }
for(std::size_t j = 0; j < SigList::size; ++j) { for(std::size_t j = 0; j < SigList::size; ++j) {
if((std::get<3>(*data)[j] & std::get<BitsetType>(std::get<0>(*data)->entities[i])) if((data->bitsets[j]
== std::get<3>(*data)[j]) { & std::get<BitsetType>(
std::lock_guard<std::mutex> lock(*std::get<4>(*data)); data->manager->entities[i]))
std::get<2>(*data)->at(j).push_back(i); == data->bitsets[j]) {
std::lock_guard<std::mutex> lock(
*data->mutex);
data->multiMatchingEntities->at(j)
.push_back(i);
} }
} }
} }
}, &fnDataAr.at(i)); }, &fnDataAr[i]);
} }
threadPool->wakeThreads(); threadPool->wakeThreads();
do { do {
std::this_thread::sleep_for(std::chrono::microseconds(200)); std::this_thread::sleep_for(std::chrono::microseconds(200));
} while(!threadPool->isQueueEmpty() || !threadPool->isAllThreadsWaiting()); } while(!threadPool->isQueueEmpty()
|| !threadPool->isAllThreadsWaiting());
} }
// call functions on matching entities // call functions on matching entities
@ -1656,8 +1741,7 @@ namespace EC
} }
else else
{ {
using TPFnType = std::tuple<Manager*, void*, std::array<std::size_t, 2>, std::vector<std::vector<std::size_t> > *, std::size_t>; std::array<TPFnDataStructFive, ThreadCount> fnDataAr;
std::array<TPFnType, ThreadCount> fnDataAr;
std::size_t s = multiMatchingEntities[index].size() std::size_t s = multiMatchingEntities[index].size()
/ ThreadCount; / ThreadCount;
for(unsigned int i = 0; i < ThreadCount; ++i) { for(unsigned int i = 0; i < ThreadCount; ++i) {
@ -1671,36 +1755,43 @@ namespace EC
if(begin == end) { if(begin == end) {
continue; continue;
} }
std::get<0>(fnDataAr.at(i)) = this; fnDataAr[i].range = {begin, end};
std::get<1>(fnDataAr.at(i)) = userData; fnDataAr[i].index = index;
std::get<2>(fnDataAr.at(i)) = {begin, end}; fnDataAr[i].manager = this;
std::get<3>(fnDataAr.at(i)) = &multiMatchingEntities; fnDataAr[i].userData = userData;
std::get<4>(fnDataAr.at(i)) = index; fnDataAr[i].multiMatchingEntities =
&multiMatchingEntities;
threadPool->queueFn([&func] (void *ud) { threadPool->queueFn([&func] (void *ud) {
auto *data = static_cast<TPFnType*>(ud); auto *data = static_cast<TPFnDataStructFive*>(ud);
for(std::size_t i = std::get<2>(*data).at(0); for(std::size_t i = data->range[0];
i < std::get<2>(*data).at(1); i < data->range[1]; ++i) {
++i) { if(data->manager->isAlive(
if(std::get<0>(*data)->isAlive(std::get<3>(*data)->at(std::get<4>(*data)).at(i))) { data->multiMatchingEntities
->at(data->index).at(i))) {
Helper::callPtr( Helper::callPtr(
std::get<3>(*data)->at(std::get<4>(*data)).at(i), data->multiMatchingEntities
*std::get<0>(*data), ->at(data->index).at(i),
*data->manager,
func, func,
std::get<1>(*data)); data->userData);
} }
} }
}, &fnDataAr.at(i)); }, &fnDataAr[i]);
} }
threadPool->wakeThreads(); threadPool->wakeThreads();
do { do {
std::this_thread::sleep_for(std::chrono::microseconds(200)); std::this_thread::sleep_for(
} while(!threadPool->isQueueEmpty() || !threadPool->isAllThreadsWaiting()); std::chrono::microseconds(200));
} while(!threadPool->isQueueEmpty()
|| !threadPool->isAllThreadsWaiting());
} }
} }
); );
} }
typedef void ForMatchingFn(std::size_t, Manager<ComponentsList, TagsList>*, void*); typedef void ForMatchingFn(std::size_t,
Manager<ComponentsList, TagsList>*,
void*);
/*! /*!
\brief A simple version of forMatchingSignature() \brief A simple version of forMatchingSignature()
@ -1720,19 +1811,23 @@ namespace EC
may not have as great of a speed-up. may not have as great of a speed-up.
*/ */
template <typename Signature> template <typename Signature>
void forMatchingSimple(ForMatchingFn fn, void *userData = nullptr, const bool useThreadPool = false) { void forMatchingSimple(ForMatchingFn fn,
const BitsetType signatureBitset = BitsetType::template generateBitset<Signature>(); void *userData = nullptr,
const bool useThreadPool = false) {
const BitsetType signatureBitset =
BitsetType::template generateBitset<Signature>();
if(!useThreadPool || !threadPool) { if(!useThreadPool || !threadPool) {
for(std::size_t i = 0; i < currentSize; ++i) { for(std::size_t i = 0; i < currentSize; ++i) {
if(!std::get<bool>(entities[i])) { if(!std::get<bool>(entities[i])) {
continue; continue;
} else if((signatureBitset & std::get<BitsetType>(entities[i])) == signatureBitset) { } else if((signatureBitset
& std::get<BitsetType>(entities[i]))
== signatureBitset) {
fn(i, this, userData); fn(i, this, userData);
} }
} }
} else { } else {
using TPFnDataType = std::tuple<Manager*, EntitiesType*, const BitsetType*, std::array<std::size_t, 2>, void*>; std::array<TPFnDataStructZero, ThreadCount> fnDataAr;
std::array<TPFnDataType, ThreadCount> fnDataAr;
std::size_t s = currentSize / ThreadCount; std::size_t s = currentSize / ThreadCount;
for(std::size_t i = 0; i < ThreadCount; ++i) { for(std::size_t i = 0; i < ThreadCount; ++i) {
@ -1746,28 +1841,31 @@ namespace EC
if(begin == end) { if(begin == end) {
continue; continue;
} }
std::get<0>(fnDataAr.at(i)) = this; fnDataAr[i].range = {begin, end};
std::get<1>(fnDataAr.at(i)) = &entities; fnDataAr[i].manager = this;
std::get<2>(fnDataAr.at(i)) = &signatureBitset; fnDataAr[i].entities = &entities;
std::get<3>(fnDataAr.at(i)) = {begin, end}; fnDataAr[i].signature = &signatureBitset;
std::get<4>(fnDataAr.at(i)) = userData; fnDataAr[i].userData = userData;
threadPool->queueFn([&fn] (void *ud) { threadPool->queueFn([&fn] (void *ud) {
auto *data = static_cast<TPFnDataType*>(ud); auto *data = static_cast<TPFnDataStructZero*>(ud);
for(std::size_t i = std::get<3>(*data).at(0); for(std::size_t i = data->range[0]; i < data->range[1];
i < std::get<3>(*data).at(1);
++i) { ++i) {
if(!std::get<0>(*data)->isAlive(i)) { if(!data->manager->isAlive(i)) {
continue; continue;
} else if((*std::get<2>(*data) & std::get<BitsetType>(std::get<1>(*data)->at(i))) == *std::get<2>(*data)) { } else if((*data->signature
fn(i, std::get<0>(*data), std::get<4>(*data)); & std::get<BitsetType>(
data->entities->at(i)))
== *data->signature) {
fn(i, data->manager, data->userData);
} }
} }
}, &fnDataAr.at(i)); }, &fnDataAr[i]);
} }
threadPool->wakeThreads(); threadPool->wakeThreads();
do { do {
std::this_thread::sleep_for(std::chrono::microseconds(200)); std::this_thread::sleep_for(std::chrono::microseconds(200));
} while(!threadPool->isQueueEmpty() || !threadPool->isAllThreadsWaiting()); } while(!threadPool->isQueueEmpty()
|| !threadPool->isAllThreadsWaiting());
} }
} }
@ -1790,7 +1888,10 @@ namespace EC
may not have as great of a speed-up. may not have as great of a speed-up.
*/ */
template <typename Iterable> template <typename Iterable>
void forMatchingIterable(Iterable iterable, ForMatchingFn fn, void* userData = nullptr, const bool useThreadPool = false) { void forMatchingIterable(Iterable iterable,
ForMatchingFn fn,
void* userData = nullptr,
const bool useThreadPool = false) {
if(!useThreadPool || !threadPool) { if(!useThreadPool || !threadPool) {
bool isValid; bool isValid;
for(std::size_t i = 0; i < currentSize; ++i) { for(std::size_t i = 0; i < currentSize; ++i) {
@ -1800,7 +1901,8 @@ namespace EC
isValid = true; isValid = true;
for(const auto& integralValue : iterable) { for(const auto& integralValue : iterable) {
if(!std::get<BitsetType>(entities[i]).getCombinedBit(integralValue)) { if(!std::get<BitsetType>(entities[i]).getCombinedBit(
integralValue)) {
isValid = false; isValid = false;
break; break;
} }
@ -1810,8 +1912,7 @@ namespace EC
fn(i, this, userData); fn(i, this, userData);
} }
} else { } else {
using TPFnDataType = std::tuple<Manager*, EntitiesType*, Iterable*, std::array<std::size_t, 2>, void*>; std::array<TPFnDataStructSeven<Iterable>, ThreadCount> fnDataAr;
std::array<TPFnDataType, ThreadCount> fnDataAr;
std::size_t s = currentSize / ThreadCount; std::size_t s = currentSize / ThreadCount;
for(std::size_t i = 0; i < ThreadCount; ++i) { for(std::size_t i = 0; i < ThreadCount; ++i) {
@ -1825,38 +1926,38 @@ namespace EC
if(begin == end) { if(begin == end) {
continue; continue;
} }
std::get<0>(fnDataAr.at(i)) = this; fnDataAr[i].range = {begin, end};
std::get<1>(fnDataAr.at(i)) = &entities; fnDataAr[i].manager = this;
std::get<2>(fnDataAr.at(i)) = &iterable; fnDataAr[i].entities = &entities;
std::get<3>(fnDataAr.at(i)) = {begin, end}; fnDataAr[i].iterable = &iterable;
std::get<4>(fnDataAr.at(i)) = userData; fnDataAr[i].userData = userData;
threadPool->queueFn([&fn] (void *ud) { threadPool->queueFn([&fn] (void *ud) {
auto *data = static_cast<TPFnDataType*>(ud); auto *data = static_cast<TPFnDataStructSeven<Iterable>*>(ud);
bool isValid; bool isValid;
for(std::size_t i = std::get<3>(*data).at(0); for(std::size_t i = data->range[0]; i < data->range[1];
i < std::get<3>(*data).at(1);
++i) { ++i) {
if(!std::get<0>(*data)->isAlive(i)) { if(!data->manager->isAlive(i)) {
continue; continue;
} }
isValid = true; isValid = true;
for(const auto& integralValue : *std::get<2>(*data)) { for(const auto& integralValue : *data->iterable) {
if(!std::get<BitsetType>(std::get<1>(*data)->at(i)).getCombinedBit(integralValue)) { if(!std::get<BitsetType>(data->entities->at(i))
.getCombinedBit(integralValue)) {
isValid = false; isValid = false;
break; break;
} }
} }
if(!isValid) { continue; } if(!isValid) { continue; }
fn(i, std::get<0>(*data), std::get<4>(*data)); fn(i, data->manager, data->userData);
} }
}, &fnDataAr.at(i)); }, &fnDataAr[i]);
} }
threadPool->wakeThreads(); threadPool->wakeThreads();
do { do {
std::this_thread::sleep_for(std::chrono::microseconds(200)); std::this_thread::sleep_for(std::chrono::microseconds(200));
} while(!threadPool->isQueueEmpty() || !threadPool->isAllThreadsWaiting()); } while(!threadPool->isQueueEmpty()
|| !threadPool->isAllThreadsWaiting());
} }
} }
}; };

View file

@ -49,6 +49,8 @@ struct Base
{ {
return 0; return 0;
} }
virtual ~Base() {}
}; };
struct Derived : public Base struct Derived : public Base