1/*
2 * Copyright (C) 2023-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#include <PropertyTools/property_api_impl.h>
17#include <new>
18
19#include <base/containers/array_view.h>
20#include <base/containers/iterator.h>
21#include <base/namespace.h>
22#include <core/log.h>
23#include <core/namespace.h>
24#include <core/property/intf_property_api.h>
25#include <core/property/intf_property_handle.h>
26#include <core/property/property.h>
27
28CORE_BEGIN_NAMESPACE()
29template<typename BlockType>
30PropertyApiImpl<BlockType>::PropertyApiImpl() = default;
31
32template<typename BlockType>
33PropertyApiImpl<BlockType>::PropertyApiImpl(BlockType* data, BASE_NS::array_view<const Property> aProps)
34    : data_(data), componentMetadata_(aProps)
35{
36    // Create a typeid by hashing the metadata information.
37    typeHash_ = 0;
38    for (auto& t : aProps) {
39        BASE_NS::HashCombine(typeHash_, t.offset);
40        BASE_NS::HashCombine(typeHash_, t.count);
41        BASE_NS::HashCombine(typeHash_, t.type.compareHash);
42        BASE_NS::HashCombine(typeHash_, t.type.typeHash);
43        BASE_NS::HashCombine(typeHash_, t.hash);
44        BASE_NS::HashCombine(typeHash_, t.size);
45    }
46}
47
48template<typename BlockType>
49size_t PropertyApiImpl<BlockType>::PropertyCount() const
50{
51    if (owner_) {
52        return owner_->PropertyCount();
53    }
54    return componentMetadata_.size();
55}
56
57// Metadata for property
58template<typename BlockType>
59const Property* PropertyApiImpl<BlockType>::MetaData(size_t aIndex) const
60{
61    if (owner_) {
62        return owner_->MetaData(aIndex);
63    }
64    return &componentMetadata_[aIndex];
65}
66
67// Metadata for properties
68template<typename BlockType>
69BASE_NS::array_view<const Property> PropertyApiImpl<BlockType>::MetaData() const
70{
71    if (owner_) {
72        return owner_->MetaData();
73    }
74    return componentMetadata_;
75}
76
77template<typename BlockType>
78IPropertyHandle* PropertyApiImpl<BlockType>::Create() const
79{
80    auto ret = new PropertyApiImpl<BlockType>();
81    ret->owner_ = Owner();
82    ret->typeHash_ = Type();
83    ret->data_ = new BlockType();
84    return ret;
85}
86
87template<typename BlockType>
88IPropertyHandle* PropertyApiImpl<BlockType>::Clone(const IPropertyHandle* src) const
89{
90    if (src->Owner() == this) {
91        auto* h = static_cast<const PropertyApiImpl<BlockType>*>(src);
92        auto* ret = new PropertyApiImpl<BlockType>();
93        ret->owner_ = Owner();
94        ret->typeHash_ = Type();
95        ret->data_ = new BlockType();
96        *ret->data_ = *h->data_;
97        return ret;
98    }
99    return nullptr;
100}
101
102template<typename BlockType>
103void PropertyApiImpl<BlockType>::Release(IPropertyHandle* dst) const
104{
105    if (dst) {
106        if (dst->Owner() == Owner()) {
107            // we can only destroy things we "own" (know)
108            auto* handle = static_cast<PropertyApiImpl<BlockType>*>(dst);
109            if (handle->owner_) {
110                // and only the ones that own the data..
111                delete handle;
112            }
113        }
114    }
115}
116
117template<typename BlockType>
118uint32_t PropertyApiImpl<BlockType>::GetGeneration() const
119{
120    return generationCount_;
121}
122
123template<typename BlockType>
124IPropertyHandle* PropertyApiImpl<BlockType>::GetData()
125{
126    return this;
127}
128
129template<typename BlockType>
130const IPropertyHandle* PropertyApiImpl<BlockType>::GetData() const
131{
132    return this;
133}
134
135template<typename BlockType>
136const IPropertyApi* PropertyApiImpl<BlockType>::Owner() const
137{
138    if (owner_) {
139        return owner_;
140    }
141    return this;
142}
143
144template<typename BlockType>
145size_t PropertyApiImpl<BlockType>::Size() const
146{
147    return sizeof(BlockType);
148}
149
150template<typename BlockType>
151const void* PropertyApiImpl<BlockType>::RLock() const
152{
153    CORE_ASSERT(!wLocked_);
154    rLocked_++;
155    return data_;
156}
157
158template<typename BlockType>
159void PropertyApiImpl<BlockType>::RUnlock() const
160{
161    CORE_ASSERT(rLocked_ > 0);
162    rLocked_--;
163}
164
165template<typename BlockType>
166void* PropertyApiImpl<BlockType>::WLock()
167{
168    CORE_ASSERT(rLocked_ <= 1 && !wLocked_);
169    wLocked_ = true;
170    return data_;
171}
172
173template<typename BlockType>
174void PropertyApiImpl<BlockType>::WUnlock()
175{
176    CORE_ASSERT(wLocked_);
177    wLocked_ = false;
178    generationCount_++;
179}
180
181template<typename BlockType>
182uint64_t PropertyApiImpl<BlockType>::Type() const
183{
184    return typeHash_;
185}
186
187template<>
188inline size_t PropertyApiImpl<void>::Size() const
189{
190    return 0;
191}
192
193template<>
194inline IPropertyHandle* PropertyApiImpl<void>::Create() const
195{
196    auto ret = new PropertyApiImpl<void>();
197    ret->owner_ = owner_;
198    ret->data_ = nullptr;
199    return ret;
200}
201
202template<>
203inline IPropertyHandle* PropertyApiImpl<void>::Clone(const IPropertyHandle* src) const
204{
205    if (src->Owner() == this) {
206        auto* ret = new PropertyApiImpl<void>();
207        ret->owner_ = owner_;
208        return ret;
209    }
210    return nullptr;
211}
212
213template<>
214inline void PropertyApiImpl<void>::Release(IPropertyHandle* dst) const
215{
216    if (dst) {
217        if (dst->Owner() == this) {
218            // we can only destroy things we "own" (know)
219            auto* handle = static_cast<PropertyApiImpl<void>*>(dst);
220            delete handle;
221        }
222    }
223}
224
225CORE_END_NAMESPACE()
226