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/any.h>
20 #include <meta/interface/detail/property.h>
21 
META_BEGIN_NAMESPACE()22 META_BEGIN_NAMESPACE()
23 
24 template<typename Base>
25 class ConstTypelessArrayPropertyInterfaceImpl : public Base {
26 public:
27     using IndexType = IArrayAny::IndexType;
28 
29     template<typename Prop>
30     explicit ConstTypelessArrayPropertyInterfaceImpl(Prop* p) : Base(p)
31     {}
32 
33     IndexType GetSize() const
34     {
35         if (auto arr = interface_cast<IArrayAny>(&this->GetValueAny())) {
36             return arr->GetSize();
37         }
38         return {};
39     }
40     AnyReturnValue GetAnyAt(IndexType index, IAny& any) const
41     {
42         if (auto arr = interface_cast<IArrayAny>(&this->GetValueAny())) {
43             return arr->GetAnyAt(index, any);
44         }
45         return AnyReturn::INCOMPATIBLE_TYPE;
46     }
47 };
48 
49 using ConstTypelessArrayPropertyInterface = ConstTypelessArrayPropertyInterfaceImpl<ConstTypelessPropertyInterface>;
50 
51 class TypelessArrayPropertyInterface : public ConstTypelessArrayPropertyInterfaceImpl<TypelessPropertyInterface> {
52 public:
53     using PropertyType = IProperty*;
54     using IndexType = IArrayAny::IndexType;
55 
TypelessArrayPropertyInterface(PropertyType p)56     TypelessArrayPropertyInterface(PropertyType p)
57         : ConstTypelessArrayPropertyInterfaceImpl<TypelessPropertyInterface>(p)
58     {}
59 
SetAnyAt(IndexType index,const IAny & v)60     AnyReturnValue SetAnyAt(IndexType index, const IAny& v)
61     {
62         if (auto c = this->GetValueAny().Clone(true)) {
63             if (auto arr = interface_cast<IArrayAny>(c)) {
64                 arr->SetAnyAt(index, v);
65                 return this->SetValueAny(*arr);
66             }
67         }
68         return AnyReturn::INCOMPATIBLE_TYPE;
69     }
AddAny(const IAny & v)70     AnyReturnValue AddAny(const IAny& v)
71     {
72         return InsertAnyAt(-1, v);
73     }
InsertAnyAt(IndexType index,const IAny & v)74     AnyReturnValue InsertAnyAt(IndexType index, const IAny& v)
75     {
76         if (auto c = this->GetValueAny().Clone(true)) {
77             if (auto arr = interface_cast<IArrayAny>(c)) {
78                 arr->InsertAnyAt(index, v);
79                 return this->SetValueAny(*arr);
80             }
81         }
82         return AnyReturn::INCOMPATIBLE_TYPE;
83     }
RemoveAt(IndexType index)84     bool RemoveAt(IndexType index)
85     {
86         if (auto c = this->GetValueAny().Clone(true)) {
87             if (auto arr = interface_cast<IArrayAny>(c)) {
88                 arr->RemoveAt(index);
89                 return this->SetValueAny(*arr);
90             }
91         }
92         return false;
93     }
94 };
95 
96 template<typename Type>
97 using ArrayPropertyBaseType = BASE_NS::conditional_t<BASE_NS::is_const_v<Type>, ConstTypelessArrayPropertyInterface,
98     TypelessArrayPropertyInterface>;
99 
100 template<typename Type>
101 class ArrayPropertyInterface : public ArrayPropertyBaseType<Type> {
102     using Super = ArrayPropertyBaseType<Type>;
103 
104 public:
105     using ValueType = BASE_NS::remove_const_t<Type>;
106     using PropertyType = typename PropertyBaseType<Type>::PropertyType;
107     using IndexType = IArrayAny::IndexType;
108 
ArrayPropertyInterface(PropertyType p)109     explicit ArrayPropertyInterface(PropertyType p) : Super(p) {}
110 
GetValueAt(IndexType index)111     ValueType GetValueAt(IndexType index) const
112     {
113         Any<ValueType> any;
114         if (auto arr = interface_cast<IArrayAny>(&this->GetValueAny())) {
115             arr->GetAnyAt(index, any);
116         }
117         return any.InternalGetValue();
118     }
SetValueAt(IndexType index,const Type & v)119     bool SetValueAt(IndexType index, const Type& v)
120     {
121         BASE_NS::vector<ValueType> vec;
122         if (this->GetValueAny().GetValue(vec)) {
123             if (index < vec.size()) {
124                 vec[index] = v;
125                 return this->SetValueAny(ArrayAny<ValueType>(BASE_NS::move(vec)));
126             }
127         }
128         return false;
129     }
AddValue(const Type & v)130     bool AddValue(const Type& v)
131     {
132         return InsertValueAt(-1, v);
133     }
InsertValueAt(IndexType index,const Type & v)134     bool InsertValueAt(IndexType index, const Type& v)
135     {
136         BASE_NS::vector<ValueType> vec;
137         if (this->GetValueAny().GetValue(vec)) {
138             index = index < vec.size() ? index : vec.size();
139             vec.insert(vec.begin() + index, v);
140             return this->SetValueAny(ArrayAny<ValueType>(BASE_NS::move(vec)));
141         }
142         return false;
143     }
GetDefaultValue()144     BASE_NS::vector<ValueType> GetDefaultValue() const
145     {
146         BASE_NS::vector<ValueType> v;
147         this->GetDefaultValueAny().GetValue(v);
148         return v;
149     }
150 
SetDefaultValue(BASE_NS::array_view<const ValueType> value)151     AnyReturnValue SetDefaultValue(BASE_NS::array_view<const ValueType> value)
152     {
153         return this->SetDefaultValueAny(ArrayAny<ValueType>(value));
154     }
155 
156     template<typename T, typename = BASE_NS::enable_if_t<BASE_NS::is_same_v<T, ValueType>>>
SetDefaultValue(BASE_NS::vector<T> value)157     AnyReturnValue SetDefaultValue(BASE_NS::vector<T> value)
158     {
159         return this->SetDefaultValueAny(ArrayAny<ValueType>(BASE_NS::move(value)));
160     }
161 
SetDefaultValue(BASE_NS::vector<ValueType> value,bool resetToDefault)162     AnyReturnValue SetDefaultValue(BASE_NS::vector<ValueType> value, bool resetToDefault)
163     {
164         auto ret = this->SetDefaultValueAny(ArrayAny<ValueType>(BASE_NS::move(value)));
165         if (resetToDefault && ret) {
166             this->ResetValue();
167         }
168         return ret;
169     }
170 
GetValue()171     BASE_NS::vector<ValueType> GetValue() const
172     {
173         BASE_NS::vector<ValueType> v {};
174         this->GetValueAny().GetValue(v);
175         return v;
176     }
177 
SetValue(BASE_NS::array_view<const ValueType> value)178     AnyReturnValue SetValue(BASE_NS::array_view<const ValueType> value)
179     {
180         return this->SetValueAny(ArrayAny<ValueType>(value));
181     }
182 
183     template<typename T, typename = BASE_NS::enable_if_t<BASE_NS::is_same_v<T, ValueType>>>
SetValue(BASE_NS::vector<T> value)184     AnyReturnValue SetValue(BASE_NS::vector<T> value)
185     {
186         return this->SetValueAny(ArrayAny<ValueType>(BASE_NS::move(value)));
187     }
188 
FindFirstValueOf(const Type & v)189     IndexType FindFirstValueOf(const Type& v) const
190     {
191         for (IndexType i = 0; i != this->GetSize(); ++i) {
192             if (GetValueAt(i) == v) {
193                 return i;
194             }
195         }
196         return -1;
197     }
198 };
199 
200 template<typename Type>
201 class TypedArrayPropertyLock final : public ArrayPropertyInterface<Type> {
202     using PropertyType = typename ArrayPropertyInterface<Type>::PropertyType;
203     using IT = ArrayPropertyInterface<Type>;
204     using InterfaceType = BASE_NS::conditional_t<BASE_NS::is_const_v<Type>, const IT*, IT*>;
205 
META_NO_COPY_MOVE(TypedArrayPropertyLock)206     META_NO_COPY_MOVE(TypedArrayPropertyLock)
207 
208 public:
209     explicit TypedArrayPropertyLock(PropertyType p) : ArrayPropertyInterface<Type>(p)
210     {
211         if (auto i = interface_cast<ILockable>(p)) {
212             i->Lock();
213         }
214     }
~TypedArrayPropertyLock()215     ~TypedArrayPropertyLock()
216     {
217         if (auto i = interface_cast<ILockable>(this->GetProperty())) {
218             i->Unlock();
219         }
220     }
221 
222     InterfaceType operator->() const
223     {
224         return const_cast<TypedArrayPropertyLock*>(this);
225     }
226 };
227 
228 template<typename Property>
229 class ArrayPropertyLock final : public ArrayPropertyBaseType<Property> {
230     using InterfaceType = ArrayPropertyBaseType<Property>*;
231 
META_NO_COPY_MOVE(ArrayPropertyLock)232     META_NO_COPY_MOVE(ArrayPropertyLock)
233 
234 public:
235     explicit ArrayPropertyLock(BASE_NS::shared_ptr<Property> p) : ArrayPropertyBaseType<Property>(p.get())
236     {
237         if (auto i = interface_cast<ILockable>(p)) {
238             i->Lock();
239         }
240     }
~ArrayPropertyLock()241     ~ArrayPropertyLock()
242     {
243         if (auto i = interface_cast<ILockable>(this->GetProperty())) {
244             i->Unlock();
245         }
246     }
247 
248     InterfaceType operator->() const
249     {
250         return const_cast<ArrayPropertyLock*>(this);
251     }
252 };
253 
254 META_END_NAMESPACE()
255 
256 #endif
257