Merge branch 'devel/master' into tizen
[platform/core/uifw/dali-core.git] / dali / public-api / object / property-map.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/public-api/object/property-map.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/common/vector-wrapper.h>
26
27 namespace Dali
28 {
29 namespace
30 {
31 typedef std::vector<StringValuePair> StringValueContainer;
32
33 using IndexValuePair      = std::pair<Property::Index, Property::Value>;
34 using IndexValueContainer = std::vector<IndexValuePair>;
35
36 }; // unnamed namespace
37
38 struct Property::Map::Impl
39 {
40   StringValueContainer mStringValueContainer;
41   IndexValueContainer  mIndexValueContainer;
42 };
43
44 Property::Map::Map()
45 : mImpl(new Impl)
46 {
47 }
48
49 Property::Map::Map(const std::initializer_list<KeyValuePair>& values)
50 : Map()
51 {
52   for(auto&& value : values)
53   {
54     const auto& key = value.first;
55     switch(key.type)
56     {
57       case Property::Key::INDEX:
58       {
59         Property::Map::Insert(key.indexKey, value.second);
60         break;
61       }
62       case Property::Key::STRING:
63       {
64         Property::Map::Insert(key.stringKey, value.second);
65         break;
66       }
67     }
68   }
69 }
70
71 Property::Map::Map(const Property::Map& other)
72 : mImpl(new Impl)
73 {
74   mImpl->mStringValueContainer = other.mImpl->mStringValueContainer;
75   mImpl->mIndexValueContainer  = other.mImpl->mIndexValueContainer;
76 }
77
78 Property::Map::Map(Property::Map&& other)
79 : mImpl(other.mImpl)
80 {
81   other.mImpl = nullptr;
82 }
83
84 Property::Map::~Map()
85 {
86   delete mImpl;
87 }
88
89 Property::Map::SizeType Property::Map::Count() const
90 {
91   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
92   return mImpl->mStringValueContainer.size() + mImpl->mIndexValueContainer.size();
93 }
94
95 bool Property::Map::Empty() const
96 {
97   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
98   return mImpl->mStringValueContainer.empty() && mImpl->mIndexValueContainer.empty();
99 }
100
101 void Property::Map::Insert(std::string key, Value value)
102 {
103   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
104   mImpl->mStringValueContainer.push_back(std::make_pair(std::move(key), std::move(value)));
105 }
106
107 void Property::Map::Insert(Property::Index key, Value value)
108 {
109   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
110   mImpl->mIndexValueContainer.push_back(std::make_pair(key, std::move(value)));
111 }
112
113 Property::Value& Property::Map::GetValue(SizeType position) const
114 {
115   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
116   SizeType numStringKeys = mImpl->mStringValueContainer.size();
117   SizeType numIndexKeys  = mImpl->mIndexValueContainer.size();
118   DALI_ASSERT_ALWAYS(position < (numStringKeys + numIndexKeys) && "position out-of-bounds");
119
120   if(position < numStringKeys)
121   {
122     return mImpl->mStringValueContainer[position].second;
123   }
124   else
125   {
126     return mImpl->mIndexValueContainer[position - numStringKeys].second;
127   }
128 }
129
130 const std::string& Property::Map::GetKey(SizeType position) const
131 {
132   DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: GetKey() is deprecated and will be removed from next release.\n");
133
134   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
135   SizeType numStringKeys = mImpl->mStringValueContainer.size();
136   DALI_ASSERT_ALWAYS(position < numStringKeys && "position out-of-bounds");
137
138   return mImpl->mStringValueContainer[position].first;
139 }
140
141 Property::Key Property::Map::GetKeyAt(SizeType position) const
142 {
143   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
144
145   SizeType numStringKeys = mImpl->mStringValueContainer.size();
146   SizeType numIndexKeys  = mImpl->mIndexValueContainer.size();
147   DALI_ASSERT_ALWAYS(position < (numStringKeys + numIndexKeys) && "position out-of-bounds");
148
149   if(position < numStringKeys)
150   {
151     Key key(mImpl->mStringValueContainer[position].first);
152     return key;
153   }
154   else
155   {
156     Key key(mImpl->mIndexValueContainer[position - numStringKeys].first);
157     return key;
158   }
159 }
160
161 StringValuePair& Property::Map::GetPair(SizeType position) const
162 {
163   DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: GetPair() is deprecated and will be removed from next release.\n");
164
165   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
166
167   SizeType numStringKeys = mImpl->mStringValueContainer.size();
168
169   DALI_ASSERT_ALWAYS(position < (numStringKeys) && "position out-of-bounds");
170
171   return mImpl->mStringValueContainer[position];
172 }
173
174 KeyValuePair Property::Map::GetKeyValue(SizeType position) const
175 {
176   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
177
178   SizeType numStringKeys = mImpl->mStringValueContainer.size();
179   SizeType numIndexKeys  = mImpl->mIndexValueContainer.size();
180
181   DALI_ASSERT_ALWAYS(position < (numStringKeys + numIndexKeys) && "position out-of-bounds");
182
183   if(position < numStringKeys)
184   {
185     Key          key(mImpl->mStringValueContainer[position].first);
186     KeyValuePair keyValue(key, mImpl->mStringValueContainer[position].second);
187     return keyValue;
188   }
189   else
190   {
191     return mImpl->mIndexValueContainer[position - numStringKeys];
192   }
193 }
194
195 Property::Value* Property::Map::Find(std::string_view key) const
196 {
197   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
198
199   for(auto&& iter : mImpl->mStringValueContainer)
200   {
201     if(key == iter.first)
202     {
203       return &iter.second;
204     }
205   }
206   return nullptr; // Not found
207 }
208
209 Property::Value* Property::Map::Find(Property::Index key) const
210 {
211   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
212
213   for(auto&& iter : mImpl->mIndexValueContainer)
214   {
215     if(iter.first == key)
216     {
217       return &iter.second;
218     }
219   }
220   return nullptr; // Not found
221 }
222
223 Property::Value* Property::Map::Find(Property::Index indexKey, std::string_view stringKey) const
224 {
225   Property::Value* valuePtr = Find(indexKey);
226   if(!valuePtr)
227   {
228     valuePtr = Find(stringKey);
229   }
230   return valuePtr;
231 }
232
233 Property::Value* Property::Map::Find(std::string_view key, Property::Type type) const
234 {
235   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
236
237   for(auto&& iter : mImpl->mStringValueContainer)
238   {
239     if((iter.second.GetType() == type) && (key == iter.first))
240     {
241       return &iter.second;
242     }
243   }
244   return nullptr; // Not found
245 }
246
247 Property::Value* Property::Map::Find(Property::Index key, Property::Type type) const
248 {
249   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
250
251   for(auto&& iter : mImpl->mIndexValueContainer)
252   {
253     if((iter.second.GetType() == type) && (iter.first == key))
254     {
255       return &iter.second;
256     }
257   }
258   return nullptr; // Not found
259 }
260
261 void Property::Map::Clear()
262 {
263   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
264
265   mImpl->mStringValueContainer.clear();
266   mImpl->mIndexValueContainer.clear();
267 }
268
269 bool Property::Map::Remove(Property::Index key)
270 {
271   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
272
273   auto iter = std::find_if(mImpl->mIndexValueContainer.begin(), mImpl->mIndexValueContainer.end(), [key](const IndexValuePair& element) { return element.first == key; });
274   if(iter != mImpl->mIndexValueContainer.end())
275   {
276     mImpl->mIndexValueContainer.erase(iter);
277     return true;
278   }
279   return false;
280 }
281
282 bool Property::Map::Remove(std::string_view key)
283 {
284   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
285
286   auto iter = std::find_if(mImpl->mStringValueContainer.begin(), mImpl->mStringValueContainer.end(), [key](const StringValuePair& element) { return element.first == key; });
287   if(iter != mImpl->mStringValueContainer.end())
288   {
289     mImpl->mStringValueContainer.erase(iter);
290     return true;
291   }
292   return false;
293 }
294
295 void Property::Map::Merge(const Property::Map& from)
296 {
297   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
298
299   // Ensure we're not attempting to merge with ourself
300   if(this != &from)
301   {
302     if(Count())
303     {
304       for(auto&& iter : from.mImpl->mStringValueContainer)
305       {
306         (*this)[iter.first] = iter.second;
307       }
308
309       for(auto&& iter : from.mImpl->mIndexValueContainer)
310       {
311         (*this)[iter.first] = iter.second;
312       }
313     }
314     else
315     {
316       // If we're empty, then just copy
317       *this = from;
318     }
319   }
320 }
321
322 const Property::Value& Property::Map::operator[](std::string_view key) const
323 {
324   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
325
326   for(auto&& iter : mImpl->mStringValueContainer)
327   {
328     if(iter.first == key)
329     {
330       return iter.second;
331     }
332   }
333
334   DALI_ASSERT_ALWAYS(!"Invalid Key");
335 }
336
337 Property::Value& Property::Map::operator[](std::string_view key)
338 {
339   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
340
341   for(auto&& iter : mImpl->mStringValueContainer)
342   {
343     if(iter.first == key)
344     {
345       return iter.second;
346     }
347   }
348
349   // Create and return reference to new value
350   mImpl->mStringValueContainer.push_back(std::make_pair(std::string(key), Property::Value()));
351   return mImpl->mStringValueContainer.back().second;
352 }
353
354 const Property::Value& Property::Map::operator[](Property::Index key) const
355 {
356   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
357
358   for(auto&& iter : mImpl->mIndexValueContainer)
359   {
360     if(iter.first == key)
361     {
362       return iter.second;
363     }
364   }
365
366   DALI_ASSERT_ALWAYS(!"Invalid Key");
367 }
368
369 Property::Value& Property::Map::operator[](Property::Index key)
370 {
371   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
372
373   for(auto&& iter : mImpl->mIndexValueContainer)
374   {
375     if(iter.first == key)
376     {
377       return iter.second;
378     }
379   }
380
381   // Create and return reference to new value
382   mImpl->mIndexValueContainer.push_back(std::make_pair(key, Property::Value()));
383   return mImpl->mIndexValueContainer.back().second;
384 }
385
386 Property::Map& Property::Map::operator=(const Property::Map& other)
387 {
388   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
389
390   if(this != &other)
391   {
392     mImpl->mStringValueContainer = other.mImpl->mStringValueContainer;
393     mImpl->mIndexValueContainer  = other.mImpl->mIndexValueContainer;
394   }
395   return *this;
396 }
397
398 Property::Map& Property::Map::operator=(Property::Map&& other)
399 {
400   if(this != &other)
401   {
402     delete mImpl;
403     mImpl       = other.mImpl;
404     other.mImpl = nullptr;
405   }
406   return *this;
407 }
408
409 std::ostream& operator<<(std::ostream& stream, const Property::Map& map)
410 {
411   stream << "Map(" << map.Count() << ") = {";
412
413   if(map.mImpl)
414   {
415     int32_t count = 0;
416     // Output the String-Value pairs
417     for(auto&& iter : map.mImpl->mStringValueContainer)
418     {
419       if(count++ > 0)
420       {
421         stream << ", ";
422       }
423       stream << iter.first << ":" << iter.second;
424     }
425
426     // Output the Index-Value pairs
427     for(auto&& iter : map.mImpl->mIndexValueContainer)
428     {
429       if(count++ > 0)
430       {
431         stream << ", ";
432       }
433       stream << iter.first << ":" << iter.second;
434     }
435   }
436
437   stream << "}";
438
439   return stream;
440 }
441
442 } // namespace Dali