Making DALi public API typesafe using guaranteed types; uint8_t, uint32_t
[platform/core/uifw/dali-core.git] / dali / public-api / object / any.h
1 #ifndef __DALI_ANY_TYPE_H__
2 #define __DALI_ANY_TYPE_H__
3
4 /*
5  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <typeinfo>   // operator typeid
23 #include <cstddef>    // NULL
24
25 // INTERNAL INCLUDES
26 #include <dali/public-api/common/dali-common.h>
27
28 namespace Dali
29 {
30 /**
31  * @addtogroup dali_core_object
32  * @{
33  */
34
35 /**
36  * @brief Stores a value of any type.
37  *
38  * Examples of use:
39  * \code{.cpp}
40  * Any uintVariable = 5u;
41  * Any floatVariable( 4.5f );
42  * Any strVariable( std::string( "Hello world" ) );
43  * uintVariable = 1u;
44  * uint32_t variable = AnyCast< uint32_t >( uintVariable );
45  * if ( typeid( int ) == uintVariable.GetType() )
46  * \endcode
47  * @SINCE_1_0.0
48  */
49 class Any
50 {
51 public:
52   /**
53    * @brief Default constructor.
54    * @SINCE_1_0.0
55    */
56   DALI_CORE_API Any();
57
58   /**
59    * @brief Destructor. Free resources.
60    * @SINCE_1_0.0
61    */
62   DALI_CORE_API ~Any();
63
64   /**
65    * @brief Passes Assert message.
66    *
67    * @SINCE_1_0.0
68    * @param[in] assertMessage Assert message to report
69    */
70   DALI_CORE_API static void AssertAlways( const char* assertMessage );
71
72   /**
73    * @brief Constructs a Any type with the given value.
74    *
75    * @SINCE_1_0.0
76    * @param[in] value The given value
77    */
78   template<typename Type>
79   Any( const Type& value )
80   : mContainer( new AnyContainerImpl<Type>( value ) )
81   {
82   }
83
84   /**
85    * @brief Copy Constructor.
86    * @SINCE_1_0.0
87    * @param[in] any Any to be copied
88    */
89   Any( const Any& any )
90   {
91     // If container isn't empty then copy the container?
92     if ( NULL != any.mContainer )
93     {
94       mContainer = any.mContainer->mCloneFunc( *any.mContainer );
95     }
96     else
97     {
98       // Otherwise mark new container as empty
99       mContainer = NULL;
100     }
101   }
102
103   /**
104    * @brief Assigns a given value to the Any type.
105    *
106    * @SINCE_1_0.0
107    * @param[in] value The given value
108    * @return A reference to this
109    * @note If the types are different, then the current container will be re-created.
110    *
111    */
112   template<typename Type>
113   Any& operator=( const Type& value )
114   {
115     // If the container is empty then assign the new value
116     if ( NULL == mContainer )
117     {
118       mContainer = new AnyContainerImpl< Type >( value );
119     }
120     else
121     {
122       // Check to see if this type is compatible with current container?
123       if ( mContainer->GetType() == typeid( Type ) )
124       {
125         // Same type so just set the new value
126         static_cast< AnyContainerImpl< Type >* >( mContainer )->SetValue( value );
127       }
128       else
129       {
130         // Incompatible types, so delete old container and assign a new one with this type and value
131         mContainer->mDeleteFunc( mContainer );
132         mContainer = new AnyContainerImpl< Type >( value );
133       }
134     }
135     return *this;
136   }
137
138   /**
139    * @brief Assignment operator.
140    *
141    * @SINCE_1_0.0
142    * @param[in] any Any to be assigned which contains a value of identical type to current contents.
143    * @return A reference to this
144    * @exception DaliException If parameter any is of a different type.
145    *
146    */
147   DALI_CORE_API Any& operator=( const Any& any );
148
149   /**
150    * @brief Gets a value of type Type from container.
151    *
152    * @SINCE_1_0.0
153    * @param[in] type destination of type Type to write to
154    */
155   template<typename Type>
156   void Get( Type& type ) const
157   {
158     type = Get<Type>();
159   }
160
161   /**
162    * @brief Returns the type info of the stored value.
163    *
164    * @SINCE_1_0.0
165    * @return The std::type_info of the stored value or the type info of the void
166    * type if there is no value stored
167    */
168   DALI_CORE_API const std::type_info& GetType() const;
169
170   /**
171    * @brief Retrieves the stored value in the Any type.
172    *
173    * @SINCE_1_0.0
174    * @return The stored value
175    */
176   template<typename Type>
177   const Type& Get() const
178   {
179     if ( NULL == mContainer )
180     {
181       AssertAlways( "Any::Get(). mContainer is NULL" );
182     }
183     else if( mContainer->GetType() != typeid( Type ) ) // Check if the value has the same value than the Any type.
184     {
185       AssertAlways( "Any::Get(). Trying to retrieve a value of a different type than the template one." );
186     }
187     return static_cast< AnyContainerImpl< Type >* >( mContainer )->GetValue();
188   }
189
190   /**
191    * @brief Returns pointer of Type to the value stored.
192    *
193    * @SINCE_1_0.0
194    * @return pointer to the value, or NULL if no value is contained
195    */
196   template<typename Type>
197   Type* GetPointer()
198   {
199     if( NULL == mContainer )
200     {
201       return NULL;
202     }
203      // Check if the value has the same value than the Any type.
204     if( mContainer->GetType() != typeid( Type ) )
205     {
206       AssertAlways( "Any::GetPointer(). Trying to retrieve a pointer to a value of a different type than the template one." );
207     }
208     return static_cast< AnyContainerImpl< Type >* >( mContainer )->GetPointerToValue();
209   }
210
211   /**
212    * @brief Returns pointer of Type to the value stored.
213    *
214    * @SINCE_1_0.0
215    * @return pointer to the value, or NULL if no value is contained
216    */
217   template<typename Type>
218   const Type* GetPointer() const
219   {
220     if( NULL == mContainer )
221     {
222       return NULL;
223     }
224      // Check if the value has the same value than the Any type.
225     if( mContainer->GetType() != typeid( Type ) )
226     {
227       AssertAlways( "Any::GetPointer(). Trying to retrieve a pointer to a value of a different type than the template one." );
228     }
229     return static_cast< AnyContainerImpl< Type >* >( mContainer )->GetPointerToValue();
230   }
231
232   /**
233    * @brief Returns whether container holds a value.
234    *
235    * @SINCE_1_0.0
236    * @return @c true if the container is empty, else @c false
237    */
238   bool Empty() const
239   {
240     return ( NULL == mContainer ) ? true : false;
241   }
242
243   struct AnyContainerBase;    // Forward declaration for typedef
244   typedef AnyContainerBase* (*CloneFunc)( const AnyContainerBase& base );
245   typedef void (*DeleteFunc)( const AnyContainerBase* base );
246
247   /**
248    * @brief Base container to hold type for match verification and instance cloning function.
249    *
250    * @SINCE_1_0.0
251    */
252   struct AnyContainerBase
253   {
254     /**
255      * @brief Constructor of base container.
256      *
257      * @SINCE_1_0.0
258      * @param[in] type typeid of container
259      * @param[in] cloneFunc Cloning function to replicate this container type
260      * @param[in] deleteFunc Deleting function to destroy this container type
261      */
262     AnyContainerBase( const std::type_info& type, CloneFunc cloneFunc, DeleteFunc deleteFunc )
263     : mType( type ),
264       mCloneFunc( cloneFunc ),
265       mDeleteFunc( deleteFunc )
266     {}
267
268     /**
269      * @brief Gets the typeid of this container.
270      *
271      * @SINCE_1_0.0
272      * @return Type
273      */
274     const std::type_info& GetType() const
275     {
276       return mType;
277     }
278
279     const::std::type_info& mType;       // typeID
280     CloneFunc mCloneFunc;               // cloning function for this container
281     DeleteFunc mDeleteFunc;             // deleting function for this container
282   };
283
284
285   /**
286    * @brief Templated Clone function from container base.
287    *
288    * @SINCE_1_0.0
289    * @param[in] base The reference to container
290    */
291   template<typename Type>
292   struct AnyContainerImplCloner
293   {
294     static AnyContainerBase* Clone( const AnyContainerBase& base )
295     {
296       return new AnyContainerImpl< Type >( static_cast< AnyContainerImpl< Type > >( base ) );
297     }
298   };
299
300   /**
301    * @brief Templated Delete function from container base.
302    *
303    * @SINCE_1_0.0
304    * @param[in] base The pointer to container
305    */
306   template<typename Type>
307   struct AnyContainerImplDelete
308   {
309     static void Delete( const AnyContainerBase* base )
310     {
311       delete ( static_cast< const AnyContainerImpl< Type >* > ( base ) );
312     }
313   };
314
315   /**
316    * @brief Templated class to hold value for type.
317    *
318    * @SINCE_1_0.0
319    */
320   template<typename Type>
321   class AnyContainerImpl : public AnyContainerBase
322   {
323   public:
324
325     /**
326      * @brief Constructor to create container holding value of type Type.
327      *
328      * @SINCE_1_0.0
329      * @param[in] value Value of Type
330      */
331     AnyContainerImpl( const Type& value )
332     : AnyContainerBase( typeid( Type ),
333                         static_cast< CloneFunc >( &AnyContainerImplCloner< Type >::Clone ),
334                         static_cast< DeleteFunc >( &AnyContainerImplDelete< Type >::Delete ) ),
335                         mValue( value )
336     {}
337
338     /**
339      * @brief Constructor to create new container of type from and existing container (cloning).
340      *
341      * @SINCE_1_0.0
342      * @param[in] base The reference to base container to copy from
343      */
344     AnyContainerImpl( const AnyContainerBase& base )
345     : AnyContainerBase( typeid( Type ),
346                         static_cast< CloneFunc >( &AnyContainerImplCloner< Type >::Clone ),
347                         static_cast< DeleteFunc >( &AnyContainerImplDelete< Type >::Delete ) )
348     {
349       mValue = static_cast< const AnyContainerImpl& >( base ).GetValue();
350     }
351
352     /**
353      * @brief Gets the container's stored value.
354      *
355      * @SINCE_1_0.0
356      * @return Value of type Type
357      */
358     const Type& GetValue() const
359     {
360       return mValue;
361     }
362
363     /**
364      * @brief Sets the container's stored value.
365      *
366      * @SINCE_1_0.0
367      * @param[in] value Value of type Type
368      */
369     void SetValue( const Type& value )
370     {
371       mValue = value;
372     }
373
374     /**
375      * @brief Gets a pointer to the value held.
376      *
377      * @SINCE_1_0.0
378      * @return Pointer to the value of type Type
379      */
380     Type* GetPointerToValue()
381     {
382       return static_cast< Type* >( &mValue );
383     }
384
385     /**
386      * @brief Gets a pointer to the value held.
387      *
388      * @SINCE_1_0.0
389      * @return Pointer to the value of type Type
390      */
391     const Type* GetPointerToValue() const
392     {
393       return static_cast< const Type* >( &mValue );
394     }
395
396     private:
397       Type mValue;
398   };
399
400   AnyContainerBase* mContainer;
401
402 };
403
404 /**
405  * AnyCast helper functions
406  */
407
408 /**
409  * @brief Extracts a pointer to the held type of an Any object from a pointer to that Any object (NULL if empty).
410  *
411  * @SINCE_1_0.0
412  * @param[in] any Pointer to an Any object
413  *
414  * @return Pointer to the Type held
415  */
416 template<typename Type>
417 inline Type* AnyCast( Any* any )
418 {
419   return any->GetPointer<Type>();
420 }
421
422 /**
423  * @brief Extracts a const pointer to the held type of an Any object from a pointer to that Any object (NULL if empty).
424  *
425  * @SINCE_1_0.0
426  * @param[in] any const Pointer to an Any object
427  *
428  * @return const Pointer to the Type held
429  */
430 template<typename Type>
431 inline const Type* AnyCast( const Any* any )
432 {
433   return any->GetPointer<Type>();
434 }
435
436 /**
437  * @brief Extracts a held value of type Type from an Any object from a reference to that Any object.
438  *
439  * @SINCE_1_0.0
440  * @param[in] any The reference to an Any object
441  *
442  * @return Type value of type Type
443  */
444 template<typename Type>
445 inline Type AnyCast( Any& any )
446 {
447   return any.Get<Type>();
448 }
449
450 /**
451  * @brief Extracts a held value of type Type from an Any object from a const reference to that Any object.
452  *
453  * @SINCE_1_0.0
454  * @param[in] any The reference to an Any object
455  *
456  * @return Type value of type Type
457  */
458 template<typename Type>
459 inline Type AnyCast( const Any& any )
460 {
461   return any.Get<Type>();
462 }
463
464 /**
465  * @brief Extracts a reference to the held value of type Type from an Any object from a reference to that Any object
466  *
467  * @SINCE_1_0.0
468  * @param[in] any The reference to an Any object
469  *
470  * @return A reference to the Type value of type Type
471  */
472 template<typename Type>
473 inline Type& AnyCastReference( Any& any )
474 {
475   return any.Get<Type>();
476 }
477
478 /**
479  * @brief Extracts a const reference to the held value of type Type from an Any object from a const reference to that Any object.
480  *
481  * @SINCE_1_0.0
482  * @param[in] any The reference to an Any object
483  *
484  * @return A const reference to the Type value of type Type
485  */
486 template<typename Type>
487 inline const Type& AnyCastReference( const Any& any )
488 {
489   return any.Get<Type>();
490 }
491
492 /**
493  * @}
494  */
495 } // namespace Dali
496
497 #endif // __DALI_ANY_TYPE_H__