• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef CORE_UTIL_ECS_COMPONENT_QUERY_H
17 #define CORE_UTIL_ECS_COMPONENT_QUERY_H
18 
19 #include <base/containers/unordered_map.h>
20 #include <core/ecs/intf_component_manager.h>
21 #include <core/ecs/intf_ecs.h>
22 #include <core/namespace.h>
23 
CORE_BEGIN_NAMESPACE()24 CORE_BEGIN_NAMESPACE()
25 /** Executes queries to component managers and outputs a result set that can be used to speed-up component data access.
26  */
27 class ComponentQuery : private IEcs::EntityListener, private IEcs::ComponentListener {
28 public:
29     ComponentQuery() = default;
30     ~ComponentQuery() override;
31 
32     /** Operations for the component query that are being applied in to of the base component set. */
33     struct Operation {
34         /** Method of operation. */
35         enum Method : uint8_t {
36             /** Looks up a component of given type and filters out the entity from the base set if it doesn't contain
37                such component. */
38             REQUIRE,
39             /** Looks up a component of given type, but never filters out the entity from the base set. */
40             OPTIONAL
41         };
42         const IComponentManager& target;
43         Method method { REQUIRE };
44     };
45 
46     /** Sets up a component query to component managers.
47      * @param baseComponentSet Components that are used as a base set for query, this should be the component manager
48      * that has least amount of components.
49      * @param operations Operations that are performed to base set when other component managers are merged to result.
50      * @param enableEntityLookup If true, allows to look up result row by using entity as a key (FindResultRow), this
51      * slightly slows down the look-up process.
52      */
53     void SetupQuery(const IComponentManager& baseComponentSet, BASE_NS::array_view<const Operation> operations,
54         bool enableEntityLookup = false);
55 
56     /** Executes the query. Assumes that the query has been set up earlier.
57      * @return True if there are possible changes in the query result since previous execute.
58      */
59     bool Execute();
60 
61     [[deprecated]] void Execute(const IComponentManager& baseComponentSet,
62         BASE_NS::array_view<const Operation> operations, bool enableEntityLookup = false);
63 
64     /** Enable or disable listening to ECS events. Enabling listeners will automatically invalidate this query when
65      * there are changes in the relevant component managers.
66      * @param enableListeners True to enable listening to ecs events to automatically invalidate the query.
67      */
68     void SetEcsListenersEnabled(bool enableListeners);
69 
70     /** Check if the result of this query is still valid. Requires a call to RegisterEcsListeners after each execution.
71      * @return True if there have been no changes in listened component managers since previous execute that would
72      * affect the query result.
73      */
74     bool IsValid() const;
75 
76     /** One row in a result set, describes the entity and its component ids. */
77     struct ResultRow {
78         ResultRow() = default;
79         ~ResultRow() = default;
80 
81         ResultRow(const ResultRow& rhs) = delete;
82         ResultRow& operator=(const ResultRow& rhs) = delete;
83         ResultRow(ResultRow&& rhs) noexcept = default;
84         ResultRow& operator=(ResultRow&& rhs) noexcept = default;
85 
86         /** Checks whether component id in given index is valid.
87          * The component id can be invalid if the component was specified optional and it is not available)
88          * @param index Index of the component.
89          * @return True if the component id is valid, false if the component id is invalid (optional components that is
90          * not available).
91          */
92         bool IsValidComponentId(size_t index) const;
93 
94         /** Entity that contains the components. */
95         Entity entity;
96 
97         /** List of component ids, in the same order that the component managers were specified in the Execute(...)
98          * call. */
99         BASE_NS::vector<IComponentManager::ComponentId> components;
100     };
101 
102     /** Returns The result of the query, in form of rows.
103      * @return Array of result rows, where each row describes an entity and its component ids.
104      */
105     BASE_NS::array_view<const ResultRow> GetResults() const;
106 
107     /** Look up result row for a given entity. To enable this functionality, the Execute() function needs to be called
108      * with enableEntityLookup parameter set as true.
109      * @param entity Entity to use in look-up
110      * @return Pointer to result row for given entity, or nullptr if there is no such row.
111      */
112     const ResultRow* FindResultRow(Entity entity) const;
113 
114 private:
115     void RegisterEcsListeners();
116     void UnregisterEcsListeners();
117 
118     // IEcs::EntityListener
119     void OnEntityEvent(IEcs::EntityListener::EventType type, BASE_NS::array_view<const Entity> entities) override;
120 
121     // IEcs::ComponentListener
122     void OnComponentEvent(IEcs::ComponentListener::EventType type, const IComponentManager& componentManager,
123         BASE_NS::array_view<const Entity> entities) override;
124 
125     CORE_NS::IEcs* ecs_ { nullptr };
126     BASE_NS::vector<ResultRow> result_;
127     BASE_NS::vector<IComponentManager*> managers_;
128     BASE_NS::vector<Operation::Method> operationMethods_;
129     BASE_NS::unordered_map<Entity, size_t> mapping_;
130     bool enableLookup_ { false };
131     bool enableListeners_ { false };
132     bool registered_ { false };
133     bool valid_ { false };
134 };
135 CORE_END_NAMESPACE()
136 
137 #endif // CORE_UTIL_ECS_COMPONENT_QUERY
138