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