Skip to content
Flecs v4.1
queries/group_by

  • C

    View on GitHub

    1#include <group_by.h>
    2#include <stdio.h>
    3
    4// Group by is a feature of cached queries that allows applications to assign a
    5// group id to each matched table. Tables that are assigned the same group id
    6// are stored together in "groups". This ensures that when a query is iterated,
    7// tables that share a group are iterated together.
    8//
    9// Groups in the cache are ordered by group id, which ensures that tables with
    10// lower ids are iterated before table with higher ids. This is the same
    11// mechanism that is used by the cascade feature, which groups tables by depth
    12// in a relationship hierarchy.
    13//
    14// This makes groups a more efficient, though less granular mechanism for
    15// ordering entities. Order is maintained at the group level, which means that
    16// once a group is created, tables can get added and removed to the group
    17// with is an O(1) operation.
    18//
    19// Groups can also be used as an efficient filtering mechanism. See the
    20// group_iter example for more details.
    21
    22typedef struct {
    23 double x, y;
    24} Position;
    25
    26int main(int argc, char *argv[]) {
    27 ecs_world_t *ecs = ecs_init_w_args(argc, argv);
    28
    29 ECS_COMPONENT(ecs, Position);
    30 ECS_TAG(ecs, Tag); // Dummy tag to put entities in different tables
    31
    32 // Create a relationship to use for the group_by function. Tables will
    33 // be assigned the relationship target as group id
    34 ECS_TAG(ecs, Group);
    35
    36 // Targets for the relationship, which will be used as group ids.
    37 ECS_TAG(ecs, First);
    38 ECS_TAG(ecs, Second);
    39 ECS_TAG(ecs, Third);
    40
    41 // Grouped query
    42 ecs_query_t *q = ecs_query(ecs, {
    43 .terms = {
    44 { .id = ecs_id(Position) }
    45 },
    46 // Group tables by the relationship target of the "Group" relationship.
    47 // A custom group_by function can be provided to derive a group id from
    48 // a table, see the group_by_custom example for more details.
    49 .group_by = Group
    50 });
    51
    52 // Create entities in 6 different tables with 3 group ids
    53 ecs_entity_t e1 = ecs_new_w_pair(ecs, Group, Third);
    54 ecs_set(ecs, e1, Position, {1, 1});
    55
    56 ecs_entity_t e2 = ecs_new_w_pair(ecs, Group, Second);
    57 ecs_set(ecs, e2, Position, {2, 2});
    58
    59 ecs_entity_t e3 = ecs_new_w_pair(ecs, Group, First);
    60 ecs_set(ecs, e3, Position, {3, 3});
    61
    62 ecs_entity_t e4 = ecs_new_w_pair(ecs, Group, Third);
    63 ecs_set(ecs, e4, Position, {4, 4});
    64 ecs_add(ecs, e4, Tag);
    65
    66 ecs_entity_t e5 = ecs_new_w_pair(ecs, Group, Second);
    67 ecs_set(ecs, e5, Position, {5, 5});
    68 ecs_add(ecs, e5, Tag);
    69
    70 ecs_entity_t e6 = ecs_new_w_pair(ecs, Group, First);
    71 ecs_set(ecs, e6, Position, {6, 6});
    72 ecs_add(ecs, e6, Tag);
    73
    74 // The query cache now looks like this:
    75 // - group First:
    76 // - table [Position, (Group, First)]
    77 // - table [Position, Tag, (Group, First)]
    78 //
    79 // - group Second:
    80 // - table [Position, (Group, Second)]
    81 // - table [Position, Tag, (Group, Second)]
    82 //
    83 // - group Third:
    84 // - table [Position, (Group, Third)]
    85 // - table [Position, Tag, (Group, Third)]
    86 //
    87
    88 // Iterate query, print position & table components
    89 ecs_iter_t it = ecs_query_iter(ecs, q);
    90 while (ecs_query_next(&it)) {
    91 Position *p = ecs_field(&it, Position, 0);
    92 char *table_str = ecs_table_str(ecs, it.table);
    93 char *group_str = ecs_get_path(ecs, ecs_iter_get_group(&it));
    94
    95 printf(" - group %s: table [%s]\n", group_str, table_str);
    96
    97 for (int i = 0; i < it.count; i ++) {
    98 printf(" {%f, %f}\n", p[i].x, p[i].y);
    99 }
    100
    101 ecs_os_free(group_str);
    102 ecs_os_free(table_str);
    103 printf("\n");
    104 }
    105
    106 // Output:
    107 // - group First: table [Position, (Group,First)]
    108 // {3.000000, 3.000000}
    109 //
    110 // - group First: table [Position, Tag, (Group,First)]
    111 // {6.000000, 6.000000}
    112 //
    113 // - group Second: table [Position, (Group,Second)]
    114 // {2.000000, 2.000000}
    115 //
    116 // - group Second: table [Position, Tag, (Group,Second)]
    117 // {5.000000, 5.000000}
    118 //
    119 // - group Third: table [Position, (Group,Third)]
    120 // {1.000000, 1.000000}
    121 //
    122 // - group Third: table [Position, Tag, (Group,Third)]
    123 // {4.000000, 4.000000}
    124
    125 return ecs_fini(ecs);
    126}
    FLECS_API const ecs_entity_t ecs_id(EcsDocDescription)
    Component ID for EcsDocDescription.
    ecs_id_t ecs_entity_t
    An entity identifier.
    Definition flecs.h:395
    struct ecs_world_t ecs_world_t
    A world is the container for all ECS data and supporting features.
    Definition flecs.h:439
    char * ecs_table_str(const ecs_world_t *world, const ecs_table_t *table)
    Convert a table to a string.
    #define ecs_add(world, entity, T)
    Add a component to an entity.
    Definition flecs_c.h:271
    #define ecs_new_w_pair(world, first, second)
    Create a new entity with a pair.
    Definition flecs_c.h:256
    #define ECS_COMPONENT(world, id)
    Declare and define a component.
    Definition flecs_c.h:98
    #define ECS_TAG(world, id)
    Declare and define a tag.
    Definition flecs_c.h:59
    #define ecs_query(world,...)
    Shorthand for creating a query with ecs_query_init().
    Definition flecs_c.h:215
    #define ecs_get_path(world, child)
    Get path from root.
    Definition flecs_c.h:594
    #define ecs_set(world, entity, component,...)
    Set a component value.
    Definition flecs_c.h:310
    #define ecs_field(it, T, index)
    Get field data for a component.
    Definition flecs_c.h:720
    uint64_t ecs_iter_get_group(const ecs_iter_t *it)
    Return the group ID for the currently iterated result.
    bool ecs_query_next(ecs_iter_t *it)
    Progress a query iterator.
    ecs_iter_t ecs_query_iter(const ecs_world_t *world, const ecs_query_t *query)
    Create a query iterator.
    int ecs_fini(ecs_world_t *world)
    Delete a world.
    ecs_world_t * ecs_init_w_args(int argc, char *argv[])
    Create a new world with arguments.
    Iterator.
    Definition flecs.h:1183
    ecs_table_t * table
    Current table.
    Definition flecs.h:1195
    int32_t count
    Number of entities to iterate.
    Definition flecs.h:1189
    Queries are lists of constraints (terms) that match entities.
    Definition flecs.h:858

  • C++

    View on GitHub

    1#include <group_by.h>
    2#include <iostream>
    3
    4// Group by is a feature of cached queries that allows applications to assign a
    5// group id to each matched table. Tables that are assigned the same group id
    6// are stored together in "groups". This ensures that when a query is iterated,
    7// tables that share a group are iterated together.
    8//
    9// Groups in the cache are ordered by group id, which ensures that tables with
    10// lower ids are iterated before table with higher ids. This is the same
    11// mechanism that is used by the cascade feature, which groups tables by depth
    12// in a relationship hierarchy.
    13//
    14// This makes groups a more efficient, though less granular mechanism for
    15// ordering entities. Order is maintained at the group level, which means that
    16// once a group is created, tables can get added and removed to the group
    17// with is an O(1) operation.
    18//
    19// Groups can also be used as an efficient filtering mechanism. See the
    20// set_group example for more details.
    21
    22struct Position {
    23 double x, y;
    24};
    25
    26// Dummy tag to put entities in different tables
    27struct Tag { };
    28
    29// Create a relationship to use for the group_by function. Tables will
    30// be assigned the relationship target as group id
    31struct Group { };
    32
    33// Targets for the relationship, which will be used as group ids.
    34struct First { };
    35struct Second { };
    36struct Third { };
    37
    38int main() {
    39 flecs::world ecs;
    40
    41 // Register components in order so that id for First is lower than Third
    42 ecs.component<First>();
    43 ecs.component<Second>();
    44 ecs.component<Third>();
    45
    46 // Grouped query
    47 flecs::query<Position> q = ecs.query_builder<Position>()
    48 .group_by<Group>()
    49 .build();
    50
    51 // Create entities in 6 different tables with 3 group ids
    52 ecs.entity().add<Group, Third>()
    53 .set<Position>({1, 1});
    54 ecs.entity().add<Group, Second>()
    55 .set<Position>({2, 2});
    56 ecs.entity().add<Group, First>()
    57 .set<Position>({3, 3});
    58
    59 ecs.entity().add<Group, Third>()
    60 .set<Position>({4, 4})
    61 .add<Tag>();
    62 ecs.entity().add<Group, Second>()
    63 .set<Position>({5, 5})
    64 .add<Tag>();
    65 ecs.entity().add<Group, First>()
    66 .set<Position>({6, 6})
    67 .add<Tag>();
    68
    69 // The query cache now looks like this:
    70 // - group First:
    71 // - table [Position, (Group, First)]
    72 // - table [Position, Tag, (Group, First)]
    73 //
    74 // - group Second:
    75 // - table [Position, (Group, Second)]
    76 // - table [Position, Tag, (Group, Second)]
    77 //
    78 // - group Third:
    79 // - table [Position, (Group, Third)]
    80 // - table [Position, Tag, (Group, Third)]
    81 //
    82
    83 q.run([&](flecs::iter& it) {
    84 while (it.next()) {
    85 auto p = it.field<Position>(0);
    86
    87 flecs::entity group = ecs.entity(it.group_id());
    88 std::cout << " - group " << group.path() << ": "
    89 << "table [" << it.table().str() << "]\n";
    90
    91 for (auto i : it) {
    92 std::cout << " {" << p[i].x << ", " << p[i].y << "}\n";
    93 }
    94
    95 std::cout << "\n";
    96 }
    97 });
    98
    99 // Output:
    100 // - group ::First: table [Position, (Group,First)]
    101 // {3, 3}
    102 //
    103 // - group ::First: table [Position, Tag, (Group,First)]
    104 // {6, 6}
    105 //
    106 // - group ::Second: table [Position, (Group,Second)]
    107 // {2, 2}
    108 //
    109 // - group ::Second: table [Position, Tag, (Group,Second)]
    110 // {5, 5}
    111 //
    112 // - group ::Third: table [Position, (Group,Third)]
    113 // {1, 1}
    114 //
    115 // - group ::Third: table [Position, Tag, (Group,Third)]
    116 // {4, 4}
    117}
    flecs::component< T > component(Args &&... args) const
    Find or register a component.
    Definition impl.hpp:11
    flecs::query_builder< Comps... > query_builder(Args &&... args) const
    Create a query builder.
    Definition impl.hpp:342
    flecs::entity entity(Args &&... args) const
    Create an entity.
    Definition impl.hpp:195
    flecs::string path(const char *sep="::", const char *init_sep="::") const
    Return the entity path.
    Entity.
    Definition entity.hpp:30
    Class for iterating over query results.
    Definition iter.hpp:68
    flecs::field< A > field(int8_t index) const
    Get read-only access to field data.
    Definition iter.hpp:84
    flecs::table table() const
    Get the table for the current iterator result.
    Definition iter.hpp:67
    uint64_t group_id() const
    Return the group ID for the current table (grouped queries only).
    Definition iter.hpp:434
    bool next()
    Progress iterator.
    Definition iter.hpp:465
    Typed query.
    Definition impl.hpp:271
    flecs::string str() const
    Convert the table type to a string.
    Definition table.hpp:40
    The world.
    Definition world.hpp:129