9#define EC_INIT_ENTITIES_SIZE 256
10#define EC_GROW_SIZE_AMOUNT 256
25#include <unordered_map>
26#include <unordered_set>
35#include "Meta/Combine.hpp"
36#include "Meta/ForEachDoubleTuple.hpp"
37#include "Meta/ForEachWithIndex.hpp"
38#include "Meta/IndexOf.hpp"
39#include "Meta/Matching.hpp"
40#include "ThreadPool.hpp"
68template <
typename ComponentsList,
typename TagsList,
69 unsigned int ThreadCount = 4>
72 using Components = ComponentsList;
73 using Tags = TagsList;
74 using Combined = EC::Meta::Combine<ComponentsList, TagsList>;
78 using ComponentsTuple = EC::Meta::Morph<ComponentsList, std::tuple<> >;
79 static_assert(std::is_default_constructible<ComponentsTuple>::value,
80 "All components must be default constructible");
82 template <
typename... Types>
84 using type = std::tuple<std::deque<Types>..., std::deque<char> >;
86 using ComponentsStorage =
87 typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
90 using EntitiesTupleType = std::tuple<bool, BitsetType>;
91 using EntitiesType = std::deque<EntitiesTupleType>;
93 EntitiesType entities;
94 ComponentsStorage componentsStorage;
95 std::size_t currentCapacity = 0;
96 std::size_t currentSize = 0;
97 std::unordered_set<std::size_t> deletedSet;
99 std::unique_ptr<ThreadPool<ThreadCount> > threadPool;
101 std::atomic_uint deferringDeletions;
102 std::vector<std::size_t> deferredDeletions;
103 std::mutex deferredDeletionsMutex;
105 std::vector<std::size_t> idStack;
106 std::size_t idStackCounter;
107 std::mutex idStackMutex;
113 std::array<std::size_t, 2> range;
115 EntitiesType* entities;
118 std::unordered_set<std::size_t> dead;
121 template <
typename Function>
123 std::array<std::size_t, 2> range;
125 EntitiesType* entities;
129 std::unordered_set<std::size_t> dead;
133 std::array<std::size_t, 2> range;
135 EntitiesType* entities;
137 const std::vector<std::size_t>* matching;
138 std::unordered_set<std::size_t> dead;
142 std::array<std::size_t, 2> range;
144 std::vector<std::vector<std::size_t> >* matchingV;
145 const std::vector<BitsetType*>* bitsets;
146 EntitiesType* entities;
148 std::unordered_set<std::size_t> dead;
152 std::array<std::size_t, 2> range;
154 std::vector<std::vector<std::size_t> >* multiMatchingEntities;
157 std::unordered_set<std::size_t> dead;
161 std::array<std::size_t, 2> range;
165 std::vector<std::vector<std::size_t> >* multiMatchingEntities;
166 std::unordered_set<std::size_t> dead;
170 std::array<std::size_t, 2> range;
172 std::vector<std::vector<std::size_t> >* multiMatchingEntities;
175 std::unordered_set<std::size_t> dead;
178 template <
typename Iterable>
180 std::array<std::size_t, 2> range;
182 EntitiesType* entities;
185 std::unordered_set<std::size_t> dead;
196 resize(EC_INIT_ENTITIES_SIZE);
197 if (ThreadCount >= 2) {
198 threadPool = std::make_unique<ThreadPool<ThreadCount> >();
201 deferringDeletions.store(0);
206 while (!threadPool->isNotRunning()) {
207 std::this_thread::sleep_for(std::chrono::microseconds(30));
213 void resize(std::size_t newCapacity) {
214 if (currentCapacity >= newCapacity) {
218 EC::Meta::forEach<ComponentsList>([
this, newCapacity](
auto t) {
219 std::get<std::deque<
decltype(t)> >(this->componentsStorage)
220 .resize(newCapacity);
223 entities.resize(newCapacity);
224 for (std::size_t i = currentCapacity; i < newCapacity; ++i) {
225 entities[i] = std::make_tuple(
false, BitsetType{});
228 currentCapacity = newCapacity;
238 if (deletedSet.empty()) {
239 if (currentSize == currentCapacity) {
240 resize(currentCapacity + EC_GROW_SIZE_AMOUNT);
243 std::get<bool>(entities[currentSize]) =
true;
245 return currentSize++;
249 auto iter = deletedSet.begin();
251 deletedSet.erase(iter);
253 std::get<bool>(entities[
id]) =
true;
259 void deleteEntityImpl(std::size_t
id) {
261 std::get<bool>(entities.at(
id)) =
false;
262 std::get<BitsetType>(entities.at(
id)).reset();
263 deletedSet.insert(
id);
276 if (deferringDeletions.load() != 0) {
277 std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
278 deferredDeletions.push_back(index);
280 deleteEntityImpl(index);
285 void handleDeferredDeletions() {
286 if (deferringDeletions.fetch_sub(1) == 1) {
287 std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
288 for (std::size_t
id : deferredDeletions) {
289 deleteEntityImpl(
id);
291 deferredDeletions.clear();
303 return index < currentSize;
312 bool isAlive(
const std::size_t& index)
const {
313 return hasEntity(index) && std::get<bool>(entities.at(index));
323 return currentSize - deletedSet.size();
333 std::size_t getCurrentCapacity()
const {
return currentCapacity; }
345 return entities.at(index);
361 template <
typename Component>
363 constexpr auto componentIndex =
365 if (componentIndex < Components::size) {
369 return (Component*)&std::get<componentIndex>(componentsStorage)
391 template <
typename Component>
409 template <
typename Component>
411 constexpr auto componentIndex =
413 if (componentIndex < Components::size) {
417 return (Component*)&std::get<componentIndex>(componentsStorage)
439 template <
typename Component>
453 template <
typename Component>
455 return std::get<BitsetType>(entities.at(index))
456 .template getComponentBit<Component>();
467 template <
typename Tag>
468 bool hasTag(
const std::size_t& index)
const {
469 return std::get<BitsetType>(entities.at(index))
470 .template getTagBit<Tag>();
502 template <
typename Component,
typename... Args>
504 if (!EC::Meta::Contains<Component, Components>::value ||
509 Component component(std::forward<Args>(args)...);
511 std::get<BitsetType>(entities[entityID])
512 .template getComponentBit<Component>() =
true;
519 (*((std::deque<Component>*)(&std::get<index>(
520 componentsStorage))))[entityID] = std::move(component);
534 template <
typename Component>
536 if (!EC::Meta::Contains<Component, Components>::value ||
541 std::get<BitsetType>(entities[entityID])
542 .template getComponentBit<Component>() =
false;
553 template <
typename Tag>
554 void addTag(
const std::size_t& entityID) {
555 if (!EC::Meta::Contains<Tag, Tags>::value || !
isAlive(entityID)) {
559 std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() =
573 template <
typename Tag>
575 if (!EC::Meta::Contains<Tag, Tags>::value || !
isAlive(entityID)) {
579 std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() =
596 resize(EC_INIT_ENTITIES_SIZE);
598 std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
599 deferringDeletions.store(0);
600 deferredDeletions.clear();
604 template <
typename... Types>
605 struct ForMatchingSignatureHelper {
606 template <
typename CType,
typename Function>
607 static void call(
const std::size_t& entityID, CType& ctype,
608 Function&& function,
void* userData =
nullptr) {
609 function(entityID, userData,
613 template <
typename CType,
typename Function>
614 static void callPtr(
const std::size_t& entityID, CType& ctype,
615 Function* function,
void* userData =
nullptr) {
616 (*function)(entityID, userData,
620 template <
typename CType,
typename Function>
621 void callInstance(
const std::size_t& entityID, CType& ctype,
622 Function&& function,
void* userData =
nullptr)
const {
623 ForMatchingSignatureHelper<Types...>::call(
624 entityID, ctype, std::forward<Function>(function), userData);
627 template <
typename CType,
typename Function>
628 void callInstancePtr(
const std::size_t& entityID, CType& ctype,
630 void* userData =
nullptr)
const {
631 ForMatchingSignatureHelper<Types...>::callPtr(entityID, ctype,
676 template <
typename Signature,
typename Function>
678 const bool useThreadPool =
false) {
679 std::size_t current_id;
682 std::lock_guard<std::mutex> lock(idStackMutex);
683 current_id = idStackCounter++;
684 idStack.push_back(current_id);
686 deferringDeletions.fetch_add(1);
687 using SignatureComponents =
690 EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;
693 BitsetType::template generateBitset<Signature>();
694 if (!useThreadPool || !threadPool) {
695 for (std::size_t i = 0; i < currentSize; ++i) {
696 if (!std::get<bool>(entities[i])) {
700 if ((signatureBitset & std::get<BitsetType>(entities[i])) ==
702 Helper::call(i, *
this, std::forward<Function>(function),
707 std::array<TPFnDataStructZero, ThreadCount * 2> fnDataAr;
709 std::size_t s = currentSize / (ThreadCount * 2);
710 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
711 std::size_t begin = s * i;
713 if (i == ThreadCount * 2 - 1) {
721 fnDataAr[i].range = {begin, end};
722 fnDataAr[i].manager =
this;
723 fnDataAr[i].entities = &entities;
724 fnDataAr[i].signature = &signatureBitset;
725 fnDataAr[i].userData = userData;
726 for (std::size_t j = begin; j < end; ++j) {
728 fnDataAr[i].dead.insert(j);
733 [&function](
void* ud) {
735 for (std::size_t i = data->range[0]; i < data->range[1];
737 if (data->dead.find(i) != data->dead.end()) {
741 if (((*data->signature) &
742 std::get<BitsetType>(data->entities->at(i))) ==
744 Helper::call(i, *data->manager,
745 std::forward<Function>(function),
752 threadPool->easyStartAndWait();
758 std::lock_guard<std::mutex> lock(idStackMutex);
759 if (idStack.back() == current_id) {
764 std::this_thread::sleep_for(std::chrono::microseconds(15));
767 handleDeferredDeletions();
811 template <
typename Signature,
typename Function>
813 const bool useThreadPool =
false) {
814 std::size_t current_id;
817 std::lock_guard<std::mutex> lock(idStackMutex);
818 current_id = idStackCounter++;
819 idStack.push_back(current_id);
821 deferringDeletions.fetch_add(1);
822 using SignatureComponents =
825 EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;
828 BitsetType::template generateBitset<Signature>();
829 if (!useThreadPool || !threadPool) {
830 for (std::size_t i = 0; i < currentSize; ++i) {
831 if (!std::get<bool>(entities[i])) {
835 if ((signatureBitset & std::get<BitsetType>(entities[i])) ==
837 Helper::callPtr(i, *
this, function, userData);
841 std::array<TPFnDataStructOne<Function>, ThreadCount * 2> fnDataAr;
843 std::size_t s = currentSize / (ThreadCount * 2);
844 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
845 std::size_t begin = s * i;
847 if (i == ThreadCount * 2 - 1) {
855 fnDataAr[i].range = {begin, end};
856 fnDataAr[i].manager =
this;
857 fnDataAr[i].entities = &entities;
858 fnDataAr[i].signature = &signatureBitset;
859 fnDataAr[i].userData = userData;
860 fnDataAr[i].fn = function;
861 for (std::size_t j = begin; j < end; ++j) {
863 fnDataAr[i].dead.insert(j);
870 for (std::size_t i = data->range[0]; i < data->range[1];
872 if (data->dead.find(i) != data->dead.end()) {
876 if (((*data->signature) &
877 std::get<BitsetType>(data->entities->at(i))) ==
879 Helper::callPtr(i, *data->manager, data->fn,
886 threadPool->easyStartAndWait();
892 std::lock_guard<std::mutex> lock(idStackMutex);
893 if (idStack.back() == current_id) {
898 std::this_thread::sleep_for(std::chrono::microseconds(15));
901 handleDeferredDeletions();
905 std::map<std::size_t,
906 std::tuple<BitsetType,
void*,
907 std::function<void(std::size_t,
908 std::vector<std::size_t>,
void*)> > >
909 forMatchingFunctions;
910 std::size_t functionIndex = 0;
956 template <
typename Signature,
typename Function>
958 void* userData =
nullptr) {
959 deferringDeletions.fetch_add(1);
960 while (forMatchingFunctions.find(functionIndex) !=
961 forMatchingFunctions.end()) {
965 using SignatureComponents =
968 EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;
972 BitsetType::template generateBitset<Signature>();
974 forMatchingFunctions.emplace(std::make_pair(
977 signatureBitset, userData,
978 [function, helper,
this](
const bool useThreadPool,
979 std::vector<std::size_t> matching,
981 if (!useThreadPool || !threadPool) {
982 for (
auto eid : matching) {
984 helper.callInstancePtr(eid, *
this, &function,
989 std::array<TPFnDataStructTwo, ThreadCount * 2> fnDataAr;
991 std::size_t s = matching.size() / (ThreadCount * 2);
992 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
993 std::size_t begin = s * i;
995 if (i == ThreadCount * 2 - 1) {
996 end = matching.size();
1003 fnDataAr[i].range = {begin, end};
1004 fnDataAr[i].manager =
this;
1005 fnDataAr[i].entities = &entities;
1006 fnDataAr[i].userData = userData;
1007 fnDataAr[i].matching = &matching;
1008 for (std::size_t j = begin; j < end; ++j) {
1009 if (!
isAlive(matching.at(j))) {
1010 fnDataAr[i].dead.insert(j);
1013 threadPool->queueFn(
1014 [&function, helper](
void* ud) {
1017 for (std::size_t i = data->range[0];
1018 i < data->range[1]; ++i) {
1019 if (data->dead.find(i) ==
1021 helper.callInstancePtr(
1022 data->matching->at(i),
1023 *data->manager, &function,
1030 threadPool->easyStartAndWait();
1034 handleDeferredDeletions();
1035 return functionIndex++;
1039 std::vector<std::vector<std::size_t> > getMatchingEntities(
1040 std::vector<BitsetType*> bitsets,
const bool useThreadPool =
false) {
1041 std::vector<std::vector<std::size_t> > matchingV(bitsets.size());
1043 if (!useThreadPool || !threadPool) {
1044 for (std::size_t i = 0; i < currentSize; ++i) {
1048 for (std::size_t j = 0; j < bitsets.size(); ++j) {
1049 if (((*bitsets[j]) & std::get<BitsetType>(entities[i])) ==
1051 matchingV[j].push_back(i);
1056 std::array<TPFnDataStructThree, ThreadCount * 2> fnDataAr;
1058 std::size_t s = currentSize / (ThreadCount * 2);
1060 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
1061 std::size_t begin = s * i;
1063 if (i == ThreadCount * 2 - 1) {
1071 fnDataAr[i].range = {begin, end};
1072 fnDataAr[i].manager =
this;
1073 fnDataAr[i].matchingV = &matchingV;
1074 fnDataAr[i].bitsets = &bitsets;
1075 fnDataAr[i].entities = &entities;
1076 fnDataAr[i].mutex = &mutex;
1077 for (std::size_t j = begin; j < end; ++j) {
1079 fnDataAr[i].dead.insert(j);
1082 threadPool->queueFn(
1084 auto* data =
static_cast<TPFnDataStructThree*
>(ud);
1085 for (std::size_t i = data->range[0]; i < data->range[1];
1087 if (data->dead.find(i) != data->dead.end()) {
1090 for (std::size_t j = 0; j < data->bitsets->size();
1092 if ((*data->bitsets->at(j) &
1093 std::get<BitsetType>(data->entities->at(
1094 i))) == *data->bitsets->at(j)) {
1095 std::lock_guard<std::mutex> lock(
1097 data->matchingV->at(j).push_back(i);
1104 threadPool->easyStartAndWait();
1143 deferringDeletions.fetch_add(1);
1144 std::vector<BitsetType*> bitsets;
1145 for (
auto iter = forMatchingFunctions.begin();
1146 iter != forMatchingFunctions.end(); ++iter) {
1147 bitsets.push_back(&std::get<BitsetType>(iter->second));
1150 std::vector<std::vector<std::size_t> > matching =
1151 getMatchingEntities(bitsets, useThreadPool);
1154 for (
auto iter = forMatchingFunctions.begin();
1155 iter != forMatchingFunctions.end(); ++iter) {
1156 std::get<2>(iter->second)(useThreadPool, matching[i++],
1157 std::get<1>(iter->second));
1160 handleDeferredDeletions();
1193 const bool useThreadPool =
false) {
1194 auto iter = forMatchingFunctions.find(
id);
1195 if (iter == forMatchingFunctions.end()) {
1198 deferringDeletions.fetch_add(1);
1199 std::vector<std::vector<std::size_t> > matching = getMatchingEntities(
1200 std::vector<BitsetType*>{&std::get<BitsetType>(iter->second)},
1202 std::get<2>(iter->second)(useThreadPool, matching[0],
1203 std::get<1>(iter->second));
1205 handleDeferredDeletions();
1232 forMatchingFunctions.clear();
1242 return forMatchingFunctions.erase(
id) == 1;
1254 template <
typename List>
1256 std::size_t deletedCount = 0;
1257 for (
auto iter = forMatchingFunctions.begin();
1258 iter != forMatchingFunctions.end();) {
1259 if (std::find(list.begin(), list.end(), iter->first) ==
1261 iter = forMatchingFunctions.erase(iter);
1268 return deletedCount;
1280 std::initializer_list<std::size_t> list) {
1293 template <
typename List>
1295 std::size_t deletedCount = 0;
1296 for (
auto listIter = list.begin(); listIter != list.end(); ++listIter) {
1297 deletedCount += forMatchingFunctions.erase(*listIter);
1300 return deletedCount;
1312 std::initializer_list<std::size_t> list) {
1322 auto f = forMatchingFunctions.find(
id);
1323 if (f != forMatchingFunctions.end()) {
1324 std::get<1>(f->second) = userData;
1378 template <
typename SigList,
typename FTuple>
1380 const bool useThreadPool =
false) {
1381 std::size_t current_id;
1384 std::lock_guard<std::mutex> lock(idStackMutex);
1385 current_id = idStackCounter++;
1386 idStack.push_back(current_id);
1388 deferringDeletions.fetch_add(1);
1389 std::vector<std::vector<std::size_t> > multiMatchingEntities(
1394 EC::Meta::forEachWithIndex<SigList>(
1395 [&signatureBitsets](
auto signature,
const auto index) {
1396 signatureBitsets[index] =
1397 BitsetType::template generateBitset<decltype(signature)>();
1401 if (!useThreadPool || !threadPool) {
1402 for (std::size_t eid = 0; eid < currentSize; ++eid) {
1406 for (std::size_t i = 0; i < SigList::size; ++i) {
1407 if ((signatureBitsets[i] &
1408 std::get<BitsetType>(entities[eid])) ==
1409 signatureBitsets[i]) {
1410 multiMatchingEntities[i].push_back(eid);
1415 std::array<TPFnDataStructFour, ThreadCount * 2> fnDataAr;
1418 std::size_t s = currentSize / (ThreadCount * 2);
1419 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
1420 std::size_t begin = s * i;
1422 if (i == ThreadCount * 2 - 1) {
1430 fnDataAr[i].range = {begin, end};
1431 fnDataAr[i].manager =
this;
1432 fnDataAr[i].multiMatchingEntities = &multiMatchingEntities;
1433 fnDataAr[i].signatures = signatureBitsets;
1434 fnDataAr[i].mutex = &mutex;
1435 for (std::size_t j = begin; j < end; ++j) {
1437 fnDataAr[i].dead.insert(j);
1441 threadPool->queueFn(
1444 for (std::size_t i = data->range[0]; i < data->range[1];
1446 if (data->dead.find(i) != data->dead.end()) {
1449 for (std::size_t j = 0; j < SigList::size; ++j) {
1450 if ((data->signatures[j] &
1451 std::get<BitsetType>(
1452 data->manager->entities[i])) ==
1453 data->signatures[j]) {
1454 std::lock_guard<std::mutex> lock(
1456 data->multiMatchingEntities->at(j)
1464 threadPool->easyStartAndWait();
1468 EC::Meta::forEachDoubleTuple(
1469 EC::Meta::Morph<SigList, std::tuple<> >{}, fTuple,
1470 [
this, &multiMatchingEntities, useThreadPool, &userData](
1471 auto sig,
auto func,
auto index) {
1472 using SignatureComponents =
1474 ComponentsList>::type;
1475 using Helper = EC::Meta::Morph<SignatureComponents,
1476 ForMatchingSignatureHelper<> >;
1477 if (!useThreadPool || !threadPool) {
1478 for (
const auto&
id : multiMatchingEntities[index]) {
1480 Helper::call(
id, *
this, func, userData);
1484 std::array<TPFnDataStructFive, ThreadCount * 2> fnDataAr;
1486 multiMatchingEntities[index].size() / (ThreadCount * 2);
1487 for (
unsigned int i = 0; i < ThreadCount * 2; ++i) {
1488 std::size_t begin = s * i;
1490 if (i == ThreadCount * 2 - 1) {
1491 end = multiMatchingEntities[index].size();
1498 fnDataAr[i].range = {begin, end};
1499 fnDataAr[i].index = index;
1500 fnDataAr[i].manager =
this;
1501 fnDataAr[i].userData = userData;
1502 fnDataAr[i].multiMatchingEntities =
1503 &multiMatchingEntities;
1504 for (std::size_t j = begin; j < end; ++j) {
1506 multiMatchingEntities.at(index).at(j))) {
1507 fnDataAr[i].dead.insert(j);
1510 threadPool->queueFn(
1514 for (std::size_t i = data->range[0];
1515 i < data->range[1]; ++i) {
1516 if (data->dead.find(i) ==
1518 Helper::call(data->multiMatchingEntities
1521 *data->manager, func,
1528 threadPool->easyStartAndWait();
1535 std::lock_guard<std::mutex> lock(idStackMutex);
1536 if (idStack.back() == current_id) {
1541 std::this_thread::sleep_for(std::chrono::microseconds(15));
1544 handleDeferredDeletions();
1598 template <
typename SigList,
typename FTuple>
1600 const bool useThreadPool =
false) {
1601 std::size_t current_id;
1604 std::lock_guard<std::mutex> lock(idStackMutex);
1605 current_id = idStackCounter++;
1606 idStack.push_back(current_id);
1608 deferringDeletions.fetch_add(1);
1609 std::vector<std::vector<std::size_t> > multiMatchingEntities(
1614 EC::Meta::forEachWithIndex<SigList>(
1615 [&signatureBitsets](
auto signature,
const auto index) {
1616 signatureBitsets[index] =
1617 BitsetType::template generateBitset<decltype(signature)>();
1621 if (!useThreadPool || !threadPool) {
1622 for (std::size_t eid = 0; eid < currentSize; ++eid) {
1626 for (std::size_t i = 0; i < SigList::size; ++i) {
1627 if ((signatureBitsets[i] &
1628 std::get<BitsetType>(entities[eid])) ==
1629 signatureBitsets[i]) {
1630 multiMatchingEntities[i].push_back(eid);
1635 std::array<TPFnDataStructSix, ThreadCount * 2> fnDataAr;
1638 std::size_t s = currentSize / (ThreadCount * 2);
1639 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
1640 std::size_t begin = s * i;
1642 if (i == ThreadCount * 2 - 1) {
1650 fnDataAr[i].range = {begin, end};
1651 fnDataAr[i].manager =
this;
1652 fnDataAr[i].multiMatchingEntities = &multiMatchingEntities;
1653 fnDataAr[i].bitsets = signatureBitsets;
1654 fnDataAr[i].mutex = &mutex;
1655 for (std::size_t j = begin; j < end; ++j) {
1657 fnDataAr[i].dead.insert(j);
1661 threadPool->queueFn(
1664 for (std::size_t i = data->range[0]; i < data->range[1];
1666 if (data->dead.find(i) != data->dead.end()) {
1669 for (std::size_t j = 0; j < SigList::size; ++j) {
1670 if ((data->bitsets[j] &
1671 std::get<BitsetType>(
1672 data->manager->entities[i])) ==
1674 std::lock_guard<std::mutex> lock(
1676 data->multiMatchingEntities->at(j)
1684 threadPool->easyStartAndWait();
1688 EC::Meta::forEachDoubleTuple(
1689 EC::Meta::Morph<SigList, std::tuple<> >{}, fTuple,
1690 [
this, &multiMatchingEntities, useThreadPool, &userData](
1691 auto sig,
auto func,
auto index) {
1692 using SignatureComponents =
1694 ComponentsList>::type;
1695 using Helper = EC::Meta::Morph<SignatureComponents,
1696 ForMatchingSignatureHelper<> >;
1697 if (!useThreadPool || !threadPool) {
1698 for (
const auto&
id : multiMatchingEntities[index]) {
1700 Helper::callPtr(
id, *
this, func, userData);
1704 std::array<TPFnDataStructFive, ThreadCount * 2> fnDataAr;
1706 multiMatchingEntities[index].size() / (ThreadCount * 2);
1707 for (
unsigned int i = 0; i < ThreadCount * 2; ++i) {
1708 std::size_t begin = s * i;
1710 if (i == ThreadCount * 2 - 1) {
1711 end = multiMatchingEntities[index].size();
1718 fnDataAr[i].range = {begin, end};
1719 fnDataAr[i].index = index;
1720 fnDataAr[i].manager =
this;
1721 fnDataAr[i].userData = userData;
1722 fnDataAr[i].multiMatchingEntities =
1723 &multiMatchingEntities;
1724 for (std::size_t j = begin; j < end; ++j) {
1726 multiMatchingEntities.at(index).at(j))) {
1727 fnDataAr[i].dead.insert(j);
1730 threadPool->queueFn(
1734 for (std::size_t i = data->range[0];
1735 i < data->range[1]; ++i) {
1736 if (data->dead.find(i) ==
1739 data->multiMatchingEntities
1742 *data->manager, func,
1749 threadPool->easyStartAndWait();
1756 std::lock_guard<std::mutex> lock(idStackMutex);
1757 if (idStack.back() == current_id) {
1762 std::this_thread::sleep_for(std::chrono::microseconds(15));
1765 handleDeferredDeletions();
1788 template <
typename Signature>
1790 const bool useThreadPool =
false) {
1791 std::size_t current_id;
1794 std::lock_guard<std::mutex> lock(idStackMutex);
1795 current_id = idStackCounter++;
1796 idStack.push_back(current_id);
1798 deferringDeletions.fetch_add(1);
1800 BitsetType::template generateBitset<Signature>();
1801 if (!useThreadPool || !threadPool) {
1802 for (std::size_t i = 0; i < currentSize; ++i) {
1803 if (!std::get<bool>(entities[i])) {
1805 }
else if ((signatureBitset &
1806 std::get<BitsetType>(entities[i])) ==
1808 fn(i,
this, userData);
1812 std::array<TPFnDataStructZero, ThreadCount * 2> fnDataAr;
1814 std::size_t s = currentSize / (ThreadCount * 2);
1815 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
1816 std::size_t begin = s * i;
1818 if (i == ThreadCount * 2 - 1) {
1826 fnDataAr[i].range = {begin, end};
1827 fnDataAr[i].manager =
this;
1828 fnDataAr[i].entities = &entities;
1829 fnDataAr[i].signature = &signatureBitset;
1830 fnDataAr[i].userData = userData;
1831 for (std::size_t j = begin; j < end; ++j) {
1833 fnDataAr[i].dead.insert(j);
1836 threadPool->queueFn(
1839 for (std::size_t i = data->range[0]; i < data->range[1];
1841 if (data->dead.find(i) != data->dead.end()) {
1843 }
else if ((*data->signature &
1844 std::get<BitsetType>(data->entities->at(
1845 i))) == *data->signature) {
1846 fn(i, data->manager, data->userData);
1852 threadPool->easyStartAndWait();
1858 std::lock_guard<std::mutex> lock(idStackMutex);
1859 if (idStack.back() == current_id) {
1864 std::this_thread::sleep_for(std::chrono::microseconds(15));
1867 handleDeferredDeletions();
1889 template <
typename Iterable>
1891 void* userData =
nullptr,
1892 const bool useThreadPool =
false) {
1893 std::size_t current_id;
1896 std::lock_guard<std::mutex> lock(idStackMutex);
1897 current_id = idStackCounter++;
1898 idStack.push_back(current_id);
1901 deferringDeletions.fetch_add(1);
1902 if (!useThreadPool || !threadPool) {
1904 for (std::size_t i = 0; i < currentSize; ++i) {
1905 if (!std::get<bool>(entities[i])) {
1910 for (
const auto& integralValue : iterable) {
1911 if (!std::get<BitsetType>(entities[i])
1912 .getCombinedBit(integralValue)) {
1921 fn(i,
this, userData);
1924 std::array<TPFnDataStructSeven<Iterable>, ThreadCount * 2> fnDataAr;
1926 std::size_t s = currentSize / (ThreadCount * 2);
1927 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
1928 std::size_t begin = s * i;
1930 if (i == ThreadCount * 2 - 1) {
1938 fnDataAr[i].range = {begin, end};
1939 fnDataAr[i].manager =
this;
1940 fnDataAr[i].entities = &entities;
1941 fnDataAr[i].iterable = &iterable;
1942 fnDataAr[i].userData = userData;
1943 for (std::size_t j = begin; j < end; ++j) {
1945 fnDataAr[i].dead.insert(j);
1948 threadPool->queueFn(
1953 for (std::size_t i = data->range[0]; i < data->range[1];
1955 if (data->dead.find(i) != data->dead.end()) {
1959 for (
const auto& integralValue : *data->iterable) {
1960 if (!std::get<BitsetType>(data->entities->at(i))
1961 .getCombinedBit(integralValue)) {
1970 fn(i, data->manager, data->userData);
1975 threadPool->easyStartAndWait();
1981 std::lock_guard<std::mutex> lock(idStackMutex);
1982 if (idStack.back() == current_id) {
1987 std::this_thread::sleep_for(std::chrono::microseconds(15));
1990 handleDeferredDeletions();
Temporary struct used internally by ThreadPool.
Definition Manager.hpp:160
Temporary struct used internally by ThreadPool.
Definition Manager.hpp:151
Temporary struct used internally by ThreadPool.
Definition Manager.hpp:122
Temporary struct used internally by ThreadPool.
Definition Manager.hpp:179
Temporary struct used internally by ThreadPool.
Definition Manager.hpp:169
Temporary struct used internally by ThreadPool.
Definition Manager.hpp:141
Temporary struct used internally by ThreadPool.
Definition Manager.hpp:132
Temporary struct used internally by ThreadPool.
Definition Manager.hpp:112
Manages an EntityComponent system.
Definition Manager.hpp:70
void forMatchingSignaturesPtr(FTuple fTuple, void *userData=nullptr, const bool useThreadPool=false)
Call multiple functions with mulitple signatures on all living entities.
Definition Manager.hpp:1599
std::size_t getCurrentSize() const
Returns the current size or number of entities in the system.
Definition Manager.hpp:322
std::size_t removeSomeMatchingFunctions(std::initializer_list< std::size_t > list)
Removes all functions that do have the index specified in argument "list".
Definition Manager.hpp:1311
bool hasTag(const std::size_t &index) const
Checks whether or not the given Entity has the given Tag.
Definition Manager.hpp:468
bool changeForMatchingFunctionContext(std::size_t id, void *userData)
Sets the context pointer of a stored function.
Definition Manager.hpp:1321
std::size_t addForMatchingFunction(Function &&function, void *userData=nullptr)
Stores a function in the manager to be called later.
Definition Manager.hpp:957
void addTag(const std::size_t &entityID)
Adds the given Tag to the given Entity.
Definition Manager.hpp:554
std::size_t keepSomeMatchingFunctions(List list)
Removes all functions that do not have the index specified in argument "list".
Definition Manager.hpp:1255
void clearForMatchingFunctions()
Remove all stored functions.
Definition Manager.hpp:1231
std::size_t addEntity()
Adds an entity to the system, returning the ID of the entity.
Definition Manager.hpp:237
void reset()
Resets the Manager, removing all entities.
Definition Manager.hpp:590
const Component * getEntityData(const std::size_t &index) const
Returns a const pointer to a component belonging to the given Entity.
Definition Manager.hpp:410
void callForMatchingFunctions(const bool useThreadPool=false)
Call all stored functions.
Definition Manager.hpp:1142
void removeComponent(const std::size_t &entityID)
Removes the given Component from the given Entity.
Definition Manager.hpp:535
void forMatchingIterable(Iterable iterable, ForMatchingFn fn, void *userData=nullptr, const bool useThreadPool=false)
Similar to forMatchingSimple(), but with a collection of Component/Tag indices.
Definition Manager.hpp:1890
void addComponent(const std::size_t &entityID, Args &&... args)
Adds a component to the given Entity.
Definition Manager.hpp:503
void forMatchingSimple(ForMatchingFn fn, void *userData=nullptr, const bool useThreadPool=false)
A simple version of forMatchingSignature()
Definition Manager.hpp:1789
bool hasComponent(const std::size_t &index) const
Checks whether or not the given Entity has the given Component.
Definition Manager.hpp:454
Component * getEntityData(const std::size_t &index)
Returns a pointer to a component belonging to the given Entity.
Definition Manager.hpp:362
void removeTag(const std::size_t &entityID)
Removes the given Tag from the given Entity.
Definition Manager.hpp:574
std::size_t keepSomeMatchingFunctions(std::initializer_list< std::size_t > list)
Removes all functions that do not have the index specified in argument "list".
Definition Manager.hpp:1279
bool callForMatchingFunction(std::size_t id, const bool useThreadPool=false)
Call a specific stored function.
Definition Manager.hpp:1192
void forMatchingSignature(Function &&function, void *userData=nullptr, const bool useThreadPool=false)
Calls the given function on all Entities matching the given Signature.
Definition Manager.hpp:677
void deleteEntity(std::size_t index)
Marks an entity for deletion.
Definition Manager.hpp:275
Component * getEntityComponent(const std::size_t &index)
Returns a pointer to a component belonging to the given Entity.
Definition Manager.hpp:392
const Component * getEntityComponent(const std::size_t &index) const
Returns a const pointer to a component belonging to the given Entity.
Definition Manager.hpp:440
Manager()
Initializes the manager with a default capacity.
Definition Manager.hpp:195
bool removeForMatchingFunction(std::size_t id)
Removes a function that has the given id.
Definition Manager.hpp:1241
void forMatchingSignaturePtr(Function *function, void *userData=nullptr, const bool useThreadPool=false)
Calls the given function on all Entities matching the given Signature.
Definition Manager.hpp:812
const EntitiesTupleType & getEntityInfo(const std::size_t &index) const
Returns a const reference to an Entity's info.
Definition Manager.hpp:344
std::size_t removeSomeMatchingFunctions(List list)
Removes all functions that do have the index specified in argument "list".
Definition Manager.hpp:1294
bool hasEntity(const std::size_t &index) const
Checks if the Entity with the given ID is in the system.
Definition Manager.hpp:302
void forMatchingSignatures(FTuple fTuple, void *userData=nullptr, const bool useThreadPool=false)
Call multiple functions with mulitple signatures on all living entities.
Definition Manager.hpp:1379
bool isAlive(const std::size_t &index) const
Checks if the Entity is not marked as deleted.
Definition Manager.hpp:312