Skip to content

Commit a016e60

Browse files
committed
Implement iterable::find
1 parent 55e1611 commit a016e60

File tree

12 files changed

+606
-6
lines changed

12 files changed

+606
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef FIND_ENTITY_H
2+
#define FIND_ENTITY_H
3+
4+
/* This generated file contains includes for project dependencies */
5+
#include "find_entity/bake_config.h"
6+
7+
#ifdef __cplusplus
8+
extern "C" {
9+
#endif
10+
11+
#ifdef __cplusplus
12+
}
13+
#endif
14+
15+
#endif
16+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
)
3+
(.)
4+
.|.
5+
| |
6+
_.--| |--._
7+
.-'; ;`-'& ; `&.
8+
\ & ; & &_/
9+
|"""---...---"""|
10+
\ | | | | | | | /
11+
`---.|.|.|.---'
12+
13+
* This file is generated by bake.lang.c for your convenience. Headers of
14+
* dependencies will automatically show up in this file. Include bake_config.h
15+
* in your main project file. Do not edit! */
16+
17+
#ifndef FIND_ENTITY_BAKE_CONFIG_H
18+
#define FIND_ENTITY_BAKE_CONFIG_H
19+
20+
/* Headers of public dependencies */
21+
#include <flecs.h>
22+
23+
#endif
24+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"id": "find_entity",
3+
"type": "application",
4+
"value": {
5+
"use": [
6+
"flecs"
7+
],
8+
"language": "c++",
9+
"public": false
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <find_entity.h>
2+
#include <iostream>
3+
4+
struct Position {
5+
double x, y;
6+
};
7+
8+
int main() {
9+
flecs::world ecs;
10+
11+
ecs.entity("e1").set<Position>({10, 20});
12+
ecs.entity("e2").set<Position>({20, 30});
13+
14+
// Create a simple query for component Position
15+
flecs::query<Position> q = ecs.query<Position>();
16+
17+
// Find the entity for which Position.x is 20
18+
flecs::entity e = q.find([](Position& p) {
19+
return p.x == 20.0;
20+
});
21+
22+
if (e) {
23+
std::cout << "Found entity " << e.path() << std::endl;
24+
} else {
25+
std::cout << "No entity found" << std::endl;
26+
}
27+
28+
// Output
29+
// Found entity ::e2
30+
}

flecs.h

+151
Original file line numberDiff line numberDiff line change
@@ -24100,6 +24100,151 @@ struct each_invoker : public invoker {
2410024100
Func m_func;
2410124101
};
2410224102

24103+
template <typename Func, typename ... Components>
24104+
struct find_invoker : public invoker {
24105+
// If the number of arguments in the function signature is one more than the
24106+
// number of components in the query, an extra entity arg is required.
24107+
static constexpr bool PassEntity =
24108+
(sizeof...(Components) + 1) == (arity<Func>::value);
24109+
24110+
// If the number of arguments in the function is two more than the number of
24111+
// components in the query, extra iter + index arguments are required.
24112+
static constexpr bool PassIter =
24113+
(sizeof...(Components) + 2) == (arity<Func>::value);
24114+
24115+
static_assert(arity<Func>::value > 0,
24116+
"each() must have at least one argument");
24117+
24118+
using Terms = typename term_ptrs<Components ...>::array;
24119+
24120+
template < if_not_t< is_same< decay_t<Func>, decay_t<Func>& >::value > = 0>
24121+
explicit find_invoker(Func&& func) noexcept
24122+
: m_func(FLECS_MOV(func)) { }
24123+
24124+
explicit find_invoker(const Func& func) noexcept
24125+
: m_func(func) { }
24126+
24127+
// Invoke object directly. This operation is useful when the calling
24128+
// function has just constructed the invoker, such as what happens when
24129+
// iterating a query.
24130+
void invoke(ecs_iter_t *iter) const {
24131+
term_ptrs<Components...> terms;
24132+
24133+
if (terms.populate(iter)) {
24134+
invoke_callback< each_ref_column >(iter, m_func, 0, terms.m_terms);
24135+
} else {
24136+
invoke_callback< each_column >(iter, m_func, 0, terms.m_terms);
24137+
}
24138+
}
24139+
24140+
// Find invokers always use instanced iterators
24141+
static bool instanced() {
24142+
return true;
24143+
}
24144+
24145+
private:
24146+
// Number of function arguments is one more than number of components, pass
24147+
// entity as argument.
24148+
template <template<typename X, typename = int> class ColumnType,
24149+
typename... Args, if_t<
24150+
sizeof...(Components) == sizeof...(Args) && PassEntity> = 0>
24151+
static flecs::entity invoke_callback(
24152+
ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
24153+
{
24154+
ECS_TABLE_LOCK(iter->world, iter->table);
24155+
24156+
ecs_world_t *world = iter->world;
24157+
size_t count = static_cast<size_t>(iter->count);
24158+
24159+
ecs_assert(count > 0, ECS_INVALID_OPERATION,
24160+
"no entities returned, use find() without flecs::entity argument");
24161+
24162+
for (size_t i = 0; i < count; i ++) {
24163+
if (func(flecs::entity(world, iter->entities[i]),
24164+
(ColumnType< remove_reference_t<Components> >(comps, i)
24165+
.get_row())...))
24166+
{
24167+
return flecs::entity(world, iter->entities[i]);
24168+
}
24169+
}
24170+
24171+
ECS_TABLE_UNLOCK(iter->world, iter->table);
24172+
24173+
return flecs::entity();
24174+
}
24175+
24176+
// Number of function arguments is two more than number of components, pass
24177+
// iter + index as argument.
24178+
template <template<typename X, typename = int> class ColumnType,
24179+
typename... Args, int Enabled = PassIter, if_t<
24180+
sizeof...(Components) == sizeof...(Args) && Enabled> = 0>
24181+
static flecs::entity invoke_callback(
24182+
ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
24183+
{
24184+
size_t count = static_cast<size_t>(iter->count);
24185+
if (count == 0) {
24186+
// If query has no This terms, count can be 0. Since each does not
24187+
// have an entity parameter, just pass through components
24188+
count = 1;
24189+
}
24190+
24191+
flecs::iter it(iter);
24192+
24193+
ECS_TABLE_LOCK(iter->world, iter->table);
24194+
24195+
for (size_t i = 0; i < count; i ++) {
24196+
if (func(it, i, (ColumnType< remove_reference_t<Components> >(comps, i)
24197+
.get_row())...))
24198+
{
24199+
return flecs::entity(world, iter->entities[i]);
24200+
}
24201+
}
24202+
24203+
ECS_TABLE_UNLOCK(iter->world, iter->table);
24204+
24205+
return flecs::entity();
24206+
}
24207+
24208+
// Number of function arguments is equal to number of components, no entity
24209+
template <template<typename X, typename = int> class ColumnType,
24210+
typename... Args, if_t<
24211+
sizeof...(Components) == sizeof...(Args) && !PassEntity && !PassIter> = 0>
24212+
static flecs::entity invoke_callback(
24213+
ecs_iter_t *iter, const Func& func, size_t, Terms&, Args... comps)
24214+
{
24215+
size_t count = static_cast<size_t>(iter->count);
24216+
if (count == 0) {
24217+
// If query has no This terms, count can be 0. Since each does not
24218+
// have an entity parameter, just pass through components
24219+
count = 1;
24220+
}
24221+
24222+
flecs::iter it(iter);
24223+
24224+
ECS_TABLE_LOCK(iter->world, iter->table);
24225+
24226+
for (size_t i = 0; i < count; i ++) {
24227+
if (func( (ColumnType< remove_reference_t<Components> >(comps, i)
24228+
.get_row())...))
24229+
{
24230+
return flecs::entity(world, iter->entities[i]);
24231+
}
24232+
}
24233+
24234+
ECS_TABLE_UNLOCK(iter->world, iter->table);
24235+
}
24236+
24237+
template <template<typename X, typename = int> class ColumnType,
24238+
typename... Args, if_t< sizeof...(Components) != sizeof...(Args) > = 0>
24239+
static flecs::entity invoke_callback(ecs_iter_t *iter, const Func& func,
24240+
size_t index, Terms& columns, Args... comps)
24241+
{
24242+
return invoke_callback<ColumnType>(
24243+
iter, func, index + 1, columns, comps..., columns[index]);
24244+
}
24245+
24246+
Func m_func;
24247+
};
2410324248

2410424249
////////////////////////////////////////////////////////////////////////////////
2410524250
//// Utility class to invoke a system iterate action
@@ -24480,6 +24625,12 @@ struct iterable {
2448024625
this->next_each_action());
2448124626
}
2448224627

24628+
template <typename Func>
24629+
flecs::entity find(Func&& func) const {
24630+
iterate<_::find_invoker>(nullptr, FLECS_FWD(func),
24631+
this->next_each_action());
24632+
}
24633+
2448324634
/** Iter iterator.
2448424635
* The "iter" iterator accepts a function that is invoked for each matching
2448524636
* table. The following function signatures are valid:

0 commit comments

Comments
 (0)