1 /*
2  * Copyright (c) 2024 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 API_CORE_ECS_ENTITY_REFERENCE_H
17 #define API_CORE_ECS_ENTITY_REFERENCE_H
18 
19 #include <cstdint>
20 
21 #include <base/containers/refcnt_ptr.h>
22 #include <base/containers/type_traits.h>
23 #include <base/namespace.h>
24 #include <core/ecs/entity.h>
25 #include <core/namespace.h>
26 
27 CORE_BEGIN_NAMESPACE()
28 class EntityReference;
29 
30 /** Entity reference counter counter. */
31 class IEntityReferenceCounter {
32 public:
33     using Ptr = BASE_NS::refcnt_ptr<IEntityReferenceCounter>;
34     virtual int32_t GetRefCount() const noexcept = 0;
35 
36 protected:
37     virtual void Ref() noexcept = 0;
38     virtual void Unref() noexcept = 0;
39 
40     friend Ptr;
41     friend EntityReference;
42 
43     IEntityReferenceCounter() = default;
44     virtual ~IEntityReferenceCounter() = default;
45     IEntityReferenceCounter(const IEntityReferenceCounter&) = delete;
46     IEntityReferenceCounter& operator=(const IEntityReferenceCounter&) = delete;
47     IEntityReferenceCounter(IEntityReferenceCounter&&) = delete;
48     IEntityReferenceCounter& operator=(IEntityReferenceCounter&&) = delete;
49 };
50 
51 /**
52  * Helper for updating reference counts of shared entities.
53  */
54 class EntityReference {
55 public:
56     /** Destructor releases the reference from the owning entity manager.
57      */
58     ~EntityReference() = default;
59 
60     /** Construct an empty reference. */
61     EntityReference() = default;
62 
63     /** Construct a reference for tracking the given entity.
64      * @param entity referenced entity
65      * @param counter Reference counter instance.
66      */
EntityReference(Entity entity,const IEntityReferenceCounter::Ptr & counter)67     EntityReference(Entity entity, const IEntityReferenceCounter::Ptr& counter) noexcept
68         : entity_(entity), counter_(counter)
69     {}
70 
71     /** Copy a reference. Reference count will be increased. */
EntityReference(const EntityReference & other)72     EntityReference(const EntityReference& other) noexcept : entity_(other.entity_), counter_(other.counter_) {}
73 
74     /** Move a reference. Moved from reference will be empty and reusable. */
EntityReference(EntityReference && other)75     EntityReference(EntityReference&& other) noexcept
76         : entity_(BASE_NS::exchange(other.entity_, Entity {})), counter_(BASE_NS::exchange(other.counter_, nullptr))
77     {}
78 
79     /** Copy a reference. Previous reference will be released and the one aquired. */
80     EntityReference& operator=(const EntityReference& other) noexcept
81     {
82         if (&other != this) {
83             entity_ = other.entity_;
84             counter_ = other.counter_;
85         }
86         return *this;
87     }
88 
89     /** Move a reference. Previous reference will be released and and the moved from reference will be empty and
90      * reusable. */
91     EntityReference& operator=(EntityReference&& other) noexcept
92     {
93         if (&other != this) {
94             entity_ = BASE_NS::exchange(other.entity_, Entity {});
95             counter_ = BASE_NS::exchange(other.counter_, nullptr);
96         }
97         return *this;
98     }
99 
100     /** Get the referenced entity. */
Entity()101     operator Entity() const noexcept
102     {
103         return entity_;
104     }
105 
106     /** Check validity of the reference.
107      * @return true if the reference is valid.
108      */
109     explicit operator bool() const noexcept
110     {
111         return EntityUtil::IsValid(entity_) && (counter_);
112     }
113 
114     /** Get ref count. Return 0, if invalid.
115      * @return Get reference count of render handle reference.
116      */
GetRefCount()117     int32_t GetRefCount() const noexcept
118     {
119         if (counter_) {
120             return counter_->GetRefCount();
121         }
122         return 0;
123     }
124 
125 private:
126     Entity entity_;
127     IEntityReferenceCounter::Ptr counter_;
128 };
129 CORE_END_NAMESPACE()
130 
131 #endif // API_CORE_ECS_ENTITY_REFERENCE_H
132