Skip to content

Commit

Permalink
#1067 Add ability to iterate cascade in descending order
Browse files Browse the repository at this point in the history
* Add ability to iterate cascade in descending order

* Fix hanging custom_builds/c/define_debug_and_sanitize test
  • Loading branch information
SanderMertens authored Nov 5, 2023
1 parent 45d18c6 commit 1e2baf1
Show file tree
Hide file tree
Showing 19 changed files with 480 additions and 33 deletions.
1 change: 1 addition & 0 deletions docs/Queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -1803,6 +1803,7 @@ Traversal behavior can be customized with the following bitflags, in addition to
| Down | `down` | `EcsDown` | `flecs::Down` | Match by traversing downwards (derived, cannot be set) |
| Parent | `parent` | `EcsParent` | `flecs::Parent` | Short for up(ChildOf) |
| Cascade | `cascade` | `EcsCascade` | `flecs::Cascade` | Same as Up, but iterate in breadth-first order |
| Desc | `desc` | `EcsDesc` | `flecs::Desc` | Combine with Cascade to iterate hierarchy bottom to top |

If just `Self` is set a query will only match components on the matched entity (no traversal). If just `Up` is set, a query will only match components that can be reached by following the relationship and ignore components from the matched entity. If both `Self` and `Up` are set, the query will first look on the matched entity, and if it does not have the component the query will continue searching by traverse the relationship.

