Add forMatchingSimple, refactorings

This commit is contained in:
Stephen Seo 2019-11-06 16:33:12 +09:00
parent e0da16a63e
commit a310a8ae38
2 changed files with 144 additions and 23 deletions

View file

@ -490,6 +490,23 @@ namespace EC
).template getTagBit<Tag>() = false; ).template getTagBit<Tag>() = false;
} }
/*!
\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
@ -1634,36 +1651,73 @@ 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()
*
Some data may persist but will be overwritten when new entities * This function behaves like forMatchingSignature(), but instead of
are added. Thus, do not depend on data to persist after a call to * providing a function with each requested component as a parameter,
reset(). * the function receives a pointer to the manager itself, with which to
*/ * query component/tag data.
void reset() */
{ template <typename Signature>
clearForMatchingFunctions(); void forMatchingSimple(ForMatchingFn fn, void *userData = nullptr, std::size_t threadCount = 1) {
const BitsetType signatureBitset = BitsetType::template generateBitset<Signature>();
currentSize = 0; if(threadCount <= 1) {
currentCapacity = 0; for(std::size_t i = 0; i < currentSize; ++i) {
deletedSet.clear(); if(!std::get<bool>(entities[i])) {
resize(EC_INIT_ENTITIES_SIZE); 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();
}
}
} }
typedef void ForMatchingIterableFn(std::size_t, Manager<ComponentsList, TagsList>*, void*);
/*! /*!
* \brief Similar to forMatchingSignature(), but with a collection of Component/Tag indices * \brief Similar to forMatchingSimple(), but with a collection of Component/Tag indices
* *
* This function works like forMatchingSignature(), but instead of * This function works like forMatchingSimple(), but instead of
* providing template types that filter out non-matching entities, an * providing template types that filter out non-matching entities, an
* iterable of indices must be provided which correlate to matching * iterable of indices must be provided which correlate to matching
* Component/Tag indices. The function given must match the previously * Component/Tag indices. The function given must match the previously
* defined typedef of type ForMatchingIterableFn. * defined typedef of type ForMatchingFn.
*/ */
template <typename Iterable> template <typename Iterable>
void forMatchingIterable(Iterable iterable, ForMatchingIterableFn fn, void* userPtr = nullptr, std::size_t threadCount = 1) { void forMatchingIterable(Iterable iterable, ForMatchingFn fn, void* userPtr = nullptr, std::size_t threadCount = 1) {
if(threadCount <= 1) { if(threadCount <= 1) {
bool isValid; bool isValid;
for(std::size_t i = 0; i < currentSize; ++i) { for(std::size_t i = 0; i < currentSize; ++i) {
@ -1687,9 +1741,10 @@ namespace EC
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) {
std::size_t begin = s * i; std::size_t begin = s * i;
std::size_t end = i == threadCount - 1 ? std::size_t end =
currentSize : i == threadCount - 1 ?
s * (i + 1); currentSize :
s * (i + 1);
threads[i] = std::thread( threads[i] = std::thread(
[this, &fn, &iterable, userPtr] (std::size_t begin, std::size_t end) { [this, &fn, &iterable, userPtr] (std::size_t begin, std::size_t end) {
bool isValid; bool isValid;

View file

@ -1077,6 +1077,72 @@ TEST(EC, FunctionStorageOrder)
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) TEST(EC, forMatchingIterableFn)
{ {
EC::Manager<ListComponentsAll, ListTagsAll> manager; EC::Manager<ListComponentsAll, ListTagsAll> manager;