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 #ifndef META_INTERFACE_DETAIL_ARRAY_PROPERTY_H
17 #define META_INTERFACE_DETAIL_ARRAY_PROPERTY_H
18
19 #include <meta/interface/detail/property.h>
20
META_BEGIN_NAMESPACE()21 META_BEGIN_NAMESPACE()
22
23 template<typename Base>
24 class ConstTypelessArrayPropertyInterfaceImpl : public Base {
25 public:
26 using IndexType = IArrayAny::IndexType;
27
28 template<typename Prop>
29 explicit ConstTypelessArrayPropertyInterfaceImpl(Prop* p) : Base(p)
30 {}
31
32 /// Get array size
33 IndexType GetSize() const
34 {
35 if (auto arr = interface_cast<IArrayAny>(&this->GetValueAny())) {
36 return arr->GetSize();
37 }
38 return {};
39 }
40 /**
41 * @brief Get value at given location to an any
42 * @param index Location in the array to get
43 * @param any Any where the value is copied to.
44 * @notice The any needs to be compatible with the array item type.
45 * @return Result of the operation
46 */
47 AnyReturnValue GetAnyAt(IndexType index, IAny& any) const
48 {
49 if (auto arr = interface_cast<IArrayAny>(&this->GetValueAny())) {
50 return arr->GetAnyAt(index, any);
51 }
52 return AnyReturn::INCOMPATIBLE_TYPE;
53 }
54 /**
55 * @brief Construct any and get value for given location
56 * @param index Location in the array to get
57 * @return Pointer to any with the value at location 'index' or nullptr in case of failure.
58 */
59 IAny::Ptr GetAnyAt(IndexType index) const
60 {
61 IAny::Ptr res = ConstructItemAny();
62 if (res) {
63 if (!GetAnyAt(index, *res)) {
64 res.reset();
65 }
66 }
67 return res;
68 }
69 /// Construct any with the array item type
70 IAny::Ptr ConstructItemAny() const
71 {
72 IAny::Ptr res;
73 if (auto i = interface_cast<IPropertyInternalAny>(this->p_)) {
74 if (auto internal = i->GetInternalAny()) {
75 res = internal->Clone({ CloneValueType::DEFAULT_VALUE, TypeIdRole::ITEM });
76 }
77 }
78 return res;
79 }
80 };
81
82 using ConstTypelessArrayPropertyInterface = ConstTypelessArrayPropertyInterfaceImpl<ConstTypelessPropertyInterface>;
83
84 class TypelessArrayPropertyInterface : public ConstTypelessArrayPropertyInterfaceImpl<TypelessPropertyInterface> {
85 public:
86 using PropertyType = IProperty*;
87 using IndexType = IArrayAny::IndexType;
88
TypelessArrayPropertyInterface(PropertyType p)89 TypelessArrayPropertyInterface(PropertyType p)
90 : ConstTypelessArrayPropertyInterfaceImpl<TypelessPropertyInterface>(p)
91 {}
92
93 /**
94 * @brief Set value for given location from an any
95 * @param index Location in the array to set
96 * @param any Any to copy value from.
97 * @return Result of the operation
98 */
SetAnyAt(IndexType index,const IAny & any)99 AnyReturnValue SetAnyAt(IndexType index, const IAny& any)
100 {
101 if (auto c = this->GetValueAny().Clone(true)) {
102 if (auto arr = interface_cast<IArrayAny>(c)) {
103 auto res = arr->SetAnyAt(index, any);
104 return res ? this->SetValueAny(*arr) : res;
105 }
106 }
107 return AnyReturn::INCOMPATIBLE_TYPE;
108 }
109 /**
110 * @brief Add value to end of array from an any
111 * @param any Any to copy value from.
112 * @return Result of the operation
113 */
AddAny(const IAny & any)114 AnyReturnValue AddAny(const IAny& any)
115 {
116 return InsertAnyAt(-1, any);
117 }
118 /**
119 * @brief Insert value to given location from an any
120 * @param index Location in the array to insert.
121 * @param any Any to copy value from.
122 * @return Result of the operation
123 */
InsertAnyAt(IndexType index,const IAny & v)124 AnyReturnValue InsertAnyAt(IndexType index, const IAny& v)
125 {
126 if (auto c = this->GetValueAny().Clone(true)) {
127 if (auto arr = interface_cast<IArrayAny>(c)) {
128 auto res = arr->InsertAnyAt(index, v);
129 return res ? this->SetValueAny(*arr) : res;
130 }
131 }
132 return AnyReturn::INCOMPATIBLE_TYPE;
133 }
134 /**
135 * @brief Remove value at give location
136 * @param index Location in the array to remove from.
137 * @return true on success
138 */
RemoveAt(IndexType index)139 bool RemoveAt(IndexType index)
140 {
141 if (auto c = this->GetValueAny().Clone(true)) {
142 if (auto arr = interface_cast<IArrayAny>(c)) {
143 return arr->RemoveAt(index) && this->SetValueAny(*arr);
144 }
145 }
146 return false;
147 }
148 };
149
150 template<typename Type>
151 using ArrayPropertyBaseType = BASE_NS::conditional_t<BASE_NS::is_const_v<Type>, ConstTypelessArrayPropertyInterface,
152 TypelessArrayPropertyInterface>;
153
154 template<typename Type>
155 class ArrayPropertyInterface : public ArrayPropertyBaseType<Type> {
156 using Super = ArrayPropertyBaseType<Type>;
157
158 public:
159 using ValueType = BASE_NS::remove_const_t<Type>;
160 using PropertyType = typename PropertyBaseType<Type>::PropertyType;
161 using IndexType = IArrayAny::IndexType;
162
ArrayPropertyInterface(PropertyType p)163 explicit ArrayPropertyInterface(PropertyType p) : Super(p) {}
164
165 /**
166 * @brief Get value at given location
167 * @param index Location from which to get value
168 * @return Value at given location or value-initialized value in case failure
169 */
GetValueAt(IndexType index)170 ValueType GetValueAt(IndexType index) const
171 {
172 Any<ValueType> any;
173 if (auto arr = interface_cast<IArrayAny>(&this->GetValueAny())) {
174 arr->GetAnyAt(index, any);
175 }
176 return any.InternalGetValue();
177 }
178 /**
179 * @brief Set value at given location
180 * @param index Location to set value
181 * @param v Value to set
182 * @return True on success
183 */
SetValueAt(IndexType index,const Type & v)184 bool SetValueAt(IndexType index, const Type& v)
185 {
186 return this->SetAnyAt(index, Any<ValueType> { v });
187 }
188 /**
189 * @brief Ad value at the end of array
190 * @param v Value to add
191 * @return True on success
192 */
AddValue(const Type & v)193 bool AddValue(const Type& v)
194 {
195 return InsertValueAt(-1, v);
196 }
197 /**
198 * @brief Insert value at given location
199 * @param index Location to insert value
200 * @param v Value to insert
201 * @return True on success
202 */
InsertValueAt(IndexType index,const Type & v)203 bool InsertValueAt(IndexType index, const Type& v)
204 {
205 return this->InsertAnyAt(index, Any<ValueType> { v });
206 }
207 /// Get default value of the array property
GetDefaultValue()208 BASE_NS::vector<ValueType> GetDefaultValue() const
209 {
210 BASE_NS::vector<ValueType> v;
211 this->GetDefaultValueAny().GetValue(v);
212 return v;
213 }
214 /// Set default value of the array property
SetDefaultValue(BASE_NS::array_view<const ValueType> value)215 AnyReturnValue SetDefaultValue(BASE_NS::array_view<const ValueType> value)
216 {
217 return this->SetDefaultValueAny(ArrayAny<ValueType>(value));
218 }
219
220 /// Set default value of the array property
221 template<typename T, typename = BASE_NS::enable_if_t<BASE_NS::is_same_v<T, ValueType>>>
SetDefaultValue(BASE_NS::vector<T> value)222 AnyReturnValue SetDefaultValue(BASE_NS::vector<T> value)
223 {
224 return this->SetDefaultValueAny(ArrayAny<ValueType>(BASE_NS::move(value)));
225 }
226
227 /// Set default value of the array property and optionally reset current value to it
SetDefaultValue(BASE_NS::vector<ValueType> value,bool resetToDefault)228 AnyReturnValue SetDefaultValue(BASE_NS::vector<ValueType> value, bool resetToDefault)
229 {
230 auto ret = this->SetDefaultValueAny(ArrayAny<ValueType>(BASE_NS::move(value)));
231 if (resetToDefault && ret) {
232 this->ResetValue();
233 }
234 return ret;
235 }
236 /// Get value of the array property
GetValue()237 BASE_NS::vector<ValueType> GetValue() const
238 {
239 BASE_NS::vector<ValueType> v {};
240 this->GetValueAny().GetValue(v);
241 return v;
242 }
243 /// Set value of the array property
SetValue(BASE_NS::array_view<const ValueType> value)244 AnyReturnValue SetValue(BASE_NS::array_view<const ValueType> value)
245 {
246 return this->SetValueAny(ArrayAny<ValueType>(value));
247 }
248 /// Set value of the array property
249 template<typename T, typename = BASE_NS::enable_if_t<BASE_NS::is_same_v<T, ValueType>>>
SetValue(BASE_NS::vector<T> value)250 AnyReturnValue SetValue(BASE_NS::vector<T> value)
251 {
252 return this->SetValueAny(ArrayAny<ValueType>(BASE_NS::move(value)));
253 }
254 /// Find index of first matching value in the array property or -1 if no such value
FindFirstValueOf(const Type & v)255 IndexType FindFirstValueOf(const Type& v) const
256 {
257 for (IndexType i = 0; i != this->GetSize(); ++i) {
258 if (GetValueAt(i) == v) {
259 return i;
260 }
261 }
262 return -1;
263 }
264 };
265
266 template<typename Type>
267 class TypedArrayPropertyLock final : public ArrayPropertyInterface<Type> {
268 using PropertyType = typename ArrayPropertyInterface<Type>::PropertyType;
269 using IT = ArrayPropertyInterface<Type>;
270 using InterfaceType = BASE_NS::conditional_t<BASE_NS::is_const_v<Type>, const IT*, IT*>;
271
META_NO_COPY_MOVE(TypedArrayPropertyLock)272 META_NO_COPY_MOVE(TypedArrayPropertyLock)
273
274 bool CanConstructFrom(PropertyType p) const
275 {
276 return p && p->IsCompatible(META_NS::GetArrayTypeId<BASE_NS::remove_const_t<Type>>());
277 }
278
279 public:
TypedArrayPropertyLock(NoCheckT,PropertyType p)280 TypedArrayPropertyLock(NoCheckT, PropertyType p) : ArrayPropertyInterface<Type>(p)
281 {
282 if (auto i = interface_cast<ILockable>(this->GetProperty())) {
283 i->Lock();
284 }
285 }
TypedArrayPropertyLock(PropertyType p)286 explicit TypedArrayPropertyLock(PropertyType p) : TypedArrayPropertyLock(NOCHECK, CanConstructFrom(p) ? p : nullptr)
287 {}
TypedArrayPropertyLock(const IProperty::Ptr & p)288 explicit TypedArrayPropertyLock(const IProperty::Ptr& p) : TypedArrayPropertyLock(p.get()) {}
TypedArrayPropertyLock(const IProperty::ConstPtr & p)289 explicit TypedArrayPropertyLock(const IProperty::ConstPtr& p) : TypedArrayPropertyLock(p.get()) {}
~TypedArrayPropertyLock()290 ~TypedArrayPropertyLock()
291 {
292 if (auto i = interface_cast<ILockable>(this->GetProperty())) {
293 i->Unlock();
294 }
295 }
296
297 InterfaceType operator->() const
298 {
299 return const_cast<TypedArrayPropertyLock*>(this);
300 }
301
IsValid()302 bool IsValid() const
303 {
304 return this->GetProperty() != nullptr;
305 }
306
307 explicit operator bool() const
308 {
309 return IsValid();
310 }
311 };
312
313 template<typename Property>
314 class ArrayPropertyLock final : public ArrayPropertyBaseType<Property> {
315 using InterfaceType = ArrayPropertyBaseType<Property>*;
316
META_NO_COPY_MOVE(ArrayPropertyLock)317 META_NO_COPY_MOVE(ArrayPropertyLock)
318
319 bool CanConstructFrom(Property* p) const
320 {
321 auto i = interface_cast<IPropertyInternalAny>(p);
322 return i && IsArray(i->GetInternalAny());
323 }
324
325 public:
ArrayPropertyLock(NoCheckT,Property * p)326 ArrayPropertyLock(NoCheckT, Property* p) : ArrayPropertyBaseType<Property>(p)
327 {
328 if (auto i = interface_cast<ILockable>(this->GetProperty())) {
329 i->Lock();
330 }
331 }
332
ArrayPropertyLock(Property * p)333 explicit ArrayPropertyLock(Property* p) : ArrayPropertyLock(NOCHECK, CanConstructFrom(p) ? p : nullptr) {}
334
ArrayPropertyLock(BASE_NS::shared_ptr<Property> p)335 explicit ArrayPropertyLock(BASE_NS::shared_ptr<Property> p) : ArrayPropertyLock(p.get()) {}
~ArrayPropertyLock()336 ~ArrayPropertyLock()
337 {
338 if (auto i = interface_cast<ILockable>(this->GetProperty())) {
339 i->Unlock();
340 }
341 }
342
343 InterfaceType operator->() const
344 {
345 return const_cast<ArrayPropertyLock*>(this);
346 }
347
IsValid()348 bool IsValid() const
349 {
350 return this->GetProperty() != nullptr;
351 }
352
353 explicit operator bool() const
354 {
355 return IsValid();
356 }
357 };
358
359 META_END_NAMESPACE()
360
361 #endif
362