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 #include "PropertyTools/property_data.h"
17
18 #include <algorithm>
19
20 #include <base/containers/allocator.h>
21 #include <core/log.h>
22 #include <core/property/intf_property_api.h>
23
24 using namespace CORE_NS;
25 using BASE_NS::array_view;
26 using BASE_NS::FNV1aHash;
27 using BASE_NS::string;
28 using BASE_NS::string_view;
29 using BASE_NS::vector;
30
31 namespace {
32 PropertyData::PropertyOffset FindProperty(
33 array_view<const Property> properties, const string_view name, const uintptr_t baseOffset);
34
FindPropertyMember(const Property & property,const string_view name,const uintptr_t baseOffset)35 PropertyData::PropertyOffset FindPropertyMember(
36 const Property& property, const string_view name, const uintptr_t baseOffset)
37 {
38 PropertyData::PropertyOffset ret = FindProperty(property.metaData.memberProperties, name, baseOffset);
39 if (ret) {
40 ret.offset += property.offset;
41 }
42 return ret;
43 }
44
FindProperty(array_view<const Property> properties,const string_view name,const uintptr_t baseOffset)45 PropertyData::PropertyOffset FindProperty(
46 array_view<const Property> properties, const string_view name, const uintptr_t baseOffset)
47 {
48 PropertyData::PropertyOffset ret { nullptr, 0U, 0U };
49 // trim down to name without array index or member variable.
50 constexpr string_view delimiters = ".[";
51 const auto delimPos = name.find_first_of(delimiters);
52 auto property = std::find_if(properties.begin(), properties.end(),
53 [baseName = name.substr(0, delimPos)](const Property& p) { return p.name == baseName; });
54 if (property != properties.end()) {
55 // if we have only a name we are done
56 if (delimPos == string_view::npos) {
57 ret.property = &*property;
58 ret.offset += property->offset;
59 ret.index = std::distance(properties.begin(), property);
60 } else if (name[delimPos] == '[') {
61 // there needs to be more than two characters after [ to be a valid array index. the propery must also be an
62 // array.
63 if ((name.size() - delimPos > 2) && property->metaData.containerMethods) { // 2: 2 chs on right of '['
64 const char* start = name.substr(delimPos + 1).data();
65 char* end;
66 const unsigned long index = strtoul(start, &end, 10); // 10: base
67 if (end && *end == ']') {
68 // probably managed to convert an array index
69 size_t size = property->type.isArray
70 ? property->count
71 : property->metaData.containerMethods->size(property->offset + baseOffset);
72 if (index < size) {
73 const auto arrayPos = static_cast<size_t>(end - name.data()) + 1;
74 if (arrayPos < name.size() && name[arrayPos] == '.') {
75 ret = FindPropertyMember(
76 property->metaData.containerMethods->property, name.substr(arrayPos + 1), baseOffset);
77 } else {
78 ret.property = &property->metaData.containerMethods->property;
79 ret.index = index;
80 }
81
82 if (property->type.isArray) {
83 ret.offset += property->offset + index * property->metaData.containerMethods->property.size;
84 } else {
85 ret.offset +=
86 property->metaData.containerMethods->get(property->offset + baseOffset, index) -
87 baseOffset;
88 }
89 }
90 }
91 }
92 } else {
93 ret = FindPropertyMember(*property, name.substr(delimPos + 1), baseOffset);
94 }
95 }
96 return ret;
97 }
98 } // namespace
99
PropertyData()100 PropertyData::PropertyData()
101 {
102 Reset();
103 }
104
WLock(IPropertyHandle & aHandle)105 bool PropertyData::WLock(IPropertyHandle& aHandle) // no-copy direct-access (Locks the datahandle);
106 {
107 CORE_ASSERT(dataHandle_ == nullptr);
108 CORE_ASSERT(dataHandleW_ == nullptr);
109 dataHandleW_ = &aHandle;
110 dataHandle_ = dataHandleW_;
111 owner_ = dataHandleW_->Owner();
112 size_ = dataHandleW_->Size();
113 dataW_ = static_cast<uint8_t*>(dataHandleW_->WLock());
114 data_ = dataW_;
115 return true;
116 }
117
WLock(IPropertyHandle & data,const string_view propertyPath)118 PropertyData::PropertyOffset PropertyData::WLock(IPropertyHandle& data, const string_view propertyPath)
119 {
120 if (WLock(data)) {
121 const uintptr_t baseOffset = reinterpret_cast<uintptr_t>(dataW_);
122 if (auto po = FindProperty(Owner()->MetaData(), propertyPath, baseOffset); po) {
123 return po;
124 }
125 }
126 WUnlock(data);
127 return { 0, 0 };
128 }
129
WUnlock(const IPropertyHandle & aHandle)130 bool PropertyData::WUnlock(const IPropertyHandle& aHandle) // (releases the datahandle lock, and removes ref)
131 {
132 CORE_ASSERT(dataHandleW_);
133 CORE_ASSERT(dataHandleW_ == dataHandle_);
134 CORE_ASSERT(dataHandleW_ == &aHandle);
135 if (dataHandleW_ == &aHandle) {
136 if (dataHandleW_) {
137 dataHandleW_->WUnlock();
138 Reset();
139 }
140 return true;
141 }
142 return false;
143 }
144
RLock(const IPropertyHandle & aHandle)145 bool PropertyData::RLock(const IPropertyHandle& aHandle) // no-copy direct-access (Locks the datahandle);
146 {
147 CORE_ASSERT(dataHandle_ == nullptr);
148 CORE_ASSERT(dataHandleW_ == nullptr);
149 dataHandleW_ = nullptr;
150 dataHandle_ = &aHandle;
151 owner_ = dataHandle_->Owner();
152 size_ = dataHandle_->Size();
153 data_ = dataHandle_->RLock();
154 dataW_ = nullptr;
155 return true;
156 }
157
RLock(const IPropertyHandle & data,const string_view propertyPath)158 PropertyData::PropertyOffset PropertyData::RLock(const IPropertyHandle& data, const string_view propertyPath)
159 {
160 if (RLock(data)) {
161 const uintptr_t baseOffset = reinterpret_cast<uintptr_t>(data_);
162 if (auto po = FindProperty(Owner()->MetaData(), propertyPath, baseOffset); po) {
163 return po;
164 }
165 }
166 RUnlock(data);
167 return { 0, 0 };
168 }
169
RUnlock(const IPropertyHandle & aHandle)170 bool PropertyData::RUnlock(const IPropertyHandle& aHandle) // (releases the datahandle lock, and removes ref)
171 {
172 CORE_ASSERT(dataHandle_);
173 CORE_ASSERT(dataHandleW_ == nullptr);
174 CORE_ASSERT(dataHandle_ == &aHandle);
175 if (dataHandle_ == &aHandle) {
176 if (dataHandle_) {
177 dataHandle_->RUnlock();
178 Reset();
179 }
180 return true;
181 }
182 return false;
183 }
184
FindProperty(const array_view<const Property> properties,const string_view propertyPath,const uintptr_t baseOffset)185 PropertyData::PropertyOffset PropertyData::FindProperty(
186 const array_view<const Property> properties, const string_view propertyPath, const uintptr_t baseOffset)
187 {
188 PropertyData::PropertyOffset offset = ::FindProperty(properties, propertyPath, baseOffset);
189 if (offset) {
190 offset.offset += baseOffset;
191 }
192 return offset;
193 }
194
~PropertyData()195 PropertyData::~PropertyData()
196 {
197 if (dataHandleW_) {
198 WUnlock(*dataHandleW_);
199 }
200 if (dataHandle_) {
201 RUnlock(*dataHandle_);
202 }
203 }
204
Reset()205 void PropertyData::Reset()
206 {
207 size_ = 0;
208 data_ = nullptr;
209 dataW_ = nullptr;
210 owner_ = nullptr;
211 dataHandle_ = nullptr;
212 dataHandleW_ = nullptr;
213 }
214
MetaData() const215 array_view<const Property> PropertyData::MetaData() const
216 {
217 if (owner_) {
218 return owner_->MetaData();
219 }
220 return {};
221 }
222
MetaData(size_t index) const223 const Property* PropertyData::MetaData(size_t index) const
224 {
225 if (owner_) {
226 const auto& meta = owner_->MetaData();
227 if (index < meta.size()) {
228 return &meta[index];
229 }
230 }
231 return nullptr;
232 }
233
Get(size_t index)234 PropertyValue PropertyData::Get(size_t index)
235 {
236 if (owner_) {
237 const auto& props_ = owner_->MetaData();
238 if (index < props_.size() && dataW_) {
239 const auto& meta = props_[index];
240 return PropertyValue(
241 &meta, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dataW_) + meta.offset), meta.count);
242 }
243 }
244 return PropertyValue();
245 }
246
Get(size_t index) const247 PropertyValue PropertyData::Get(size_t index) const
248 {
249 if (owner_) {
250 const auto& props_ = owner_->MetaData();
251 if (index < props_.size()) {
252 const auto& meta = props_[index];
253 return PropertyValue(
254 &meta, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(data_) + meta.offset), meta.count);
255 }
256 }
257 return PropertyValue();
258 }
259
PropertyCount() const260 size_t PropertyData::PropertyCount() const
261 {
262 if (owner_) {
263 const auto& props_ = owner_->MetaData();
264 return props_.size();
265 }
266 return 0;
267 }
268
Get(const string_view name)269 PropertyValue PropertyData::Get(const string_view name)
270 {
271 if (owner_) {
272 const auto& props_ = owner_->MetaData();
273 if (!props_.empty() && dataW_) {
274 const auto nameHash = FNV1aHash(name.data(), name.size());
275 for (const auto& meta : props_) {
276 if (meta.hash == nameHash && meta.name == name) {
277 return PropertyValue(
278 &meta, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dataW_) + meta.offset), meta.count);
279 }
280 }
281 }
282 }
283 return PropertyValue();
284 }
285
Get(const string_view name) const286 PropertyValue PropertyData::Get(const string_view name) const
287 {
288 if (owner_) {
289 const auto& props_ = owner_->MetaData();
290 if (!props_.empty()) {
291 const auto nameHash = FNV1aHash(name.data(), name.size());
292 for (const auto& meta : props_) {
293 if (meta.hash == nameHash && meta.name == name) {
294 return PropertyValue(
295 &meta, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(data_) + meta.offset), meta.count);
296 }
297 }
298 }
299 }
300 return PropertyValue();
301 }
302
operator [](size_t index)303 PropertyValue PropertyData::operator[](size_t index)
304 {
305 return Get(index);
306 }
307
operator [](size_t index) const308 PropertyValue PropertyData::operator[](size_t index) const
309 {
310 return Get(index);
311 }
312
operator [](const string_view & name)313 PropertyValue PropertyData::operator[](const string_view& name)
314 {
315 return Get(name);
316 }
317
operator [](const string_view & name) const318 PropertyValue PropertyData::operator[](const string_view& name) const
319 {
320 return Get(name);
321 }
322
Owner() const323 const IPropertyApi* PropertyData::Owner() const
324 {
325 return owner_;
326 }
327
Size() const328 size_t PropertyData::Size() const
329 {
330 return size_;
331 }
332
RLock() const333 const void* PropertyData::RLock() const
334 {
335 return data_;
336 }
337
WLock()338 void* PropertyData::WLock()
339 {
340 return dataW_;
341 }
342
RUnlock() const343 void PropertyData::RUnlock() const {}
344
WUnlock()345 void PropertyData::WUnlock() {}
346