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