Expand Down
33 changes: 29 additions & 4 deletions flecs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,7 @@ struct ecs_query_t {
/* Monitor generation */
int32_t monitor_generation;

int32_t cascade_by; /* Identify cascade column */
int32_t cascade_by; /* Identify cascade term */
int32_t match_count; /* How often have tables been (un)matched */
int32_t prev_match_count; /* Track if sorting is needed */
int32_t rematch_count; /* Track which tables were added during rematch */
Expand Down Expand Up @@ -17273,12 +17273,26 @@ ecs_query_table_match_t* flecs_query_find_group_insertion_node(
ecs_map_iter_t it = ecs_map_iter(&query->groups);
ecs_query_table_list_t *list, *closest_list = NULL;
uint64_t id, closest_id = 0;

bool desc = false;

if (query->cascade_by) {
desc = (query->filter.terms[
query->cascade_by - 1].src.flags & EcsDesc) != 0;
}

/* Find closest smaller group id */
while (ecs_map_next(&it)) {
id = ecs_map_key(&it);
if (id >= group_id) {
continue;

if (!desc) {
if (id >= group_id) {
continue;
}
} else {
if (id <= group_id) {
continue;
}
}

list = ecs_map_ptr(&it);
Expand All @@ -17287,7 +17301,14 @@ ecs_query_table_match_t* flecs_query_find_group_insertion_node(
continue;
}

if (!closest_list || ((group_id - id) < (group_id - closest_id))) {
bool comp;
if (!desc) {
comp = ((group_id - id) < (group_id - closest_id));
} else {
comp = ((group_id - id) > (group_id - closest_id));
}

if (!closest_list || comp) {
closest_id = id;
closest_list = list;
}
Expand Down Expand Up @@ -30153,6 +30174,7 @@ void FlecsMonitorImport(
#define TOK_DOWN "down"
#define TOK_CASCADE "cascade"
#define TOK_PARENT "parent"
#define TOK_DESC "desc"

#define TOK_OVERRIDE "OVERRIDE"
#define TOK_ROLE_AND "AND"
Expand Down Expand Up @@ -30497,6 +30519,8 @@ uint8_t flecs_parse_set_token(
return EcsDown;
} else if (!ecs_os_strcmp(token, TOK_CASCADE)) {
return EcsCascade;
} else if (!ecs_os_strcmp(token, TOK_DESC)) {
return EcsDesc;
} else if (!ecs_os_strcmp(token, TOK_PARENT)) {
return EcsParent;
} else {
Expand Down Expand Up @@ -30663,6 +30687,7 @@ const char* flecs_parse_arguments(

/* Check for term flags */
} else if (!ecs_os_strcmp(token, TOK_CASCADE) ||
!ecs_os_strcmp(token, TOK_DESC) ||
!ecs_os_strcmp(token, TOK_SELF) ||
!ecs_os_strcmp(token, TOK_UP) ||
!ecs_os_strcmp(token, TOK_DOWN) ||
Expand Down
21 changes: 15 additions & 6 deletions flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2905,12 +2905,13 @@ typedef enum ecs_oper_kind_t {
#define EcsDown (1u << 3) /**< Match by traversing downwards (derived, cannot be set) */
#define EcsTraverseAll (1u << 4) /**< Match all entities encountered through traversal */
#define EcsCascade (1u << 5) /**< Sort results breadth first */
#define EcsParent (1u << 6) /**< Short for up(ChildOf) */
#define EcsIsVariable (1u << 7) /**< Term id is a variable */
#define EcsIsEntity (1u << 8) /**< Term id is an entity */
#define EcsIsName (1u << 9) /**< Term id is a name (don't attempt to lookup as entity) */
#define EcsFilter (1u << 10) /**< Prevent observer from triggering on term */
#define EcsTraverseFlags (EcsUp|EcsDown|EcsTraverseAll|EcsSelf|EcsCascade|EcsParent)
#define EcsDesc (1u << 6) /**< Iterate groups in descending order */
#define EcsParent (1u << 7) /**< Short for up(ChildOf) */
#define EcsIsVariable (1u << 8) /**< Term id is a variable */
#define EcsIsEntity (1u << 9) /**< Term id is an entity */
#define EcsIsName (1u << 10) /**< Term id is a name (don't attempt to lookup as entity) */
#define EcsFilter (1u << 11) /**< Prevent observer from triggering on term */
#define EcsTraverseFlags (EcsUp|EcsDown|EcsTraverseAll|EcsSelf|EcsCascade|EcsDesc|EcsParent)

/* Term flags discovered & set during filter creation. Mostly used internally to
* store information relevant to queries. */
Expand Down Expand Up @@ -15842,6 +15843,7 @@ static const uint32_t Self = EcsSelf;
static const uint32_t Up = EcsUp;
static const uint32_t Down = EcsDown;
static const uint32_t Cascade = EcsCascade;
static const uint32_t Desc = EcsDesc;
static const uint32_t Parent = EcsParent;
static const uint32_t IsVariable = EcsIsVariable;
static const uint32_t IsEntity = EcsIsEntity;
Expand Down Expand Up @@ -26862,6 +26864,13 @@ struct term_id_builder_i {
return this->cascade(_::cpp_type<Trav>::id(this->world_v()));
}

/* Use with cascade to iterate results in descending (bottom -> top) order */
Base& desc() {
this->assert_term_id();
m_term_id->flags |= flecs::Desc;
return *this;
}

/* The parent flag is short for up(flecs::ChildOf) */
Base& parent() {
this->assert_term_id();
Expand Down
13 changes: 7 additions & 6 deletions include/flecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -673,12 +673,13 @@ typedef enum ecs_oper_kind_t {
#define EcsDown (1u << 3) /**< Match by traversing downwards (derived, cannot be set) */
#define EcsTraverseAll (1u << 4) /**< Match all entities encountered through traversal */
#define EcsCascade (1u << 5) /**< Sort results breadth first */
#define EcsParent (1u << 6) /**< Short for up(ChildOf) */
#define EcsIsVariable (1u << 7) /**< Term id is a variable */
#define EcsIsEntity (1u << 8) /**< Term id is an entity */
#define EcsIsName (1u << 9) /**< Term id is a name (don't attempt to lookup as entity) */
#define EcsFilter (1u << 10) /**< Prevent observer from triggering on term */
#define EcsTraverseFlags (EcsUp|EcsDown|EcsTraverseAll|EcsSelf|EcsCascade|EcsParent)
#define EcsDesc (1u << 6) /**< Iterate groups in descending order */
#define EcsParent (1u << 7) /**< Short for up(ChildOf) */
#define EcsIsVariable (1u << 8) /**< Term id is a variable */
#define EcsIsEntity (1u << 9) /**< Term id is an entity */
#define EcsIsName (1u << 10) /**< Term id is a name (don't attempt to lookup as entity) */
#define EcsFilter (1u << 11) /**< Prevent observer from triggering on term */
#define EcsTraverseFlags (EcsUp|EcsDown|EcsTraverseAll|EcsSelf|EcsCascade|EcsDesc|EcsParent)

/* Term flags discovered & set during filter creation. Mostly used internally to
* store information relevant to queries. */
Expand Down
1 change: 1 addition & 0 deletions include/flecs/addons/cpp/c_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ static const uint32_t Self = EcsSelf;
static const uint32_t Up = EcsUp;
static const uint32_t Down = EcsDown;
static const uint32_t Cascade = EcsCascade;
static const uint32_t Desc = EcsDesc;
static const uint32_t Parent = EcsParent;
static const uint32_t IsVariable = EcsIsVariable;
static const uint32_t IsEntity = EcsIsEntity;
Expand Down
7 changes: 7 additions & 0 deletions include/flecs/addons/cpp/mixins/term/builder_i.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ struct term_id_builder_i {
return this->cascade(_::cpp_type<Trav>::id(this->world_v()));
}

/* Use with cascade to iterate results in descending (bottom -> top) order */
Base& desc() {
this->assert_term_id();
m_term_id->flags |= flecs::Desc;
return *this;
}

/* The parent flag is short for up(flecs::ChildOf) */
Base& parent() {
this->assert_term_id();
Expand Down
4 changes: 4 additions & 0 deletions src/addons/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#define TOK_DOWN "down"
#define TOK_CASCADE "cascade"
#define TOK_PARENT "parent"
#define TOK_DESC "desc"

#define TOK_OVERRIDE "OVERRIDE"
#define TOK_ROLE_AND "AND"
Expand Down Expand Up @@ -377,6 +378,8 @@ uint8_t flecs_parse_set_token(
return EcsDown;
} else if (!ecs_os_strcmp(token, TOK_CASCADE)) {
return EcsCascade;
} else if (!ecs_os_strcmp(token, TOK_DESC)) {
return EcsDesc;
} else if (!ecs_os_strcmp(token, TOK_PARENT)) {
return EcsParent;
} else {
Expand Down Expand Up @@ -543,6 +546,7 @@ const char* flecs_parse_arguments(

/* Check for term flags */
} else if (!ecs_os_strcmp(token, TOK_CASCADE) ||
!ecs_os_strcmp(token, TOK_DESC) ||
!ecs_os_strcmp(token, TOK_SELF) ||
!ecs_os_strcmp(token, TOK_UP) ||
!ecs_os_strcmp(token, TOK_DOWN) ||
Expand Down
2 changes: 1 addition & 1 deletion src/private_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ struct ecs_query_t {
/* Monitor generation */
int32_t monitor_generation;

int32_t cascade_by; /* Identify cascade column */
int32_t cascade_by; /* Identify cascade term */
int32_t match_count; /* How often have tables been (un)matched */
int32_t prev_match_count; /* Track if sorting is needed */
int32_t rematch_count; /* Track which tables were added during rematch */
Expand Down
27 changes: 24 additions & 3 deletions src/query.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,26 @@ ecs_query_table_match_t* flecs_query_find_group_insertion_node(
ecs_map_iter_t it = ecs_map_iter(&query->groups);
ecs_query_table_list_t *list, *closest_list = NULL;
uint64_t id, closest_id = 0;

bool desc = false;

if (query->cascade_by) {
desc = (query->filter.terms[
query->cascade_by - 1].src.flags & EcsDesc) != 0;
}

/* Find closest smaller group id */
while (ecs_map_next(&it)) {
id = ecs_map_key(&it);
if (id >= group_id) {
continue;

if (!desc) {
if (id >= group_id) {
continue;
}
} else {
if (id <= group_id) {
continue;
}
}

list = ecs_map_ptr(&it);
Expand All @@ -133,7 +147,14 @@ ecs_query_table_match_t* flecs_query_find_group_insertion_node(
continue;
}

if (!closest_list || ((group_id - id) < (group_id - closest_id))) {
bool comp;
if (!desc) {
comp = ((group_id - id) < (group_id - closest_id));
} else {
comp = ((group_id - id) > (group_id - closest_id));
}

if (!closest_list || comp) {
closest_id = id;
closest_list = list;
}
Expand Down
3 changes: 2 additions & 1 deletion test/addons/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@
"pair_3_args_implicit_this",
"pair_4_args",
"pair_4_args_implicit_this",
"pair_3_args_2_terms"
"pair_3_args_2_terms",
"cascade_desc"
]
}, {
"id": "Plecs",
Expand Down
23 changes: 23 additions & 0 deletions test/addons/src/Parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -5532,3 +5532,26 @@ void Parser_pair_3_args_2_terms(void) {
ecs_fini(world);
}

void Parser_cascade_desc(void) {
ecs_world_t *world = ecs_mini();

ECS_TAG(world, Pred);

ecs_filter_t f = ECS_FILTER_INIT;
test_assert(NULL != ecs_filter_init(world, &(ecs_filter_desc_t){
.storage = &f,
.expr = "Pred(cascade|desc)"
}));
test_int(filter_count(&f), 1);

ecs_term_t *terms = filter_terms(&f);
test_first(terms[0], Pred, EcsSelf|EcsIsEntity);
test_src(terms[0], EcsThis, EcsUp|EcsCascade|EcsDesc|EcsIsVariable);
test_int(terms[0].oper, EcsAnd);
test_int(terms[0].inout, EcsInOutDefault);
test_int(terms[0].src.trav, EcsIsA);

ecs_filter_fini(&f);

ecs_fini(world);
}
7 changes: 6 additions & 1 deletion test/addons/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ void Parser_pair_3_args_implicit_this(void);
void Parser_pair_4_args(void);
void Parser_pair_4_args_implicit_this(void);
void Parser_pair_3_args_2_terms(void);
void Parser_cascade_desc(void);

// Testsuite 'Plecs'
void Plecs_null(void);
Expand Down Expand Up @@ -2519,6 +2520,10 @@ bake_test_case Parser_testcases[] = {
{
"pair_3_args_2_terms",
Parser_pair_3_args_2_terms
},
{
"cascade_desc",
Parser_cascade_desc
}
};

Expand Down Expand Up @@ -7741,7 +7746,7 @@ static bake_test_suite suites[] = {
"Parser",
NULL,
NULL,
231,
232,
Parser_testcases
},
{
Expand Down
5 changes: 5 additions & 0 deletions test/api/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,8 @@
"new_custom_rel_cascade",
"cascade_w_2_depths",
"cascade_w_3_depths",
"cascade_w_2_depths_desc",
"cascade_w_3_depths_desc",
"not_pair_relation_wildcard",
"not_pair_object_wildcard",
"two_pair_wildcards_one_not",
Expand Down Expand Up @@ -1630,6 +1632,9 @@
"cascade_rematch_2_lvls",
"cascade_rematch_2_lvls_2_relations",
"cascade_topological",
"cascade_desc_rematch_2_lvls",
"cascade_desc_rematch_2_lvls_2_relations",
"cascade_desc_topological",
"childof_rematch_from_isa",
"rematch_optional_ref",
"rematch_optional_ref_w_2_refs",
Expand Down
Loading

0 comments on commit 1e2baf1

Please sign in to comment.