• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <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 {
ParseIndex(const string_view name,const uintptr_t baseOffset,const Property & property,array_view<const Property> & properties,size_t & pos,PropertyData::PropertyOffset & ret)37 bool ParseIndex(const string_view name, const uintptr_t baseOffset, const Property& property,
38     array_view<const Property>& properties, size_t& pos, PropertyData::PropertyOffset& ret)
39 {
40     // there needs to be at least three characters (e.g. [0]) to be a valid array index. the propery must also be an
41     // array.
42     static constexpr size_t minLength = 3U;
43     if ((pos >= name.size()) || ((name.size() - pos) < minLength) || !property.metaData.containerMethods) {
44         ret = {};
45         return false;
46     }
47     ret.propertyPath = name.substr(0, pos);
48     ++pos;
49 
50     const char* start = name.substr(pos).data();
51     char* end = nullptr;
52     const unsigned long index = strtoul(start, &end, 10); // 10: base
53     // check that conversion stopped at the closing square bracket
54     if (!end || *end != ']') {
55         ret = {};
56         return false;
57     }
58     // move past the closing square bracket and store the path so far
59     pos = static_cast<size_t>(end - name.data()) + 1U;
60     ret.propertyPath = name.substr(0, pos);
61 
62     auto* containerMethods = property.metaData.containerMethods;
63 
64     // calculate offset to the index. for arrays a direct offset, but for containers need to get the addess
65     // inside the container and compensate the base and member offsets.
66     ptrdiff_t offset = PTRDIFF_MAX;
67     if (property.type.isArray && (index < property.count)) {
68         offset = static_cast<ptrdiff_t>(index * containerMethods->property.size);
69     } else if (!property.type.isArray && baseOffset) {
70         if (index < containerMethods->size(property.offset + baseOffset)) {
71             offset = static_cast<ptrdiff_t>(
72                 containerMethods->get(property.offset + baseOffset, index) - baseOffset - ret.offset);
73         }
74     }
75 
76     if (offset != PTRDIFF_MAX) {
77         ret.property = &containerMethods->property;
78         ret.offset = static_cast<uintptr_t>(static_cast<ptrdiff_t>(ret.offset) + offset);
79         ret.index = index;
80 
81         if (pos < name.size() && name[pos] == '.') {
82             ++pos;
83             // continue search from the member properties.
84             properties = containerMethods->property.metaData.memberProperties;
85         }
86     } else {
87         ret = {};
88         return false;
89     }
90     return true;
91 }
92 
FindProperty(array_view<const Property> properties,const string_view name,const uintptr_t baseOffset)93 PropertyData::PropertyOffset FindProperty(
94     array_view<const Property> properties, const string_view name, const uintptr_t baseOffset)
95 {
96     PropertyData::PropertyOffset ret { nullptr, 0U, 0U, {} };
97 
98     // trim down to name without array index or member variable.
99     constexpr const string_view delimiters = ".[";
100 
101     size_t pos = 0U;
102     while (pos < name.size()) {
103         const auto delimPos = name.find_first_of(delimiters, pos);
104         auto baseName = name.substr(pos, delimPos - pos);
105         pos = delimPos;
106         if (baseName.empty()) {
107             ret = {};
108             break;
109         }
110 
111         auto property = std::find_if(
112             properties.cbegin(), properties.cend(), [baseName](const Property& p) { return p.name == baseName; });
113         if (property != properties.cend()) {
114             // remember what property this was
115             ret.property = &*property;
116             ret.offset += property->offset;
117             ret.index = static_cast<size_t>(std::distance(properties.cbegin(), property));
118 
119             // if we have only a name we are done
120             if (pos == string_view::npos) {
121                 ret.propertyPath = name;
122             } else if (name[pos] == '.') {
123                 // there needs to be at least one character to be a valid name.
124                 if ((name.size() - pos) < 2U) {
125                     ret = {};
126                     break;
127                 }
128                 ret.propertyPath = name.substr(0, pos);
129                 ++pos;
130                 // continue search from the member properties.
131                 properties = property->metaData.memberProperties;
132             } else if (name[pos] == '[') {
133                 if (!ParseIndex(name, baseOffset, *property, properties, pos, ret)) {
134                     break;
135                 }
136             }
137         } else if (!properties.empty()) {
138             ret = {};
139             break;
140         } else {
141             break;
142         }
143     }
144     return ret;
145 }
146 } // namespace
147 
PropertyData()148 PropertyData::PropertyData()
149 {
150     Reset();
151 }
152 
WLock(IPropertyHandle & handle)153 bool PropertyData::WLock(IPropertyHandle& handle) // no-copy direct-access (Locks the datahandle);
154 {
155     if (dataHandle_ || dataHandleW_) {
156         return false;
157     }
158     dataHandleW_ = &handle;
159     dataHandle_ = dataHandleW_;
160     owner_ = dataHandleW_->Owner();
161     size_ = dataHandleW_->Size();
162     dataW_ = static_cast<uint8_t*>(dataHandleW_->WLock());
163     data_ = dataW_;
164     return true;
165 }
166 
WLock(IPropertyHandle & handle,const string_view propertyPath)167 PropertyData::PropertyOffset PropertyData::WLock(IPropertyHandle& handle, const string_view propertyPath)
168 {
169     if (WLock(handle)) {
170         const uintptr_t baseOffset = reinterpret_cast<uintptr_t>(dataW_);
171         if (auto po = FindProperty(Owner()->MetaData(), propertyPath, baseOffset); po) {
172             return po;
173         }
174     }
175     WUnlock(handle);
176     return { nullptr, 0U, 0U, {} };
177 }
178 
WUnlock(const IPropertyHandle & handle)179 bool PropertyData::WUnlock(const IPropertyHandle& handle) // (releases the datahandle lock, and removes ref)
180 {
181     BASE_ASSERT(dataHandleW_);
182     BASE_ASSERT(dataHandleW_ == dataHandle_);
183     BASE_ASSERT(dataHandleW_ == &handle);
184     if (dataHandleW_ == &handle) {
185         if (dataHandleW_) {
186             dataHandleW_->WUnlock();
187             Reset();
188         }
189         return true;
190     }
191     return false;
192 }
193 
RLock(const IPropertyHandle & handle)194 bool PropertyData::RLock(const IPropertyHandle& handle) // no-copy direct-access (Locks the datahandle);
195 {
196     if (dataHandle_ || dataHandleW_) {
197         return false;
198     }
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     BASE_ASSERT(dataHandle_);
223     BASE_ASSERT(dataHandleW_ == nullptr);
224     BASE_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 
PropertyCount() const290 size_t PropertyData::PropertyCount() const
291 {
292     if (owner_) {
293         const auto& props = owner_->MetaData();
294         return props.size();
295     }
296     return 0;
297 }
298 
Owner() const299 const IPropertyApi* PropertyData::Owner() const
300 {
301     return owner_;
302 }
303 
Size() const304 size_t PropertyData::Size() const
305 {
306     return size_;
307 }
308 
RLock() const309 const void* PropertyData::RLock() const
310 {
311     return data_;
312 }
313 
WLock()314 void* PropertyData::WLock()
315 {
316     return dataW_;
317 }
318 
RUnlock() const319 void PropertyData::RUnlock() const {}
320 
WUnlock()321 void PropertyData::WUnlock() {}
322