Merge "Clean up the code to build successfully on macOS" into devel/master
[platform/core/uifw/dali-core.git] / dali / public-api / object / property-map.cpp
1 /*
2  * Copyright (c) 2020 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 void Property::Map::Merge(const Property::Map& from)
270 {
271   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
272
273   // Ensure we're not attempting to merge with ourself
274   if(this != &from)
275   {
276     if(Count())
277     {
278       for(auto&& iter : from.mImpl->mStringValueContainer)
279       {
280         (*this)[iter.first] = iter.second;
281       }
282
283       for(auto&& iter : from.mImpl->mIndexValueContainer)
284       {
285         (*this)[iter.first] = iter.second;
286       }
287     }
288     else
289     {
290       // If we're empty, then just copy
291       *this = from;
292     }
293   }
294 }
295
296 const Property::Value& Property::Map::operator[](std::string_view key) const
297 {
298   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
299
300   for(auto&& iter : mImpl->mStringValueContainer)
301   {
302     if(iter.first == key)
303     {
304       return iter.second;
305     }
306   }
307
308   DALI_ASSERT_ALWAYS(!"Invalid Key");
309 }
310
311 Property::Value& Property::Map::operator[](std::string_view key)
312 {
313   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
314
315   for(auto&& iter : mImpl->mStringValueContainer)
316   {
317     if(iter.first == key)
318     {
319       return iter.second;
320     }
321   }
322
323   // Create and return reference to new value
324   mImpl->mStringValueContainer.push_back(std::make_pair(std::string(key), Property::Value()));
325   return mImpl->mStringValueContainer.back().second;
326 }
327
328 const Property::Value& Property::Map::operator[](Property::Index key) const
329 {
330   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
331
332   for(auto&& iter : mImpl->mIndexValueContainer)
333   {
334     if(iter.first == key)
335     {
336       return iter.second;
337     }
338   }
339
340   DALI_ASSERT_ALWAYS(!"Invalid Key");
341 }
342
343 Property::Value& Property::Map::operator[](Property::Index key)
344 {
345   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
346
347   for(auto&& iter : mImpl->mIndexValueContainer)
348   {
349     if(iter.first == key)
350     {
351       return iter.second;
352     }
353   }
354
355   // Create and return reference to new value
356   mImpl->mIndexValueContainer.push_back(std::make_pair(key, Property::Value()));
357   return mImpl->mIndexValueContainer.back().second;
358 }
359
360 Property::Map& Property::Map::operator=(const Property::Map& other)
361 {
362   DALI_ASSERT_DEBUG(mImpl && "Cannot use an object previously used as an r-value");
363
364   if(this != &other)
365   {
366     mImpl->mStringValueContainer = other.mImpl->mStringValueContainer;
367     mImpl->mIndexValueContainer  = other.mImpl->mIndexValueContainer;
368   }
369   return *this;
370 }
371
372 Property::Map& Property::Map::operator=(Property::Map&& other)
373 {
374   if(this != &other)
375   {
376     delete mImpl;
377     mImpl       = other.mImpl;
378     other.mImpl = nullptr;
379   }
380   return *this;
381 }
382
383 std::ostream& operator<<(std::ostream& stream, const Property::Map& map)
384 {
385   stream << "Map(" << map.Count() << ") = {";
386
387   if(map.mImpl)
388   {
389     int32_t count = 0;
390     // Output the String-Value pairs
391     for(auto&& iter : map.mImpl->mStringValueContainer)
392     {
393       if(count++ > 0)
394       {
395         stream << ", ";
396       }
397       stream << iter.first << ":" << iter.second;
398     }
399
400     // Output the Index-Value pairs
401     for(auto&& iter : map.mImpl->mIndexValueContainer)
402     {
403       if(count++ > 0)
404       {
405         stream << ", ";
406       }
407       stream << iter.first << ":" << iter.second;
408     }
409   }
410
411   stream << "}";
412
413   return stream;
414 }
415
416 } // namespace Dali