18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#ifndef CORE_UTIL_ECS_COMPONENT_QUERY_H
178bf80f4bSopenharmony_ci#define CORE_UTIL_ECS_COMPONENT_QUERY_H
188bf80f4bSopenharmony_ci
198bf80f4bSopenharmony_ci#include <cstddef>
208bf80f4bSopenharmony_ci#include <cstdint>
218bf80f4bSopenharmony_ci
228bf80f4bSopenharmony_ci#include <base/containers/unordered_map.h>
238bf80f4bSopenharmony_ci#include <base/containers/vector.h>
248bf80f4bSopenharmony_ci#include <base/namespace.h>
258bf80f4bSopenharmony_ci#include <core/ecs/entity.h>
268bf80f4bSopenharmony_ci#include <core/ecs/intf_component_manager.h>
278bf80f4bSopenharmony_ci#include <core/ecs/intf_ecs.h>
288bf80f4bSopenharmony_ci#include <core/namespace.h>
298bf80f4bSopenharmony_ci
308bf80f4bSopenharmony_ciBASE_BEGIN_NAMESPACE()
318bf80f4bSopenharmony_citemplate<class T>
328bf80f4bSopenharmony_ciclass array_view;
338bf80f4bSopenharmony_ciBASE_END_NAMESPACE()
348bf80f4bSopenharmony_ci
358bf80f4bSopenharmony_ciCORE_BEGIN_NAMESPACE()
368bf80f4bSopenharmony_ci/** Executes queries to component managers and outputs a result set that can be used to speed-up component data access.
378bf80f4bSopenharmony_ci */
388bf80f4bSopenharmony_ciclass ComponentQuery : private IEcs::EntityListener, private IEcs::ComponentListener {
398bf80f4bSopenharmony_cipublic:
408bf80f4bSopenharmony_ci    ComponentQuery() = default;
418bf80f4bSopenharmony_ci    ~ComponentQuery() override;
428bf80f4bSopenharmony_ci
438bf80f4bSopenharmony_ci    /** Operations for the component query that are being applied in to of the base component set. */
448bf80f4bSopenharmony_ci    struct Operation {
458bf80f4bSopenharmony_ci        /** Method of operation. */
468bf80f4bSopenharmony_ci        enum Method : uint8_t {
478bf80f4bSopenharmony_ci            /** Looks up a component of given type and filters out the entity from the base set if it doesn't contain
488bf80f4bSopenharmony_ci               such component. */
498bf80f4bSopenharmony_ci            REQUIRE,
508bf80f4bSopenharmony_ci            /** Looks up a component of given type, but never filters out the entity from the base set. */
518bf80f4bSopenharmony_ci            OPTIONAL
528bf80f4bSopenharmony_ci        };
538bf80f4bSopenharmony_ci        const IComponentManager& target;
548bf80f4bSopenharmony_ci        Method method { REQUIRE };
558bf80f4bSopenharmony_ci    };
568bf80f4bSopenharmony_ci
578bf80f4bSopenharmony_ci    /** Sets up a component query to component managers.
588bf80f4bSopenharmony_ci     * @param baseComponentSet Components that are used as a base set for query, this should be the component manager
598bf80f4bSopenharmony_ci     * that has least amount of components.
608bf80f4bSopenharmony_ci     * @param operations Operations that are performed to base set when other component managers are merged to result.
618bf80f4bSopenharmony_ci     * @param enableEntityLookup If true, allows to look up result row by using entity as a key (FindResultRow), this
628bf80f4bSopenharmony_ci     * slightly slows down the look-up process.
638bf80f4bSopenharmony_ci     */
648bf80f4bSopenharmony_ci    void SetupQuery(const IComponentManager& baseComponentSet, BASE_NS::array_view<const Operation> operations,
658bf80f4bSopenharmony_ci        bool enableEntityLookup = false);
668bf80f4bSopenharmony_ci
678bf80f4bSopenharmony_ci    /** Executes the query. Assumes that the query has been set up earlier.
688bf80f4bSopenharmony_ci     * @return True if there are possible changes in the query result since previous execute.
698bf80f4bSopenharmony_ci     */
708bf80f4bSopenharmony_ci    bool Execute();
718bf80f4bSopenharmony_ci
728bf80f4bSopenharmony_ci    [[deprecated]] void Execute(const IComponentManager& baseComponentSet,
738bf80f4bSopenharmony_ci        BASE_NS::array_view<const Operation> operations, bool enableEntityLookup = false);
748bf80f4bSopenharmony_ci
758bf80f4bSopenharmony_ci    /** Enable or disable listening to ECS events. Enabling listeners will automatically invalidate this query when
768bf80f4bSopenharmony_ci     * there are changes in the relevant component managers.
778bf80f4bSopenharmony_ci     * @param enableListeners True to enable listening to ecs events to automatically invalidate the query.
788bf80f4bSopenharmony_ci     */
798bf80f4bSopenharmony_ci    void SetEcsListenersEnabled(bool enableListeners);
808bf80f4bSopenharmony_ci
818bf80f4bSopenharmony_ci    /** Check if the result of this query is still valid. Requires a call to RegisterEcsListeners after each execution.
828bf80f4bSopenharmony_ci     * @return True if there have been no changes in listened component managers since previous execute that would
838bf80f4bSopenharmony_ci     * affect the query result.
848bf80f4bSopenharmony_ci     */
858bf80f4bSopenharmony_ci    bool IsValid() const;
868bf80f4bSopenharmony_ci
878bf80f4bSopenharmony_ci    /** One row in a result set, describes the entity and its component ids. */
888bf80f4bSopenharmony_ci    struct ResultRow {
898bf80f4bSopenharmony_ci        ResultRow() = default;
908bf80f4bSopenharmony_ci        ~ResultRow() = default;
918bf80f4bSopenharmony_ci
928bf80f4bSopenharmony_ci        ResultRow(const ResultRow& rhs) = delete;
938bf80f4bSopenharmony_ci        ResultRow& operator=(const ResultRow& rhs) = delete;
948bf80f4bSopenharmony_ci        ResultRow(ResultRow&& rhs) noexcept = default;
958bf80f4bSopenharmony_ci        ResultRow& operator=(ResultRow&& rhs) noexcept = default;
968bf80f4bSopenharmony_ci
978bf80f4bSopenharmony_ci        /** Checks whether component id in given index is valid.
988bf80f4bSopenharmony_ci         * The component id can be invalid if the component was specified optional and it is not available)
998bf80f4bSopenharmony_ci         * @param index Index of the component.
1008bf80f4bSopenharmony_ci         * @return True if the component id is valid, false if the component id is invalid (optional components that is
1018bf80f4bSopenharmony_ci         * not available).
1028bf80f4bSopenharmony_ci         */
1038bf80f4bSopenharmony_ci        bool IsValidComponentId(size_t index) const;
1048bf80f4bSopenharmony_ci
1058bf80f4bSopenharmony_ci        /** Entity that contains the components. */
1068bf80f4bSopenharmony_ci        Entity entity;
1078bf80f4bSopenharmony_ci
1088bf80f4bSopenharmony_ci        /** List of component ids, in the same order that the component managers were specified in the Execute(...)
1098bf80f4bSopenharmony_ci         * call. */
1108bf80f4bSopenharmony_ci        BASE_NS::vector<IComponentManager::ComponentId> components;
1118bf80f4bSopenharmony_ci    };
1128bf80f4bSopenharmony_ci
1138bf80f4bSopenharmony_ci    /** Returns The result of the query, in form of rows.
1148bf80f4bSopenharmony_ci     * @return Array of result rows, where each row describes an entity and its component ids.
1158bf80f4bSopenharmony_ci     */
1168bf80f4bSopenharmony_ci    BASE_NS::array_view<const ResultRow> GetResults() const;
1178bf80f4bSopenharmony_ci
1188bf80f4bSopenharmony_ci    /** Look up result row for a given entity. To enable this functionality, the Execute() function needs to be called
1198bf80f4bSopenharmony_ci     * with enableEntityLookup parameter set as true.
1208bf80f4bSopenharmony_ci     * @param entity Entity to use in look-up
1218bf80f4bSopenharmony_ci     * @return Pointer to result row for given entity, or nullptr if there is no such row.
1228bf80f4bSopenharmony_ci     */
1238bf80f4bSopenharmony_ci    const ResultRow* FindResultRow(Entity entity) const;
1248bf80f4bSopenharmony_ci
1258bf80f4bSopenharmony_ciprivate:
1268bf80f4bSopenharmony_ci    void RegisterEcsListeners();
1278bf80f4bSopenharmony_ci    void UnregisterEcsListeners();
1288bf80f4bSopenharmony_ci
1298bf80f4bSopenharmony_ci    // IEcs::EntityListener
1308bf80f4bSopenharmony_ci    void OnEntityEvent(IEcs::EntityListener::EventType type, BASE_NS::array_view<const Entity> entities) override;
1318bf80f4bSopenharmony_ci
1328bf80f4bSopenharmony_ci    // IEcs::ComponentListener
1338bf80f4bSopenharmony_ci    void OnComponentEvent(IEcs::ComponentListener::EventType type, const IComponentManager& componentManager,
1348bf80f4bSopenharmony_ci        BASE_NS::array_view<const Entity> entities) override;
1358bf80f4bSopenharmony_ci
1368bf80f4bSopenharmony_ci    CORE_NS::IEcs* ecs_ { nullptr };
1378bf80f4bSopenharmony_ci    BASE_NS::vector<ResultRow> result_;
1388bf80f4bSopenharmony_ci    BASE_NS::vector<IComponentManager*> managers_;
1398bf80f4bSopenharmony_ci    BASE_NS::vector<Operation::Method> operationMethods_;
1408bf80f4bSopenharmony_ci    BASE_NS::unordered_map<Entity, size_t> mapping_;
1418bf80f4bSopenharmony_ci    bool enableLookup_ { false };
1428bf80f4bSopenharmony_ci    bool enableListeners_ { false };
1438bf80f4bSopenharmony_ci    bool registered_ { false };
1448bf80f4bSopenharmony_ci    bool valid_ { false };
1458bf80f4bSopenharmony_ci};
1468bf80f4bSopenharmony_ciCORE_END_NAMESPACE()
1478bf80f4bSopenharmony_ci
1488bf80f4bSopenharmony_ci#endif // CORE_UTIL_ECS_COMPONENT_QUERY
149