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