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 #include "PropertyTools/property_data.h"
17
18 #include <PropertyTools/property_value.h>
19 #include <algorithm>
20 #include <climits>
21 #include <cstdlib>
22
23 #include <base/containers/array_view.h>
24 #include <base/containers/iterator.h>
25 #include <base/containers/string.h>
26 #include <base/containers/string_view.h>
27 #include <base/util/compile_time_hashes.h>
28 #include <core/log.h>
29 #include <core/property/intf_property_api.h>
30 #include <core/property/intf_property_handle.h>
31 #include <core/property/property.h>
32
33 using namespace CORE_NS;
34 using BASE_NS::array_view;
35 using BASE_NS::FNV1aHash;
36 using BASE_NS::string;
37 using BASE_NS::string_view;
38
39 namespace {
ParseIndex(const string_view name,const uintptr_t baseOffset,const Property & property,array_view<const Property> & properties,size_t & pos,PropertyData::PropertyOffset & ret)40 bool ParseIndex(const string_view name, const uintptr_t baseOffset, const Property& property,
41 array_view<const Property>& properties, size_t& pos, PropertyData::PropertyOffset& ret)
42 {
43 // there needs to be at least three characters to be a valid array index. the propery must also be an
44 // array.
45 if (((name.size() - pos) < 3U) || !property.metaData.containerMethods) { // 3: min length e.g. [0]
46 ret = {};
47 return false;
48 }
49 ret.propertyPath = name.substr(0, pos);
50 ++pos;
51
52 const char* start = name.substr(pos).data();
53 char* end = nullptr;
54 const unsigned long index = strtoul(start, &end, 10); // 10: base
55 // check that conversion stopped at the closing square bracket
56 if (!end || *end != ']') {
57 ret = {};
58 return false;
59 }
60 // move past the closing square bracket and store the path so far
61 pos = static_cast<size_t>(end - name.data()) + 1U;
62 ret.propertyPath = name.substr(0, pos);
63
64 auto* containerMethods = property.metaData.containerMethods;
65
66 // calculate offset to the index. for arrays a direct offset, but for containers need to get the addess
67 // inside the container and compensate the base and member offsets.
68 ptrdiff_t offset = PTRDIFF_MAX;
69 if (property.type.isArray && (index < property.count)) {
70 offset = static_cast<ptrdiff_t>(index * containerMethods->property.size);
71 } else if (!property.type.isArray && baseOffset) {
72 if (index < containerMethods->size(property.offset + baseOffset)) {
73 offset = static_cast<ptrdiff_t>(
74 containerMethods->get(property.offset + baseOffset, index) - baseOffset - ret.offset);
75 }
76 }
77
78 if (offset != PTRDIFF_MAX) {
79 ret.property = &containerMethods->property;
80 ret.offset = static_cast<uintptr_t>(static_cast<ptrdiff_t>(ret.offset) + offset);
81 ret.index = index;
82
83 if (pos < name.size() && name[pos] == '.') {
84 ++pos;
85 // continue search from the member properties.
86 properties = containerMethods->property.metaData.memberProperties;
87 }
88 } else {
89 ret = {};
90 return false;
91 }
92 return true;
93 }
94
FindProperty(array_view<const Property> properties,const string_view name,const uintptr_t baseOffset)95 PropertyData::PropertyOffset FindProperty(
96 array_view<const Property> properties, const string_view name, const uintptr_t baseOffset)
97 {
98 PropertyData::PropertyOffset ret { nullptr, 0U, 0U, {} };
99
100 // trim down to name without array index or member variable.
101 constexpr const string_view delimiters = ".[";
102
103 size_t pos = 0U;
104 while (pos < name.size()) {
105 const auto delimPos = name.find_first_of(delimiters, pos);
106 auto baseName = name.substr(pos, delimPos - pos);
107 pos = delimPos;
108 if (baseName.empty()) {
109 ret = {};
110 break;
111 }
112
113 auto property = std::find_if(
114 properties.cbegin(), properties.cend(), [baseName](const Property& p) { return p.name == baseName; });
115 if (property != properties.cend()) {
116 // remember what property this was
117 ret.property = &*property;
118 ret.offset += property->offset;
119 ret.index = static_cast<size_t>(std::distance(properties.cbegin(), property));
120
121 // if we have only a name we are done
122 if (pos == string_view::npos) {
123 ret.propertyPath = name;
124 } else if (name[pos] == '.') {
125 // there needs to be at least one character to be a valid name.
126 if ((name.size() - pos) < 2U) {
127 ret = {};
128 break;
129 }
130 ret.propertyPath = name.substr(0, pos);
131 ++pos;
132 // continue search from the member properties.
133 properties = property->metaData.memberProperties;
134 } else if (name[pos] == '[') {
135 if (!ParseIndex(name, baseOffset, *property, properties, pos, ret)) {
136 break;
137 }
138 }
139 } else if (!properties.empty()) {
140 ret = {};
141 break;
142 } else {
143 break;
144 }
145 }
146 return ret;
147 }
148 } // namespace
149
PropertyData()150 PropertyData::PropertyData()
151 {
152 Reset();
153 }
154
WLock(IPropertyHandle & handle)155 bool PropertyData::WLock(IPropertyHandle& handle) // no-copy direct-access (Locks the datahandle);
156 {
157 CORE_ASSERT(dataHandle_ == nullptr);
158 CORE_ASSERT(dataHandleW_ == nullptr);
159 dataHandleW_ = &handle;
160 dataHandle_ = dataHandleW_;
161 owner_ = dataHandleW_->Owner();
162 size_ = dataHandleW_->Size();
163 dataW_ = static_cast<uint8_t*>(dataHandleW_->WLock());
164 data_ = dataW_;
165 return true;
166 }
167
WLock(IPropertyHandle & handle,const string_view propertyPath)168 PropertyData::PropertyOffset PropertyData::WLock(IPropertyHandle& handle, const string_view propertyPath)
169 {
170 if (WLock(handle)) {
171 const uintptr_t baseOffset = reinterpret_cast<uintptr_t>(dataW_);
172 if (auto po = FindProperty(Owner()->MetaData(), propertyPath, baseOffset); po) {
173 return po;
174 }
175 }
176 WUnlock(handle);
177 return { nullptr, 0U, 0U, {} };
178 }
179
WUnlock(const IPropertyHandle & handle)180 bool PropertyData::WUnlock(const IPropertyHandle& handle) // (releases the datahandle lock, and removes ref)
181 {
182 CORE_ASSERT(dataHandleW_);
183 CORE_ASSERT(dataHandleW_ == dataHandle_);
184 CORE_ASSERT(dataHandleW_ == &handle);
185 if (dataHandleW_ == &handle) {
186 if (dataHandleW_) {
187 dataHandleW_->WUnlock();
188 Reset();
189 }
190 return true;
191 }
192 return false;
193 }
194
RLock(const IPropertyHandle & handle)195 bool PropertyData::RLock(const IPropertyHandle& handle) // no-copy direct-access (Locks the datahandle);
196 {
197 CORE_ASSERT(dataHandle_ == nullptr);
198 CORE_ASSERT(dataHandleW_ == nullptr);
199 dataHandleW_ = nullptr;
200 dataHandle_ = &handle;
201 owner_ = dataHandle_->Owner();
202 size_ = dataHandle_->Size();
203 data_ = dataHandle_->RLock();
204 dataW_ = nullptr;
205 return true;
206 }
207
RLock(const IPropertyHandle & handle,const string_view propertyPath)208 PropertyData::PropertyOffset PropertyData::RLock(const IPropertyHandle& handle, const string_view propertyPath)
209 {
210 if (RLock(handle)) {
211 const uintptr_t baseOffset = reinterpret_cast<uintptr_t>(data_);
212 if (auto po = FindProperty(Owner()->MetaData(), propertyPath, baseOffset); po) {
213 return po;
214 }
215 }
216 RUnlock(handle);
217 return { nullptr, 0U, 0U, {} };
218 }
219
RUnlock(const IPropertyHandle & handle)220 bool PropertyData::RUnlock(const IPropertyHandle& handle) // (releases the datahandle lock, and removes ref)
221 {
222 CORE_ASSERT(dataHandle_);
223 CORE_ASSERT(dataHandleW_ == nullptr);
224 CORE_ASSERT(dataHandle_ == &handle);
225 if (dataHandle_ == &handle) {
226 if (dataHandle_) {
227 dataHandle_->RUnlock();
228 Reset();
229 }
230 return true;
231 }
232 return false;
233 }
234
FindProperty(const array_view<const Property> properties,const string_view propertyPath,const uintptr_t baseOffset)235 PropertyData::PropertyOffset PropertyData::FindProperty(
236 const array_view<const Property> properties, const string_view propertyPath, const uintptr_t baseOffset)
237 {
238 PropertyData::PropertyOffset offset = ::FindProperty(properties, propertyPath, baseOffset);
239 if (offset) {
240 offset.offset += baseOffset;
241 }
242 return offset;
243 }
244
FindProperty(const array_view<const Property> properties,const string_view propertyPath)245 PropertyData::PropertyOffset PropertyData::FindProperty(
246 const array_view<const Property> properties, const string_view propertyPath)
247 {
248 return ::FindProperty(properties, propertyPath, 0U);
249 }
250
~PropertyData()251 PropertyData::~PropertyData()
252 {
253 if (dataHandleW_) {
254 WUnlock(*dataHandleW_);
255 }
256 if (dataHandle_) {
257 RUnlock(*dataHandle_);
258 }
259 }
260
Reset()261 void PropertyData::Reset()
262 {
263 size_ = 0;
264 data_ = nullptr;
265 dataW_ = nullptr;
266 owner_ = nullptr;
267 dataHandle_ = nullptr;
268 dataHandleW_ = nullptr;
269 }
270
MetaData() const271 array_view<const Property> PropertyData::MetaData() const
272 {
273 if (owner_) {
274 return owner_->MetaData();
275 }
276 return {};
277 }
278
MetaData(size_t index) const279 const Property* PropertyData::MetaData(size_t index) const
280 {
281 if (owner_) {
282 const auto& meta = owner_->MetaData();
283 if (index < meta.size()) {
284 return &meta[index];
285 }
286 }
287 return nullptr;
288 }
289
Get(size_t index)290 PropertyValue PropertyData::Get(size_t index)
291 {
292 if (owner_ && dataW_) {
293 const auto& props = owner_->MetaData();
294 if (index < props.size()) {
295 const auto& meta = props[index];
296 return PropertyValue(&meta, static_cast<void*>(dataW_ + meta.offset), meta.count);
297 }
298 }
299 return PropertyValue();
300 }
301
Get(size_t index) const302 PropertyValue PropertyData::Get(size_t index) const
303 {
304 if (owner_ && data_) {
305 const auto& props = owner_->MetaData();
306 if (index < props.size()) {
307 const auto& meta = props[index];
308 return PropertyValue(&meta,
309 const_cast<void*>(static_cast<const void*>(static_cast<const uint8_t*>(data_) + meta.offset)),
310 meta.count);
311 }
312 }
313 return PropertyValue();
314 }
315
PropertyCount() const316 size_t PropertyData::PropertyCount() const
317 {
318 if (owner_) {
319 const auto& props = owner_->MetaData();
320 return props.size();
321 }
322 return 0;
323 }
324
Get(const string_view name)325 PropertyValue PropertyData::Get(const string_view name)
326 {
327 if (owner_ && dataW_) {
328 const auto& props = owner_->MetaData();
329 if (!props.empty()) {
330 const auto nameHash = FNV1aHash(name.data(), name.size());
331 for (const auto& meta : props) {
332 if (meta.hash == nameHash && meta.name == name) {
333 return PropertyValue(&meta, static_cast<void*>(dataW_ + meta.offset), meta.count);
334 }
335 }
336 }
337 }
338 return PropertyValue();
339 }
340
Get(const string_view name) const341 PropertyValue PropertyData::Get(const string_view name) const
342 {
343 if (owner_ && data_) {
344 const auto& props = owner_->MetaData();
345 if (!props.empty()) {
346 const auto nameHash = FNV1aHash(name.data(), name.size());
347 for (const auto& meta : props) {
348 if (meta.hash == nameHash && meta.name == name) {
349 return PropertyValue(&meta,
350 const_cast<void*>(static_cast<const void*>(static_cast<const uint8_t*>(data_) + meta.offset)),
351 meta.count);
352 }
353 }
354 }
355 }
356 return PropertyValue();
357 }
358
operator [](size_t index)359 PropertyValue PropertyData::operator[](size_t index)
360 {
361 return Get(index);
362 }
363
operator [](size_t index) const364 PropertyValue PropertyData::operator[](size_t index) const
365 {
366 return Get(index);
367 }
368
369 PropertyValue PropertyData::operator[](const string_view& name)
370 {
371 return Get(name);
372 }
373
operator [](const string_view & name) const374 PropertyValue PropertyData::operator[](const string_view& name) const
375 {
376 return Get(name);
377 }
378
379 const IPropertyApi* PropertyData::Owner() const
__anonf853e2af0502(const string_view& name) 380 {
381 return owner_;
382 }
383
384 size_t PropertyData::Size() const
__anonf853e2af0602(const string_view& name) 385 {
386 return size_;
387 }
388
389 const void* PropertyData::RLock() const
__anonf853e2af0702(const string_view& name) 390 {
391 return data_;
392 }
393
394 void* PropertyData::WLock()
395 {
396 return dataW_;
397 }
398
RUnlock() const399 void PropertyData::RUnlock() const {}
400
WUnlock()401 void PropertyData::WUnlock() {}
402