API change: context/userdata provided to functions

All functions called by EC/Manager now accept an additional parameter
as a void* to support user-provided data (or context) for functions
(useful when the function is not a lambda function and doesn't have any
other data stored with it).
This commit is contained in:
Stephen Seo 2018-08-08 16:52:12 +09:00
parent 2411125003
commit 6bf239a43b
2 changed files with 300 additions and 88 deletions

View file

@ -491,10 +491,12 @@ namespace EC
static void call( static void call(
const std::size_t& entityID, const std::size_t& entityID,
CType& ctype, CType& ctype,
Function&& function) Function&& function,
void* context = nullptr)
{ {
function( function(
entityID, entityID,
context,
ctype.template getEntityData<Types>(entityID)... ctype.template getEntityData<Types>(entityID)...
); );
} }
@ -503,10 +505,12 @@ namespace EC
static void callPtr( static void callPtr(
const std::size_t& entityID, const std::size_t& entityID,
CType& ctype, CType& ctype,
Function* function) Function* function,
void* context = nullptr)
{ {
(*function)( (*function)(
entityID, entityID,
context,
ctype.template getEntityData<Types>(entityID)... ctype.template getEntityData<Types>(entityID)...
); );
} }
@ -515,24 +519,28 @@ namespace EC
void callInstance( void callInstance(
const std::size_t& entityID, const std::size_t& entityID,
CType& ctype, CType& ctype,
Function&& function) const Function&& function,
void* context = nullptr) const
{ {
ForMatchingSignatureHelper<Types...>::call( ForMatchingSignatureHelper<Types...>::call(
entityID, entityID,
ctype, ctype,
std::forward<Function>(function)); std::forward<Function>(function),
context);
} }
template <typename CType, typename Function> template <typename CType, typename Function>
void callInstancePtr( void callInstancePtr(
const std::size_t& entityID, const std::size_t& entityID,
CType& ctype, CType& ctype,
Function* function) const Function* function,
void* context = nullptr) const
{ {
ForMatchingSignatureHelper<Types...>::callPtr( ForMatchingSignatureHelper<Types...>::callPtr(
entityID, entityID,
ctype, ctype,
function); function,
context);
} }
}; };
@ -542,24 +550,33 @@ namespace EC
Signature. Signature.
The function object given to this function must accept std::size_t The function object given to this function must accept std::size_t
as its first parameter and Component pointers for the rest of the as its first parameter, void* as its second parameter, and Component
parameters. Tags specified in the Signature are only used as pointers for the rest of the parameters. Tags specified in the
filters and will not be given as a parameter to the function. Signature are only used as filters and will not be given as a
parameter to the function.
The second parameter is default 1 (not multi-threaded). If the The second parameter is default nullptr and will be passed to the
second parameter threadCount is set to a value greater than 1, then function call as the second parameter as a means of providing
threadCount threads will be used. context (useful when the function is not a lambda function). The
Note that multi-threading is based on splitting the task of calling third parameter is default 1 (not multi-threaded). If the third
the function across sections of entities. Thus if there are only parameter threadCount is set to a value greater than 1, then
a small amount of entities in the manager, then using multiple threadCount threads will be used. Note that multi-threading is
threads may not have as great of a speed-up. based on splitting the task of calling the function across sections
of entities. Thus if there are only a small amount of entities in
the manager, then using multiple threads may not have as great of a
speed-up.
Example: Example:
\code{.cpp} \code{.cpp}
manager.forMatchingSignature<TypeList<C0, C1, T0>>([] ( Context c; // some class/struct with data
std::size_t ID, C0* component0, C1* component1) { manager.forMatchingSignature<TypeList<C0, C1, T0>>([]
(std::size_t ID,
void* context,
C0* component0, C1* component1)
{
// Lambda function contents here // Lambda function contents here
}, },
&c, // "Context" object passed to the function
4 // four threads 4 // four threads
); );
\endcode \endcode
@ -568,6 +585,7 @@ namespace EC
*/ */
template <typename Signature, typename Function> template <typename Signature, typename Function>
void forMatchingSignature(Function&& function, void forMatchingSignature(Function&& function,
void* context = nullptr,
std::size_t threadCount = 1) std::size_t threadCount = 1)
{ {
using SignatureComponents = using SignatureComponents =
@ -592,7 +610,7 @@ namespace EC
== signatureBitset) == signatureBitset)
{ {
Helper::call(i, *this, Helper::call(i, *this,
std::forward<Function>(function)); std::forward<Function>(function), context);
} }
} }
} }
@ -612,7 +630,8 @@ namespace EC
{ {
end = s * (i + 1); end = s * (i + 1);
} }
threads[i] = std::thread([this, &function, &signatureBitset] threads[i] = std::thread(
[this, &function, &signatureBitset, &context]
(std::size_t begin, (std::size_t begin,
std::size_t end) { std::size_t end) {
for(std::size_t i = begin; i < end; ++i) for(std::size_t i = begin; i < end; ++i)
@ -627,7 +646,7 @@ namespace EC
== signatureBitset) == signatureBitset)
{ {
Helper::call(i, *this, Helper::call(i, *this,
std::forward<Function>(function)); std::forward<Function>(function), context);
} }
} }
}, },
@ -646,26 +665,35 @@ namespace EC
Signature. Signature.
The function pointer given to this function must accept std::size_t The function pointer given to this function must accept std::size_t
as its first parameter and Component pointers for the rest of the as its first parameter, void* as its second parameter, and
parameters. Tags specified in the Signature are only used as Component pointers for the rest of the parameters. Tags specified in
filters and will not be given as a parameter to the function. the Signature are only used as filters and will not be given as a
parameter to the function.
The second parameter is default 1 (not multi-threaded). If the The second parameter is default nullptr and will be passed to the
second parameter threadCount is set to a value greater than 1, then function call as the second parameter as a means of providing
threadCount threads will be used. context (useful when the function is not a lambda function). The
Note that multi-threading is based on splitting the task of calling third parameter is default 1 (not multi-threaded). If the third
the function across sections of entities. Thus if there are only parameter threadCount is set to a value greater than 1, then
a small amount of entities in the manager, then using multiple threadCount threads will be used. Note that multi-threading is based
threads may not have as great of a speed-up. on splitting the task of calling the function across sections of
entities. Thus if there are only a small amount of entities in the
manager, then using multiple threads may not have as great of a
speed-up.
Example: Example:
\code{.cpp} \code{.cpp}
auto function = [] (std::size_t ID, C0* component0, Context c; // some class/struct with data
C1* component1) { auto function = []
(std::size_t ID,
void* context,
C0* component0, C1* component1)
{
// Lambda function contents here // Lambda function contents here
}; };
manager.forMatchingSignaturePtr<TypeList<C0, C1, T0>>( manager.forMatchingSignaturePtr<TypeList<C0, C1, T0>>(
&function, // ptr &function, // ptr
&c, // "Context" object passed to the function
4 // four threads 4 // four threads
); );
\endcode \endcode
@ -674,6 +702,7 @@ namespace EC
*/ */
template <typename Signature, typename Function> template <typename Signature, typename Function>
void forMatchingSignaturePtr(Function* function, void forMatchingSignaturePtr(Function* function,
void* context = nullptr,
std::size_t threadCount = 1) std::size_t threadCount = 1)
{ {
using SignatureComponents = using SignatureComponents =
@ -697,7 +726,7 @@ namespace EC
if((signatureBitset & std::get<BitsetType>(entities[i])) if((signatureBitset & std::get<BitsetType>(entities[i]))
== signatureBitset) == signatureBitset)
{ {
Helper::callPtr(i, *this, function); Helper::callPtr(i, *this, function, context);
} }
} }
} }
@ -717,7 +746,8 @@ namespace EC
{ {
end = s * (i + 1); end = s * (i + 1);
} }
threads[i] = std::thread([this, &function, &signatureBitset] threads[i] = std::thread(
[this, &function, &signatureBitset, &context]
(std::size_t begin, (std::size_t begin,
std::size_t end) { std::size_t end) {
for(std::size_t i = begin; i < end; ++i) for(std::size_t i = begin; i < end; ++i)
@ -731,7 +761,7 @@ namespace EC
& std::get<BitsetType>(entities[i])) & std::get<BitsetType>(entities[i]))
== signatureBitset) == signatureBitset)
{ {
Helper::callPtr(i, *this, function); Helper::callPtr(i, *this, function, context);
} }
} }
}, },
@ -750,9 +780,11 @@ namespace EC
private: private:
std::unordered_map<std::size_t, std::tuple< std::unordered_map<std::size_t, std::tuple<
BitsetType, BitsetType,
void*,
std::function<void( std::function<void(
std::size_t, std::size_t,
std::vector<std::size_t>)> > > std::vector<std::size_t>,
void*)> > >
forMatchingFunctions; forMatchingFunctions;
std::size_t functionIndex = 0; std::size_t functionIndex = 0;
@ -775,10 +807,16 @@ namespace EC
std::size_t). Calling clearForMatchingFunctions() will reset this std::size_t). Calling clearForMatchingFunctions() will reset this
counter to zero. counter to zero.
Note that the context pointer provided here (default nullptr) will
be provided to the stored function when called.
Example: Example:
\code{.cpp} \code{.cpp}
manager.addForMatchingFunction<TypeList<C0, C1, T0>>([] ( manager.addForMatchingFunction<TypeList<C0, C1, T0>>([]
std::size_t ID, C0* component0, C1* component1) { (std::size_t ID,
void* context,
C0* component0, C1* component1)
{
// Lambda function contents here // Lambda function contents here
}); });
@ -795,7 +833,9 @@ namespace EC
or calling with callForMatchingFunction(). or calling with callForMatchingFunction().
*/ */
template <typename Signature, typename Function> template <typename Signature, typename Function>
std::size_t addForMatchingFunction(Function&& function) std::size_t addForMatchingFunction(
Function&& function,
void* context = nullptr)
{ {
while(forMatchingFunctions.find(functionIndex) while(forMatchingFunctions.find(functionIndex)
!= forMatchingFunctions.end()) != forMatchingFunctions.end())
@ -818,9 +858,11 @@ namespace EC
functionIndex, functionIndex,
std::make_tuple( std::make_tuple(
signatureBitset, signatureBitset,
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)
{ {
if(threadCount <= 1) if(threadCount <= 1)
{ {
@ -828,7 +870,8 @@ namespace EC
{ {
if(isAlive(eid)) if(isAlive(eid))
{ {
helper.callInstancePtr(eid, *this, &function); helper.callInstancePtr(
eid, *this, &function, context);
} }
} }
} }
@ -849,14 +892,15 @@ namespace EC
end = s * (i + 1); end = s * (i + 1);
} }
threads[i] = std::thread( threads[i] = std::thread(
[this, &function, &helper] [this, &function, &helper, &context]
(std::size_t begin, (std::size_t begin,
std::size_t end) { std::size_t end) {
for(std::size_t i = begin; i < end; ++i) for(std::size_t i = begin; i < end; ++i)
{ {
if(isAlive(i)) if(isAlive(i))
{ {
helper.callInstancePtr(i, *this, &function); helper.callInstancePtr(
i, *this, &function, context);
} }
} }
}, },
@ -950,8 +994,8 @@ namespace EC
/*! /*!
\brief Call all stored functions. \brief Call all stored functions.
A second parameter can be optionally used to specify the number The first (and only) parameter can be optionally used to specify the
of threads to use when calling the functions. Otherwise, this number of threads to use when calling the functions. Otherwise, this
function is by default not multi-threaded. function is by default not multi-threaded.
Note that multi-threading is based on splitting the task of calling Note that multi-threading is based on splitting the task of calling
the functions across sections of entities. Thus if there are only the functions across sections of entities. Thus if there are only
@ -960,8 +1004,10 @@ namespace EC
Example: Example:
\code{.cpp} \code{.cpp}
manager.addForMatchingFunction<TypeList<C0, C1, T0>>([] ( manager.addForMatchingFunction<TypeList<C0, C1, T0>>([]
std::size_t ID, C0* component0, C1* component1) { (std::size_t ID,
void* context,
C0* component0, C1* component1) {
// Lambda function contents here // Lambda function contents here
}); });
@ -993,7 +1039,8 @@ namespace EC
iter != forMatchingFunctions.end(); iter != forMatchingFunctions.end();
++iter) ++iter)
{ {
std::get<1>(iter->second)(threadCount, matching[i++]); std::get<2>(iter->second)(
threadCount, matching[i++], std::get<1>(iter->second));
} }
} }
@ -1012,7 +1059,7 @@ namespace EC
\code{.cpp} \code{.cpp}
std::size_t id = std::size_t id =
manager.addForMatchingFunction<TypeList<C0, C1, T0>>( manager.addForMatchingFunction<TypeList<C0, C1, T0>>(
[] (std::size_t ID, C0* c0, C1* c1) { [] (std::size_t ID, void* context, C0* c0, C1* c1) {
// Lambda function contents here // Lambda function contents here
}); });
@ -1036,7 +1083,8 @@ namespace EC
std::vector<std::vector<std::size_t> > matching = std::vector<std::vector<std::size_t> > matching =
getMatchingEntities(std::vector<BitsetType*>{ getMatchingEntities(std::vector<BitsetType*>{
&std::get<BitsetType>(iter->second)}, threadCount); &std::get<BitsetType>(iter->second)}, threadCount);
std::get<1>(iter->second)(threadCount, matching[0]); std::get<2>(iter->second)(
threadCount, matching[0], std::get<1>(iter->second));
return true; return true;
} }
@ -1047,8 +1095,11 @@ namespace EC
Example: Example:
\code{.cpp} \code{.cpp}
manager.addForMatchingFunction<TypeList<C0, C1, T0>>([] ( manager.addForMatchingFunction<TypeList<C0, C1, T0>>([]
std::size_t ID, C0* component0, C1* component1) { (std::size_t ID,
void* context,
C0* component0, C1* component1)
{
// Lambda function contents here // Lambda function contents here
}); });
@ -1170,6 +1221,22 @@ namespace EC
return forMatchingFunctions.erase(index) == 1; return forMatchingFunctions.erase(index) == 1;
} }
/*!
\brief Sets the context pointer of a stored function
\return True if id is valid and context was updated
*/
bool changeForMatchingFunctionContext(std::size_t id, void* context)
{
auto f = forMatchingFunctions.find(id);
if(f != forMatchingFunctions.end())
{
std::get<1>(f->second) = context;
return true;
}
return false;
}
/*! /*!
\brief Call multiple functions with mulitple signatures on all \brief Call multiple functions with mulitple signatures on all
living entities. living entities.
@ -1191,6 +1258,9 @@ namespace EC
See the Unit Test of this function in src/test/ECTest.cpp for See the Unit Test of this function in src/test/ECTest.cpp for
usage examples. usage examples.
The second parameter (default nullptr) will be provided to every
function call as a void* (context).
This function was created for the use case where there are many This function was created for the use case where there are many
entities in the system which can cause multiple calls to entities in the system which can cause multiple calls to
forMatchingSignature to be slow due to the overhead of iterating forMatchingSignature to be slow due to the overhead of iterating
@ -1209,7 +1279,9 @@ namespace EC
*/ */
template <typename SigList, typename FTuple> template <typename SigList, typename FTuple>
void forMatchingSignatures( void forMatchingSignatures(
FTuple fTuple, const std::size_t threadCount = 1) FTuple fTuple,
void* context = nullptr,
const std::size_t threadCount = 1)
{ {
std::vector<std::vector<std::size_t> > multiMatchingEntities( std::vector<std::vector<std::size_t> > multiMatchingEntities(
SigList::size); SigList::size);
@ -1294,7 +1366,7 @@ namespace EC
EC::Meta::forEachDoubleTuple( EC::Meta::forEachDoubleTuple(
EC::Meta::Morph<SigList, std::tuple<> >{}, EC::Meta::Morph<SigList, std::tuple<> >{},
fTuple, fTuple,
[this, &multiMatchingEntities, &threadCount] [this, &multiMatchingEntities, &threadCount, &context]
(auto sig, auto func, auto index) (auto sig, auto func, auto index)
{ {
using SignatureComponents = using SignatureComponents =
@ -1310,7 +1382,7 @@ namespace EC
{ {
if(isAlive(id)) if(isAlive(id))
{ {
Helper::call(id, *this, func); Helper::call(id, *this, func, context);
} }
} }
} }
@ -1332,7 +1404,8 @@ namespace EC
end = s * (i + 1); end = s * (i + 1);
} }
threads[i] = std::thread( threads[i] = std::thread(
[this, &multiMatchingEntities, &index, &func] [this, &multiMatchingEntities, &index, &func,
&context]
(std::size_t begin, std::size_t end) (std::size_t begin, std::size_t end)
{ {
for(std::size_t j = begin; j < end; for(std::size_t j = begin; j < end;
@ -1343,7 +1416,8 @@ namespace EC
Helper::call( Helper::call(
multiMatchingEntities[index][j], multiMatchingEntities[index][j],
*this, *this,
func); func,
context);
} }
} }
}, begin, end); }, begin, end);
@ -1381,6 +1455,9 @@ namespace EC
See the Unit Test of this function in src/test/ECTest.cpp for See the Unit Test of this function in src/test/ECTest.cpp for
usage examples. usage examples.
The second parameter (default nullptr) will be provided to every
function call as a void* (context).
This function was created for the use case where there are many This function was created for the use case where there are many
entities in the system which can cause multiple calls to entities in the system which can cause multiple calls to
forMatchingSignature to be slow due to the overhead of iterating forMatchingSignature to be slow due to the overhead of iterating
@ -1399,6 +1476,7 @@ namespace EC
*/ */
template <typename SigList, typename FTuple> template <typename SigList, typename FTuple>
void forMatchingSignaturesPtr(FTuple fTuple, void forMatchingSignaturesPtr(FTuple fTuple,
void* context = nullptr,
std::size_t threadCount = 1) std::size_t threadCount = 1)
{ {
std::vector<std::vector<std::size_t> > multiMatchingEntities( std::vector<std::vector<std::size_t> > multiMatchingEntities(
@ -1484,7 +1562,7 @@ namespace EC
EC::Meta::forEachDoubleTuple( EC::Meta::forEachDoubleTuple(
EC::Meta::Morph<SigList, std::tuple<> >{}, EC::Meta::Morph<SigList, std::tuple<> >{},
fTuple, fTuple,
[this, &multiMatchingEntities, &threadCount] [this, &multiMatchingEntities, &threadCount, &context]
(auto sig, auto func, auto index) (auto sig, auto func, auto index)
{ {
using SignatureComponents = using SignatureComponents =
@ -1500,7 +1578,7 @@ namespace EC
{ {
if(isAlive(id)) if(isAlive(id))
{ {
Helper::callPtr(id, *this, func); Helper::callPtr(id, *this, func, context);
} }
} }
} }
@ -1522,7 +1600,8 @@ namespace EC
end = s * (i + 1); end = s * (i + 1);
} }
threads[i] = std::thread( threads[i] = std::thread(
[this, &multiMatchingEntities, &index, &func] [this, &multiMatchingEntities, &index, &func,
&context]
(std::size_t begin, std::size_t end) (std::size_t begin, std::size_t end)
{ {
for(std::size_t j = begin; j < end; for(std::size_t j = begin; j < end;
@ -1533,7 +1612,8 @@ namespace EC
Helper::callPtr( Helper::callPtr(
multiMatchingEntities[index][j], multiMatchingEntities[index][j],
*this, *this,
func); func,
context);
} }
} }
}, begin, end); }, begin, end);

View file

@ -58,6 +58,38 @@ struct Derived : public Base
typedef std::unique_ptr<Base> TestPtr; typedef std::unique_ptr<Base> TestPtr;
struct Context
{
int a, b;
};
void assignContextToC0(std::size_t /* id */, void* context, C0* c)
{
Context* contextPtr = (Context*) context;
c->x = contextPtr->a;
c->y = contextPtr->b;
}
void assignC0ToContext(std::size_t /* id */, void* context, C0* c)
{
Context* contextPtr = (Context*) context;
contextPtr->a = c->x;
contextPtr->b = c->y;
}
void setC0ToOneAndTwo(std::size_t /* id */, void* /* context */, C0* c)
{
c->x = 1;
c->y = 2;
}
void setContextToThreeAndFour(std::size_t /* id */, void* context, C0* /* c */)
{
Context* contextPtr = (Context*) context;
contextPtr->a = 3;
contextPtr->b = 4;
}
TEST(EC, Bitset) TEST(EC, Bitset)
{ {
{ {
@ -101,12 +133,16 @@ TEST(EC, Manager)
vel->vy = 1; vel->vy = 1;
} }
auto posUpdate = [] (std::size_t id, C0* pos, C1* vel) { auto posUpdate = []
(std::size_t /* id */, void* /* context */, C0* pos, C1* vel)
{
pos->x += vel->vx; pos->x += vel->vx;
pos->y += vel->vy; pos->y += vel->vy;
}; };
auto updateTag = [] (std::size_t id, C0* pos, C1* vel) { auto updateTag = []
(std::size_t /* id */, void* /* context */, C0* pos, C1* vel)
{
pos->x = pos->y = vel->vx = vel->vy = 0; pos->x = pos->y = vel->vx = vel->vy = 0;
}; };
@ -139,7 +175,7 @@ TEST(EC, Manager)
std::size_t count = 0; std::size_t count = 0;
auto updateTagOnly = [&count] (std::size_t id) { auto updateTagOnly = [&count] (std::size_t /* id */, void* /* context */) {
std::cout << "UpdateTagOnly was run." << std::endl; std::cout << "UpdateTagOnly was run." << std::endl;
++count; ++count;
}; };
@ -167,7 +203,7 @@ TEST(EC, MoveComponentWithUniquePtr)
int x = 0; int x = 0;
int y = 0; int y = 0;
manager.forMatchingSignature<EC::Meta::TypeList<C0Ptr> >([&x, &y] manager.forMatchingSignature<EC::Meta::TypeList<C0Ptr> >([&x, &y]
(std::size_t eID, C0Ptr* ptr) { (std::size_t /* id */, void* /* context */, C0Ptr* ptr) {
x = (*ptr)->x; x = (*ptr)->x;
y = (*ptr)->y; y = (*ptr)->y;
}); });
@ -186,7 +222,9 @@ TEST(EC, MoveComponentWithUniquePtr)
int result = 0; int result = 0;
auto getResultFunction = [&result] (std::size_t eID, TestPtr* ptr) { auto getResultFunction = [&result]
(std::size_t /* id */, void* /* context */, TestPtr* ptr)
{
result = (*ptr)->getInt(); result = (*ptr)->getInt();
}; };
@ -246,31 +284,31 @@ TEST(EC, FunctionStorage)
manager.addComponent<C3>(eid); manager.addComponent<C3>(eid);
auto f0index = manager.addForMatchingFunction<EC::Meta::TypeList<C0>>( auto f0index = manager.addForMatchingFunction<EC::Meta::TypeList<C0>>(
[] (std::size_t eid, C0* c0) { [] (std::size_t /* id */, void* /* context */, C0* c0) {
++c0->x; ++c0->x;
++c0->y; ++c0->y;
}); });
auto f1index = manager.addForMatchingFunction<EC::Meta::TypeList<C0, C1>>( auto f1index = manager.addForMatchingFunction<EC::Meta::TypeList<C0, C1>>(
[] (std::size_t eid, C0* c0, C1* c1) { [] (std::size_t /* id */, void* /* context */, C0* c0, C1* c1) {
c1->vx = c0->x + 10; c1->vx = c0->x + 10;
c1->vy = c1->vy + c1->vx + c0->y + 10; c1->vy = c1->vy + c1->vx + c0->y + 10;
}); });
auto f2index = manager.addForMatchingFunction<EC::Meta::TypeList<C0>>( auto f2index = manager.addForMatchingFunction<EC::Meta::TypeList<C0>>(
[] (std::size_t eid, C0* c0) { [] (std::size_t /* id */, void* /* context */, C0* c0) {
c0->x = c0->y = 9999; c0->x = c0->y = 9999;
}); });
auto f3index = manager.addForMatchingFunction<EC::Meta::TypeList<C1>>( auto f3index = manager.addForMatchingFunction<EC::Meta::TypeList<C1>>(
[] (std::size_t eid, C1* c1) { [] (std::size_t /* id */, void* /* context */, C1* c1) {
c1->vx = c1->vy = 10000; c1->vx = c1->vy = 10000;
}); });
EXPECT_EQ(2, manager.removeSomeMatchingFunctions({f2index, f3index})); EXPECT_EQ(2, manager.removeSomeMatchingFunctions({f2index, f3index}));
auto f4index = manager.addForMatchingFunction<EC::Meta::TypeList<C0>>( auto f4index = manager.addForMatchingFunction<EC::Meta::TypeList<C0>>(
[] (std::size_t eid, C0* c0) { [] (std::size_t /* id */, void* /* context */, C0* c0) {
c0->x = 999; c0->x = 999;
c0->y = 888; c0->y = 888;
}); });
@ -281,7 +319,7 @@ TEST(EC, FunctionStorage)
} }
auto f5index = manager.addForMatchingFunction<EC::Meta::TypeList<C0>>( auto f5index = manager.addForMatchingFunction<EC::Meta::TypeList<C0>>(
[] (std::size_t eid, C0* c0) { [] (std::size_t /* id */, void* /* context */, C0* c0) {
c0->x = 777; c0->x = 777;
c0->y = 666; c0->y = 666;
}); });
@ -418,10 +456,11 @@ TEST(EC, MultiThreaded)
} }
manager.forMatchingSignature<EC::Meta::TypeList<C0> >( manager.forMatchingSignature<EC::Meta::TypeList<C0> >(
[] (const std::size_t& eid, C0* c) { [] (const std::size_t& /* id */, void* /* context */, C0* c) {
c->x = 1; c->x = 1;
c->y = 2; c->y = 2;
}, },
nullptr,
2 2
); );
@ -443,10 +482,11 @@ TEST(EC, MultiThreaded)
} }
manager.forMatchingSignature<EC::Meta::TypeList<C0> >( manager.forMatchingSignature<EC::Meta::TypeList<C0> >(
[] (const std::size_t& eid, C0* c) { [] (const std::size_t& /* id */, void* /* context */, C0* c) {
c->x = 3; c->x = 3;
c->y = 4; c->y = 4;
}, },
nullptr,
8 8
); );
@ -467,7 +507,7 @@ TEST(EC, MultiThreaded)
} }
auto f0 = manager.addForMatchingFunction<EC::Meta::TypeList<C0> >( auto f0 = manager.addForMatchingFunction<EC::Meta::TypeList<C0> >(
[] (const std::size_t& eid, C0* c) { [] (const std::size_t& /* id */, void* /* context */, C0* c) {
c->x = 1; c->x = 1;
c->y = 2; c->y = 2;
} }
@ -482,7 +522,7 @@ TEST(EC, MultiThreaded)
} }
auto f1 = manager.addForMatchingFunction<EC::Meta::TypeList<C0> >( auto f1 = manager.addForMatchingFunction<EC::Meta::TypeList<C0> >(
[] (const std::size_t& eid, C0* c) { [] (const std::size_t& /* id */, void* /* context */, C0* c) {
c->x = 3; c->x = 3;
c->y = 4; c->y = 4;
} }
@ -559,13 +599,13 @@ TEST(EC, ForMatchingSignatures)
TypeList<TypeList<C0>, TypeList<C0, C1> > TypeList<TypeList<C0>, TypeList<C0, C1> >
>( >(
std::make_tuple( std::make_tuple(
[] (std::size_t eid, C0* c) { [] (std::size_t /* id */, void* /* context */, C0* c) {
EXPECT_EQ(c->x, 0); EXPECT_EQ(c->x, 0);
EXPECT_EQ(c->y, 0); EXPECT_EQ(c->y, 0);
c->x = 1; c->x = 1;
c->y = 1; c->y = 1;
}, },
[] (std::size_t eid, C0* c0, C1* c1) { [] (std::size_t /* id */, void* /* context */, C0* c0, C1* c1) {
EXPECT_EQ(c0->x, 1); EXPECT_EQ(c0->x, 1);
EXPECT_EQ(c0->y, 1); EXPECT_EQ(c0->y, 1);
EXPECT_EQ(c1->vx, 0); EXPECT_EQ(c1->vx, 0);
@ -612,7 +652,8 @@ TEST(EC, ForMatchingSignatures)
> >
( (
std::make_tuple( std::make_tuple(
[&first, &last, &cx, &cy, &cxM, &cyM] (std::size_t eid, C0* c) { [&first, &last, &cx, &cy, &cxM, &cyM]
(std::size_t eid, void* /* context */, C0* c) {
if(eid != first && eid != last) if(eid != first && eid != last)
{ {
{ {
@ -641,7 +682,7 @@ TEST(EC, ForMatchingSignatures)
} }
}, },
[&c0x, &c0y, &c1vx, &c1vy, &c0xM, &c0yM, &c1vxM, &c1vyM] [&c0x, &c0y, &c1vx, &c1vy, &c0xM, &c0yM, &c1vxM, &c1vyM]
(std::size_t eid, C0* c0, C1* c1) { (std::size_t eid, void* /* context */, C0* c0, C1* c1) {
{ {
std::lock_guard<std::mutex> guard(c0xM); std::lock_guard<std::mutex> guard(c0xM);
c0x.insert(std::make_pair(eid, c0->x)); c0x.insert(std::make_pair(eid, c0->x));
@ -665,6 +706,7 @@ TEST(EC, ForMatchingSignatures)
c0->x = 1; c0->x = 1;
c0->y = 2; c0->y = 2;
}), }),
nullptr,
3 3
); );
@ -729,13 +771,13 @@ TEST(EC, ForMatchingSignatures)
TypeList<C0, C1>, TypeList<C0, C1>,
TypeList<C0, C1> > >( TypeList<C0, C1> > >(
std::make_tuple( std::make_tuple(
[] (std::size_t eid, C0* c0, C1* c1) { [] (std::size_t /* id */, void* /* context */, C0* c0, C1* c1) {
c0->x = 9999; c0->x = 9999;
c0->y = 9999; c0->y = 9999;
c1->vx = 9999; c1->vx = 9999;
c1->vy = 9999; c1->vy = 9999;
}, },
[] (std::size_t eid, C0* c0, C1* c1) { [] (std::size_t /* id */, void* /* context */, C0* c0, C1* c1) {
c0->x = 10000; c0->x = 10000;
c0->y = 10000; c0->y = 10000;
c1->vx = 10000; c1->vx = 10000;
@ -785,14 +827,15 @@ TEST(EC, forMatchingPtrs)
} }
} }
const auto func0 = [] (std::size_t eid, C0* c0, C1* c1) const auto func0 = []
(std::size_t /* id */, void* /* context */, C0* c0, C1* c1)
{ {
c0->x = 1; c0->x = 1;
c0->y = 2; c0->y = 2;
c1->vx = 3; c1->vx = 3;
c1->vy = 4; c1->vy = 4;
}; };
const auto func1 = [] (std::size_t eid, C0* c0) const auto func1 = [] (std::size_t /* id */, void* /* context */, C0* c0)
{ {
c0->x = 11; c0->x = 11;
c0->y = 12; c0->y = 12;
@ -864,13 +907,17 @@ TEST(EC, forMatchingPtrs)
} }
// test duplicate signatures // test duplicate signatures
const auto setTo9999 = [] (std::size_t eid, C0* c0, C1* c1) { const auto setTo9999 = []
(std::size_t /* id */, void* /* context */, C0* c0, C1* c1)
{
c0->x = 9999; c0->x = 9999;
c0->y = 9999; c0->y = 9999;
c1->vx = 9999; c1->vx = 9999;
c1->vy = 9999; c1->vy = 9999;
}; };
const auto setTo10000 = [] (std::size_t eid, C0* c0, C1* c1) { const auto setTo10000 = []
(std::size_t /* id */, void* /* context */, C0* c0, C1* c1)
{
c0->x = 10000; c0->x = 10000;
c0->y = 10000; c0->y = 10000;
c1->vx = 10000; c1->vx = 10000;
@ -895,3 +942,88 @@ TEST(EC, forMatchingPtrs)
}; };
} }
TEST(EC, context)
{
EC::Manager<ListComponentsAll, ListTagsAll> manager;
auto e0 = manager.addEntity();
auto e1 = manager.addEntity();
manager.addComponent<C0>(e0, 1, 2);
manager.addComponent<C0>(e1, 3, 4);
Context c;
c.a = 2000;
c.b = 5432;
EXPECT_EQ(1, manager.getEntityData<C0>(e0)->x);
EXPECT_EQ(2, manager.getEntityData<C0>(e0)->y);
EXPECT_EQ(3, manager.getEntityData<C0>(e1)->x);
EXPECT_EQ(4, manager.getEntityData<C0>(e1)->y);
manager.forMatchingSignature<EC::Meta::TypeList<C0>>(assignContextToC0, &c);
EXPECT_EQ(2000, manager.getEntityData<C0>(e0)->x);
EXPECT_EQ(5432, manager.getEntityData<C0>(e0)->y);
EXPECT_EQ(2000, manager.getEntityData<C0>(e1)->x);
EXPECT_EQ(5432, manager.getEntityData<C0>(e1)->y);
c.a = 1111;
c.b = 2222;
using C0TL = EC::Meta::TypeList<C0>;
manager.forMatchingSignatures<EC::Meta::TypeList<C0TL, C0TL, C0TL>>(
std::make_tuple(
setC0ToOneAndTwo, assignContextToC0, setContextToThreeAndFour),
&c);
EXPECT_EQ(1111, manager.getEntityData<C0>(e0)->x);
EXPECT_EQ(2222, manager.getEntityData<C0>(e0)->y);
EXPECT_EQ(1111, manager.getEntityData<C0>(e1)->x);
EXPECT_EQ(2222, manager.getEntityData<C0>(e1)->y);
EXPECT_EQ(3, c.a);
EXPECT_EQ(4, c.b);
manager.forMatchingSignaturesPtr<EC::Meta::TypeList<C0TL, C0TL>>(
std::make_tuple(
&setC0ToOneAndTwo, &assignC0ToContext),
&c);
EXPECT_EQ(1, c.a);
EXPECT_EQ(2, c.b);
EXPECT_EQ(1, manager.getEntityData<C0>(e0)->x);
EXPECT_EQ(2, manager.getEntityData<C0>(e0)->y);
EXPECT_EQ(1, manager.getEntityData<C0>(e1)->x);
EXPECT_EQ(2, manager.getEntityData<C0>(e1)->y);
c.a = 1980;
c.b = 1990;
auto fid = manager.addForMatchingFunction<C0TL>(assignContextToC0, &c);
manager.callForMatchingFunction(fid);
EXPECT_EQ(1980, manager.getEntityData<C0>(e0)->x);
EXPECT_EQ(1990, manager.getEntityData<C0>(e0)->y);
EXPECT_EQ(1980, manager.getEntityData<C0>(e1)->x);
EXPECT_EQ(1990, manager.getEntityData<C0>(e1)->y);
c.a = 2000;
c.b = 2010;
manager.callForMatchingFunctions();
EXPECT_EQ(2000, manager.getEntityData<C0>(e0)->x);
EXPECT_EQ(2010, manager.getEntityData<C0>(e0)->y);
EXPECT_EQ(2000, manager.getEntityData<C0>(e1)->x);
EXPECT_EQ(2010, manager.getEntityData<C0>(e1)->y);
Context altC;
altC.a = 999;
altC.b = 1999;
manager.changeForMatchingFunctionContext(fid, &altC);
manager.callForMatchingFunctions();
EXPECT_EQ(999, manager.getEntityData<C0>(e0)->x);
EXPECT_EQ(1999, manager.getEntityData<C0>(e0)->y);
EXPECT_EQ(999, manager.getEntityData<C0>(e1)->x);
EXPECT_EQ(1999, manager.getEntityData<C0>(e1)->y);
}