[dali_1.9.14] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / public-api / object / property-value.cpp
index 8093309..7132bfb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 // CLASS HEADER
 #include <dali/public-api/object/property-value.h>
 
+// EXTERNAL INCLUDES
+#include <ostream>
+
 // INTERNAL INCLUDES
-#include <dali/public-api/object/any.h>
+#include <dali/public-api/common/extents.h>
 #include <dali/public-api/math/angle-axis.h>
 #include <dali/public-api/math/radian.h>
 #include <dali/public-api/math/vector2.h>
 #include <dali/public-api/math/matrix.h>
 #include <dali/public-api/math/rect.h>
 #include <dali/public-api/math/quaternion.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/property-array.h>
 #include <dali/public-api/object/property-types.h>
 #include <dali/integration-api/debug.h>
 
 namespace Dali
 {
 
+namespace
+{
+/**
+ * Helper to check if the property value can be read as int/bool
+ */
+inline bool IsIntegerType( Property::Type type )
+{
+  return ( Property::BOOLEAN == type )||( Property::INTEGER == type );
+}
+}
+
 struct Property::Value::Impl
 {
-  Impl()
-  : mType( Property::NONE )
-  {
-  }
+  Impl( bool booleanValue )
+  : type( Property::BOOLEAN ),
+    integerValue( booleanValue )
+  { }
+
+  Impl( float floatValue )
+  : type( Property::FLOAT ),
+    floatValue( floatValue )
+  { }
+
+  Impl( int32_t integerValue )
+  : type( Property::INTEGER ),
+    integerValue( integerValue )
+  { }
+
+  Impl( const Vector2& vectorValue )
+  : type( Property::VECTOR2 ),
+    vector2Value( new Vector2( vectorValue ) )
+  { }
 
-  Impl(bool boolValue)
-  : mType( PropertyTypes::Get<bool>() ),
-    mValue( boolValue )
+  Impl( const Vector3& vectorValue )
+  : type( Property::VECTOR3 ),
+    vector3Value( new Vector3( vectorValue ) )
+  { }
+
+  Impl( const Vector4& vectorValue )
+  : type( Property::VECTOR4 ),
+    vector4Value( new Vector4( vectorValue ) )
+  { }
+
+  Impl( const Matrix3& matrixValue )
+  : type( Property::MATRIX3 ),
+    matrix3Value( new Matrix3( matrixValue ) )
   {
   }
 
-  Impl(float floatValue)
-  : mType( PropertyTypes::Get<float>() ),
-    mValue( floatValue )
+  Impl( const Matrix& matrixValue )
+  : type( Property::MATRIX ),
+    matrixValue( new Matrix( matrixValue ) )
   {
   }
 
-  Impl(int integerValue)
-  : mType( PropertyTypes::Get<int>() ),
-    mValue( integerValue )
+  Impl( const AngleAxis& angleAxisValue )
+  : type( Property::ROTATION ),
+    angleAxisValue( new AngleAxis(angleAxisValue) )
   {
   }
 
-  Impl(unsigned int unsignedIntegerValue)
-  : mType( PropertyTypes::Get<unsigned int>() ),
-    mValue( unsignedIntegerValue )
+  Impl( const Quaternion& quaternionValue )
+  : type( Property::ROTATION ),
+    angleAxisValue( new AngleAxis() )
   {
+    quaternionValue.ToAxisAngle( angleAxisValue->axis, angleAxisValue->angle );
   }
 
-  Impl(const Vector2& vectorValue)
-  : mType( PropertyTypes::Get<Vector2>() ),
-    mValue( vectorValue )
+  Impl( const std::string& stringValue )
+  : type( Property::STRING ),
+    stringValue( new std::string( stringValue ) )
   {
   }
 
-  Impl(const Vector3& vectorValue)
-  : mType( PropertyTypes::Get<Vector3>() ),
-    mValue( vectorValue )
+  Impl( const Rect<int32_t>& rectValue )
+  : type( Property::RECTANGLE ),
+    rectValue( new Rect<int>( rectValue ) )
   {
   }
 
-  Impl(const Vector4& vectorValue)
-  : mType( PropertyTypes::Get<Vector4>() ),
-    mValue( vectorValue )
+  Impl( const Rect<float>& rectValue )
+  : type( Property::VECTOR4 ),
+    vector4Value( new Vector4( rectValue.x, rectValue.y, rectValue.width, rectValue.height ) )
   {
   }
 
-  Impl(const Matrix3& matrixValue)
-  : mType(PropertyTypes::Get<Matrix3>()),
-    mValue(matrixValue)
+  Impl( const Property::Array& arrayValue )
+  : type( Property::ARRAY ),
+    arrayValue( new Property::Array( arrayValue ) )
   {
   }
 
-  Impl(const Matrix& matrixValue)
-  : mType(PropertyTypes::Get<Matrix>()),
-    mValue(matrixValue)
+  Impl( Property::Array&& arrayValue )
+  : type( Property::ARRAY ),
+    arrayValue( new Property::Array( std::move( arrayValue ) ) )
   {
   }
 
-  Impl(const AngleAxis& angleAxisValue)
-  : mType( PropertyTypes::Get<AngleAxis>() ),
-    mValue( angleAxisValue )
+  Impl( const Property::Map& mapValue )
+  : type( Property::MAP ),
+    mapValue( new Property::Map( mapValue ) )
   {
   }
 
-  Impl(const Quaternion& quaternionValue)
-  : mType( PropertyTypes::Get<Quaternion>() ),
-    mValue( quaternionValue )
+  Impl( Property::Map&& mapValue )
+  : type( Property::MAP ),
+    mapValue( new Property::Map( std::move( mapValue ) ) )
   {
   }
 
-  Impl(const std::string& stringValue)
-    : mType( PropertyTypes::Get<std::string>() ),
-      mValue( stringValue )
+  Impl( const Extents& extentsValue )
+  : type( Property::EXTENTS ),
+    extentsValue( new Extents( extentsValue ) )
   {
   }
 
-  Impl(const Rect<int>& rect)
-    : mType( PropertyTypes::Get<Rect<int> >() ),
-      mValue( rect )
+  Impl( const std::initializer_list< KeyValuePair >& values )
+  : type( Property::MAP ),
+    mapValue( new Property::Map( values ) )
   {
   }
 
-  Impl(Property::Map container)
-    : mType( PropertyTypes::Get<Property::Map >() ),
-      mValue( container )
+  /**
+   * Destructor, takes care of releasing the dynamically allocated types
+   */
+  ~Impl()
   {
+    switch( type )
+    {
+      case Property::NONE :             // FALLTHROUGH
+      case Property::BOOLEAN :          // FALLTHROUGH
+      case Property::FLOAT :            // FALLTHROUGH
+      case Property::INTEGER :
+      {
+        break; // nothing to do
+      }
+      case Property::VECTOR2 :
+      {
+        delete vector2Value;
+        break;
+      }
+      case Property::VECTOR3:
+      {
+        delete vector3Value;
+        break;
+      }
+      case Property::VECTOR4:
+      {
+        delete vector4Value;
+        break;
+      }
+      case Property::MATRIX3:
+      {
+        delete matrix3Value;
+        break;
+      }
+      case Property::MATRIX:
+      {
+        delete matrixValue;
+        break;
+      }
+      case Property::RECTANGLE:
+      {
+        delete rectValue;
+        break;
+      }
+      case Property::ROTATION:
+      {
+        delete angleAxisValue;
+        break;
+      }
+      case Property::STRING:
+      {
+        delete stringValue;
+        break;
+      }
+      case Property::ARRAY:
+      {
+        delete arrayValue;
+        break;
+      }
+      case Property::MAP:
+      {
+        delete mapValue;
+        break;
+      }
+      case Property::EXTENTS:
+      {
+        delete extentsValue;
+        break;
+      }
+    }
   }
 
-  Impl(Property::Array container)
-    : mType( PropertyTypes::Get<Property::Array >() ),
-      mValue( container )
+public: // Data
+
+  Type type;
+  union
   {
-  }
+    int32_t integerValue;
+    float floatValue;
+    // must use pointers for any class value pre c++ 11
+    Vector2* vector2Value;
+    Vector3* vector3Value;
+    Vector4* vector4Value;
+    Matrix3* matrix3Value;
+    Matrix* matrixValue;
+    AngleAxis* angleAxisValue;
+    std::string* stringValue;
+    Rect<int32_t>* rectValue;
+    Property::Array* arrayValue;
+    Property::Map* mapValue;
+    Extents* extentsValue;
+  };
 
-  Type mType;
+private:
+
+  // non-copyable
+  Impl( const Impl& ) = delete;
+  Impl& operator=( const Impl& ) = delete;
 
-  typedef Any AnyValue;
-  AnyValue mValue;
 };
 
 Property::Value::Value()
-: mImpl( NULL )
+: mImpl( nullptr )
+{
+}
+
+Property::Value::Value( bool booleanValue )
+: mImpl( new Impl( booleanValue ) )
+{
+}
+
+Property::Value::Value( float floatValue )
+: mImpl( new Impl( floatValue ) )
 {
-  mImpl = new Impl();
 }
 
-Property::Value::Value(bool boolValue)
-: mImpl( NULL )
+Property::Value::Value( int32_t integerValue )
+: mImpl( new Impl( integerValue ) )
 {
-  mImpl = new Impl( boolValue );
 }
 
-Property::Value::Value(float floatValue)
-: mImpl( NULL )
+Property::Value::Value( const Vector2& vectorValue )
+: mImpl( new Impl( vectorValue ) )
 {
-  mImpl = new Impl( floatValue );
 }
 
-Property::Value::Value(int integerValue)
-: mImpl( NULL )
+Property::Value::Value( const Vector3& vectorValue )
+: mImpl( new Impl( vectorValue ) )
 {
-  mImpl = new Impl( integerValue );
 }
 
-Property::Value::Value(unsigned int unsignedIntegerValue)
-: mImpl( NULL )
+Property::Value::Value( const Vector4& vectorValue )
+: mImpl( new Impl( vectorValue ) )
 {
-  mImpl = new Impl( unsignedIntegerValue );
 }
 
-Property::Value::Value(const Vector2& vectorValue)
-: mImpl( NULL )
+Property::Value::Value( const Matrix3& matrixValue )
+: mImpl( new Impl( matrixValue ) )
 {
-  mImpl = new Impl( vectorValue );
 }
 
-Property::Value::Value(const Vector3& vectorValue)
-: mImpl( NULL )
+Property::Value::Value( const Matrix& matrixValue )
+: mImpl( new Impl( matrixValue ) )
 {
-  mImpl = new Impl( vectorValue );
 }
 
-Property::Value::Value(const Vector4& vectorValue)
-: mImpl( NULL )
+Property::Value::Value( const Rect<int32_t>& rectValue )
+: mImpl( new Impl( rectValue ) )
 {
-  mImpl = new Impl( vectorValue );
 }
 
-Property::Value::Value(const Matrix3& matrixValue)
-: mImpl( NULL )
+Property::Value::Value( const Rect<float>& rectValue )
+: mImpl( new Impl( rectValue ) )
 {
-  mImpl = new Impl( matrixValue );
 }
 
-Property::Value::Value(const Matrix& matrixValue)
-: mImpl( NULL )
+Property::Value::Value( const AngleAxis& angleAxisValue )
+: mImpl( new Impl( angleAxisValue ) )
 {
-  mImpl = new Impl( matrixValue );
 }
 
-Property::Value::Value(const Rect<int>& rect)
-: mImpl( NULL )
+Property::Value::Value( const Quaternion& quaternionValue )
+: mImpl( new Impl( quaternionValue ) )
 {
-  mImpl = new Impl( rect );
 }
 
-Property::Value::Value(const AngleAxis& angleAxisValue)
-: mImpl( NULL )
+Property::Value::Value( const std::string& stringValue )
+: mImpl( new Impl( stringValue ) )
 {
-  mImpl = new Impl( angleAxisValue );
 }
 
-Property::Value::Value(const Quaternion& quaternionValue)
+Property::Value::Value( const char* stringValue )
+: mImpl( nullptr )
 {
-  mImpl = new Impl( quaternionValue );
+  if( stringValue ) // string constructor is undefined with nullptr
+  {
+    mImpl = new Impl( std::string(stringValue) );
+  }
+  else
+  {
+    mImpl = new Impl( std::string() );
+  }
 }
 
-Property::Value::Value(const std::string& stringValue)
+Property::Value::Value( Property::Array& arrayValue )
+: mImpl( new Impl( arrayValue ) )
 {
-  mImpl = new Impl( stringValue );
 }
 
-Property::Value::Value(const char *stringValue)
+Property::Value::Value( Property::Array&& arrayValue )
+: mImpl( new Impl( std::move( arrayValue ) ) )
 {
-  mImpl = new Impl( std::string(stringValue) );
 }
 
-Property::Value::Value(Property::Array &arrayValue)
+Property::Value::Value( Property::Map& mapValue )
+: mImpl( new Impl( mapValue ) )
 {
-  mImpl = new Impl( arrayValue );
 }
 
-Property::Value::Value(Property::Map &mapValue)
+Property::Value::Value( Property::Map&& mapValue )
+: mImpl( new Impl( std::move( mapValue ) ) )
 {
-  mImpl = new Impl( mapValue );
 }
 
+Property::Value::Value( const Extents& extentsValue )
+: mImpl( new Impl( extentsValue ) )
+{
+}
 
-Property::Value::~Value()
+Property::Value::Value( const std::initializer_list< KeyValuePair >& values )
+: mImpl( new Impl( values ) )
 {
-  delete mImpl;
 }
 
-Property::Value::Value(const Value& value)
+Property::Value::Value( Type type )
+: mImpl( nullptr )
 {
-  switch (value.GetType())
+  switch (type)
   {
     case Property::BOOLEAN:
     {
-      mImpl = new Impl( value.Get<bool>() );
+      mImpl = new Impl( false );
       break;
     }
-
     case Property::FLOAT:
     {
-      mImpl = new Impl( value.Get<float>() );
+      mImpl = new Impl( 0.f );
       break;
     }
-
     case Property::INTEGER:
     {
-      mImpl = new Impl( value.Get<int>() );
-      break;
-    }
-
-    case Property::UNSIGNED_INTEGER:
-    {
-      mImpl = new Impl( value.Get<unsigned int>() );
+      mImpl = new Impl( 0 );
       break;
     }
-
     case Property::VECTOR2:
     {
-      mImpl = new Impl( value.Get<Vector2>() );
+      mImpl = new Impl( Vector2::ZERO );
       break;
     }
-
     case Property::VECTOR3:
     {
-      mImpl = new Impl( value.Get<Vector3>() );
+      mImpl = new Impl( Vector3::ZERO );
       break;
     }
-
     case Property::VECTOR4:
     {
-      mImpl = new Impl( value.Get<Vector4>() );
+      mImpl = new Impl( Vector4::ZERO );
       break;
     }
-
     case Property::RECTANGLE:
     {
-      mImpl = new Impl( value.Get<Rect<int> >() );
+      mImpl = new Impl( Rect<int32_t>(0,0,0,0) );
       break;
     }
-
     case Property::ROTATION:
     {
-      mImpl = new Impl( value.Get<Quaternion>() );
+      mImpl = new Impl( AngleAxis() );
       break;
     }
-
-    case Property::MATRIX3:
+    case Property::STRING:
     {
-      mImpl = new Impl( value.Get<Matrix3>());
+      mImpl = new Impl( std::string() );
       break;
     }
-
     case Property::MATRIX:
     {
-      mImpl = new Impl( value.Get<Matrix>());
+      mImpl = new Impl( Matrix() );
       break;
     }
-
-    case Property::STRING:
+    case Property::MATRIX3:
     {
-      mImpl = new Impl( value.Get<std::string>() );
+      mImpl = new Impl( Matrix3() );
+      break;
+    }
+    case Property::ARRAY:
+    {
+      mImpl = new Impl( Property::Array() );
       break;
     }
-
     case Property::MAP:
     {
-      mImpl = new Impl( value.Get<Property::Map>() );
+      mImpl = new Impl( Property::Map() );
       break;
     }
-
-    case Property::ARRAY:
+    case Property::EXTENTS:
     {
-      mImpl = new Impl( value.Get<Property::Array>() );
+      mImpl = new Impl( Extents() );
       break;
     }
-
-    case Property::NONE: // fall
-    default:
+    case Property::NONE:
     {
-      mImpl = new Impl();
+      // No need to create an Impl
       break;
     }
   }
 }
 
-Property::Value::Value(Type type)
+Property::Value::Value( const Property::Value& value )
+: mImpl( nullptr )
 {
-  switch (type)
+  // reuse assignment operator
+  operator=( value );
+}
+
+Property::Value::Value( Property::Value&& value )
+: mImpl( value.mImpl )
+{
+  value.mImpl = nullptr;
+}
+
+Property::Value& Property::Value::operator=( const Property::Value& value )
+{
+  if ( this == &value )
   {
-    case Property::BOOLEAN:
+    // skip self assignment
+    return *this;
+  }
+  // if we are assigned an empty value, just drop impl
+  if( !value.mImpl )
+  {
+    delete mImpl;
+    mImpl = nullptr;
+    return *this;
+  }
+  // first check if the type is the same, no need to change impl, just assign
+  if( mImpl && ( mImpl->type == value.mImpl->type ) )
+  {
+    switch( mImpl->type )
     {
-      mImpl = new Impl( false );
-      break;
+      case Property::BOOLEAN:
+      {
+        mImpl->integerValue = value.mImpl->integerValue;
+        break;
+      }
+      case Property::FLOAT:
+      {
+        mImpl->floatValue = value.mImpl->floatValue;
+        break;
+      }
+      case Property::INTEGER:
+      {
+        mImpl->integerValue = value.mImpl->integerValue;
+        break;
+      }
+      case Property::VECTOR2:
+      {
+        *mImpl->vector2Value = *value.mImpl->vector2Value; // type cannot change in mImpl so vector is allocated
+        break;
+      }
+      case Property::VECTOR3:
+      {
+        *mImpl->vector3Value = *value.mImpl->vector3Value; // type cannot change in mImpl so vector is allocated
+        break;
+      }
+      case Property::VECTOR4:
+      {
+        *mImpl->vector4Value = *value.mImpl->vector4Value; // type cannot change in mImpl so vector is allocated
+        break;
+      }
+      case Property::RECTANGLE:
+      {
+        *mImpl->rectValue = *value.mImpl->rectValue; // type cannot change in mImpl so rect is allocated
+        break;
+      }
+      case Property::ROTATION:
+      {
+        *mImpl->angleAxisValue = *value.mImpl->angleAxisValue; // type cannot change in mImpl so quaternion is allocated
+        break;
+      }
+      case Property::STRING:
+      {
+        *mImpl->stringValue = *value.mImpl->stringValue; // type cannot change in mImpl so string is allocated
+        break;
+      }
+      case Property::MATRIX:
+      {
+        *mImpl->matrixValue = *value.mImpl->matrixValue; // type cannot change in mImpl so matrix is allocated
+        break;
+      }
+      case Property::MATRIX3:
+      {
+        *mImpl->matrix3Value = *value.mImpl->matrix3Value; // type cannot change in mImpl so matrix is allocated
+        break;
+      }
+      case Property::ARRAY:
+      {
+        *mImpl->arrayValue = *value.mImpl->arrayValue; // type cannot change in mImpl so array is allocated
+        break;
+      }
+      case Property::MAP:
+      {
+        *mImpl->mapValue = *value.mImpl->mapValue; // type cannot change in mImpl so map is allocated
+        break;
+      }
+      case Property::EXTENTS:
+      {
+        *mImpl->extentsValue = *value.mImpl->extentsValue; // type cannot change in mImpl so extents is allocated
+        break;
+      }
+      case Property::NONE:
+      { // mImpl will be a nullptr, there's no way to get to this case
+      }
     }
-
-    case Property::FLOAT:
+  }
+  else
+  {
+    // different type, release old impl and create new
+    Impl* newImpl( nullptr );
+    switch ( value.mImpl->type )
     {
-      mImpl = new Impl( 0.f );
-      break;
+      case Property::BOOLEAN:
+      {
+        newImpl = new Impl( bool( value.mImpl->integerValue ) );
+        break;
+      }
+      case Property::FLOAT:
+      {
+        newImpl = new Impl( value.mImpl->floatValue );
+        break;
+      }
+      case Property::INTEGER:
+      {
+        newImpl = new Impl( value.mImpl->integerValue );
+        break;
+      }
+      case Property::VECTOR2:
+      {
+        newImpl = new Impl( *value.mImpl->vector2Value ); // type cannot change in mImpl so vector is allocated
+        break;
+      }
+      case Property::VECTOR3:
+      {
+        newImpl = new Impl( *value.mImpl->vector3Value ); // type cannot change in mImpl so vector is allocated
+        break;
+      }
+      case Property::VECTOR4:
+      {
+        newImpl = new Impl( *value.mImpl->vector4Value ); // type cannot change in mImpl so vector is allocated
+        break;
+      }
+      case Property::RECTANGLE:
+      {
+        newImpl = new Impl( *value.mImpl->rectValue ); // type cannot change in mImpl so rect is allocated
+        break;
+      }
+      case Property::ROTATION:
+      {
+        newImpl = new Impl( *value.mImpl->angleAxisValue ); // type cannot change in mImpl so quaternion is allocated
+        break;
+      }
+      case Property::MATRIX3:
+      {
+        newImpl = new Impl( *value.mImpl->matrix3Value ); // type cannot change in mImpl so matrix is allocated
+        break;
+      }
+      case Property::MATRIX:
+      {
+        newImpl = new Impl( *value.mImpl->matrixValue ); // type cannot change in mImpl so matrix is allocated
+        break;
+      }
+      case Property::STRING:
+      {
+        newImpl = new Impl( *value.mImpl->stringValue ); // type cannot change in mImpl so string is allocated
+        break;
+      }
+      case Property::ARRAY:
+      {
+        newImpl = new Impl( *value.mImpl->arrayValue ); // type cannot change in mImpl so array is allocated
+        break;
+      }
+      case Property::MAP:
+      {
+        newImpl = new Impl( *value.mImpl->mapValue ); // type cannot change in mImpl so map is allocated
+        break;
+      }
+      case Property::EXTENTS:
+      {
+        newImpl = new Impl( *value.mImpl->extentsValue ); // type cannot change in mImpl so extents is allocated
+        break;
+      }
+      case Property::NONE:
+      { // nullptr value will be used for "empty" value
+      }
     }
+    delete mImpl;
+    mImpl = newImpl;
+  }
 
-    case Property::INTEGER:
+  return *this;
+}
+
+Property::Value& Property::Value::operator=( Property::Value&& value )
+{
+  if( this != &value )
+  {
+    delete mImpl;
+    mImpl = value.mImpl;
+    value.mImpl = nullptr;
+  }
+
+  return *this;
+}
+
+Property::Value::~Value()
+{
+  delete mImpl;
+}
+
+Property::Type Property::Value::GetType() const
+{
+  Property::Type type( Property::NONE );
+  if( mImpl )
+  {
+    type = mImpl->type;
+  }
+  return type;
+}
+
+bool Property::Value::Get( bool& booleanValue ) const
+{
+  bool converted = false;
+  if( mImpl && IsIntegerType( mImpl->type ) )
+  {
+    booleanValue = mImpl->integerValue;
+    converted = true;
+  }
+  return converted;
+}
+
+bool Property::Value::Get( float& floatValue ) const
+{
+  bool converted = false;
+  if( mImpl )
+  {
+    if( mImpl->type == FLOAT )
     {
-      mImpl = new Impl( 0 );
-      break;
+      floatValue = mImpl->floatValue;
+      converted = true;
     }
-
-    case Property::UNSIGNED_INTEGER:
+    else if( IsIntegerType( mImpl->type ) )
     {
-      mImpl = new Impl( 0U );
-      break;
+      floatValue = static_cast< float >( mImpl->integerValue );
+      converted = true;
     }
+  }
+  return converted;
+}
 
-    case Property::VECTOR2:
+bool Property::Value::Get( int32_t& integerValue ) const
+{
+  bool converted = false;
+  if( mImpl )
+  {
+    if( IsIntegerType( mImpl->type ) )
     {
-      mImpl = new Impl( Vector2::ZERO );
-      break;
+      integerValue = mImpl->integerValue;
+      converted = true;
     }
-
-    case Property::VECTOR3:
+    else if( mImpl->type == FLOAT )
     {
-      mImpl = new Impl( Vector3::ZERO );
-      break;
+      integerValue = static_cast< int32_t >( mImpl->floatValue );
+      converted = true;
     }
+  }
+  return converted;
+}
 
-    case Property::VECTOR4:
+bool Property::Value::Get( Vector2& vectorValue ) const
+{
+  bool converted = false;
+  if( mImpl )
+  {
+    // type cannot change in mImpl so vector is allocated
+    if( mImpl->type == VECTOR2 || mImpl->type == VECTOR3 || mImpl->type == VECTOR4 )
     {
-      mImpl = new Impl( Vector4::ZERO );
-      break;
+      vectorValue = *(mImpl->vector2Value); // if Vector3 or 4 only x and y are assigned
+      converted = true;
     }
+  }
+  return converted;
+}
 
-    case Property::RECTANGLE:
+bool Property::Value::Get( Vector3& vectorValue ) const
+{
+  bool converted = false;
+  if( mImpl )
+  {
+    // type cannot change in mImpl so vector is allocated
+    if ( mImpl->type == VECTOR3 || mImpl->type == VECTOR4 )
     {
-      mImpl = new Impl( Rect<int>(0,0,0,0) );
-      break;
+      vectorValue = *(mImpl->vector3Value); // if Vector4 only x,y,z are assigned
+      converted = true;
     }
-
-    case Property::ROTATION:
+    else if( mImpl->type == VECTOR2 )
     {
-      mImpl = new Impl( Quaternion(0.f, Vector4::YAXIS) );
-      break;
+      vectorValue = *(mImpl->vector2Value);
+      converted = true;
     }
+  }
+  return converted;
+}
 
-    case Property::STRING:
+bool Property::Value::Get( Vector4& vectorValue ) const
+{
+  bool converted = false;
+  if( mImpl )
+  {
+    if( mImpl->type == VECTOR4 ) // type cannot change in mImpl so vector is allocated
     {
-      mImpl = new Impl( std::string() );
-      break;
+      vectorValue = *(mImpl->vector4Value);
+      converted = true;
     }
-
-    case Property::MAP:
+    else if( mImpl->type == VECTOR2 )
     {
-      mImpl = new Impl( Property::Map() );
-      break;
+      vectorValue = *(mImpl->vector2Value);
+      converted = true;
     }
-
-    case Property::MATRIX:
+    else if( mImpl->type == VECTOR3 )
     {
-      mImpl = new Impl( Matrix() );
-      break;
-    }
-
-    case Property::MATRIX3:
-    {
-      mImpl = new Impl( Matrix3() );
-      break;
-    }
-
-    case Property::ARRAY:
-    {
-      mImpl = new Impl( Property::Array() );
-      break;
-    }
-
-    case Property::NONE: // fall
-    default:
-    {
-      mImpl = new Impl();
-      break;
+      vectorValue = *(mImpl->vector3Value);
+      converted = true;
     }
   }
+  return converted;
 }
 
-Property::Value& Property::Value::operator=(const Property::Value& value)
+bool Property::Value::Get( Matrix3& matrixValue ) const
 {
-  if (this == &value)
+  bool converted = false;
+  if( mImpl && (mImpl->type == MATRIX3) ) // type cannot change in mImpl so matrix is allocated
   {
-    // skip self assignment
-    return *this;
+    matrixValue = *(mImpl->matrix3Value);
+    converted = true;
   }
-
-  mImpl->mType = value.GetType();
-
-  switch (mImpl->mType)
-  {
-    case Property::BOOLEAN:
-    {
-      mImpl->mValue = value.Get<bool>();
-      break;
-    }
-
-    case Property::FLOAT:
-    {
-      mImpl->mValue = value.Get<float>();
-      break;
-    }
-
-    case Property::INTEGER:
-    {
-      mImpl->mValue = value.Get<int>();
-      break;
-    }
-
-    case Property::UNSIGNED_INTEGER:
-    {
-      mImpl->mValue = value.Get<unsigned int>();
-      break;
-    }
-
-    case Property::VECTOR2:
-    {
-      mImpl->mValue = value.Get<Vector2>();
-      break;
-    }
-
-    case Property::VECTOR3:
-    {
-      mImpl->mValue = value.Get<Vector3>();
-      break;
-    }
-
-    case Property::VECTOR4:
-    {
-      mImpl->mValue = value.Get<Vector4>();
-      break;
-    }
-
-    case Property::RECTANGLE:
-    {
-      mImpl->mValue = value.Get<Rect<int> >();
-      break;
-    }
-
-    case Property::ROTATION:
-    {
-      mImpl->mValue = value.Get<Quaternion>();
-      break;
-    }
-
-    case Property::STRING:
-    {
-      mImpl->mValue = value.Get<std::string>();
-      break;
-    }
-
-    case Property::MATRIX:
-    {
-      mImpl->mValue = value.Get<Matrix>();
-      break;
-    }
-
-    case Property::MATRIX3:
-    {
-      mImpl->mValue = value.Get<Matrix3>();
-      break;
-    }
-
-    case Property::MAP:
-    {
-      mImpl->mValue = value.Get<Property::Map>();
-      break;
-    }
-
-    case Property::ARRAY:
-    {
-      mImpl->mValue = value.Get<Property::Array>();
-      break;
-    }
-
-    case Property::NONE: // fall
-    default:
-    {
-      mImpl->mValue = Impl::AnyValue(0);
-      break;
-    }
-  }
-
-  return *this;
-}
-
-Property::Type Property::Value::GetType() const
-{
-  return mImpl->mType;
-}
-
-void Property::Value::Get(bool& boolValue) const
-{
-  DALI_ASSERT_DEBUG( Property::BOOLEAN == GetType() && "Property type invalid" );  // AnyCast does asserted type checking
-
-  boolValue = AnyCast<bool>(mImpl->mValue);
-}
-
-void Property::Value::Get(float& floatValue) const
-{
-  DALI_ASSERT_DEBUG( Property::FLOAT == GetType() && "Property type invalid" );
-
-  floatValue = AnyCast<float>(mImpl->mValue);
-}
-
-void Property::Value::Get(int& integerValue) const
-{
-  DALI_ASSERT_DEBUG( Property::INTEGER == GetType() && "Property type invalid" );
-
-  integerValue = AnyCast<int>(mImpl->mValue);
-}
-
-void Property::Value::Get(unsigned int& unsignedIntegerValue) const
-{
-  DALI_ASSERT_DEBUG( Property::UNSIGNED_INTEGER == GetType() && "Property type invalid" );
-
-  unsignedIntegerValue = AnyCast<unsigned int>(mImpl->mValue);
-}
-
-void Property::Value::Get(Vector2& vectorValue) const
-{
-  DALI_ASSERT_DEBUG( Property::VECTOR2 == GetType() && "Property type invalid" );
-
-  vectorValue = AnyCast<Vector2>(mImpl->mValue);
-}
-
-void Property::Value::Get(Vector3& vectorValue) const
-{
-  DALI_ASSERT_DEBUG( Property::VECTOR3 == GetType() && "Property type invalid" );
-
-  vectorValue = AnyCast<Vector3>(mImpl->mValue);
-}
-
-void Property::Value::Get(Vector4& vectorValue) const
-{
-  DALI_ASSERT_DEBUG( Property::VECTOR4 == GetType() && "Property type invalid" );
-
-  vectorValue = AnyCast<Vector4>(mImpl->mValue);
+  return converted;
 }
 
-void Property::Value::Get(Matrix3& matrixValue) const
+bool Property::Value::Get( Matrix& matrixValue ) const
 {
-  DALI_ASSERT_DEBUG( Property::MATRIX3 == GetType() && "Property type invalid" );
-  matrixValue = AnyCast<Matrix3>(mImpl->mValue);
-}
-
-void Property::Value::Get(Matrix& matrixValue) const
-{
-  DALI_ASSERT_DEBUG( Property::MATRIX == GetType() && "Property type invalid" );
-  matrixValue = AnyCast<Matrix>(mImpl->mValue);
+  bool converted = false;
+  if( mImpl && (mImpl->type == MATRIX) ) // type cannot change in mImpl so matrix is allocated
+  {
+    matrixValue = *(mImpl->matrixValue);
+    converted = true;
+  }
+  return converted;
 }
 
-void Property::Value::Get(Rect<int>& rect) const
+bool Property::Value::Get( Rect<int32_t>& rectValue ) const
 {
-  DALI_ASSERT_DEBUG( Property::RECTANGLE == GetType() && "Property type invalid" );
-
-  rect = AnyCast<Rect<int> >(mImpl->mValue);
+  bool converted = false;
+  if( mImpl && (mImpl->type == RECTANGLE) ) // type cannot change in mImpl so rect is allocated
+  {
+    rectValue = *(mImpl->rectValue);
+    converted = true;
+  }
+  return converted;
 }
 
-void Property::Value::Get(AngleAxis& angleAxisValue) const
+bool Property::Value::Get( AngleAxis& angleAxisValue ) const
 {
-  DALI_ASSERT_ALWAYS( Property::ROTATION == GetType() && "Property type invalid" );
-
-  // Rotations have two representations
-  DALI_ASSERT_DEBUG( typeid(Quaternion) == mImpl->mValue.GetType() ||
-                     typeid(AngleAxis)  == mImpl->mValue.GetType() );
-
-  if ( typeid(Quaternion) == mImpl->mValue.GetType() )
-  {
-    Quaternion quaternion = AnyCast<Quaternion>(mImpl->mValue);
-
-    Radian angleRadians(0.0f);
-    quaternion.ToAxisAngle( angleAxisValue.axis, angleRadians );
-    angleAxisValue.angle = angleRadians;
-  }
-  else
+  bool converted = false;
+  if( mImpl && (mImpl->type == ROTATION) ) // type cannot change in mImpl so angleAxis is allocated
   {
-    angleAxisValue = AnyCast<AngleAxis>(mImpl->mValue);
+    angleAxisValue = *(mImpl->angleAxisValue);
+    converted = true;
   }
+  return converted;
 }
 
-void Property::Value::Get(Quaternion& quaternionValue) const
+bool Property::Value::Get( Quaternion& quaternionValue ) const
 {
-  DALI_ASSERT_DEBUG( Property::ROTATION == GetType() && "Property type invalid" );
-
-  // Rotations have two representations
-  DALI_ASSERT_DEBUG( typeid(Quaternion) == mImpl->mValue.GetType() ||
-               typeid(AngleAxis)  == mImpl->mValue.GetType() );
-
-  if ( typeid(Quaternion) == mImpl->mValue.GetType() )
-  {
-    quaternionValue = AnyCast<Quaternion>(mImpl->mValue);
-  }
-  else
+  bool converted = false;
+  if( mImpl && (mImpl->type == ROTATION) ) // type cannot change in mImpl so angleAxis is allocated
   {
-    AngleAxis angleAxis = AnyCast<AngleAxis>(mImpl->mValue);
-
-    quaternionValue = Quaternion( Radian(angleAxis.angle), angleAxis.axis );
+    quaternionValue = Quaternion(mImpl->angleAxisValue->angle, mImpl->angleAxisValue->axis );
+    converted = true;
   }
+  return converted;
 }
 
-void Property::Value::Get(std::string &out) const
+bool Property::Value::Get( std::string& stringValue ) const
 {
-  DALI_ASSERT_DEBUG(Property::STRING == GetType() && "Property type invalid");
-
-  out = AnyCast<std::string>(mImpl->mValue);
+  bool converted = false;
+  if( mImpl && (mImpl->type == STRING) ) // type cannot change in mImpl so string is allocated
+  {
+    stringValue.assign( *(mImpl->stringValue) );
+    converted = true;
+  }
+  return converted;
 }
 
-void Property::Value::Get(Property::Array &out) const
+bool Property::Value::Get( Property::Array& arrayValue ) const
 {
-  DALI_ASSERT_DEBUG(Property::ARRAY == GetType() && "Property type invalid");
-
-  out = AnyCast<Property::Array>(mImpl->mValue);
+  bool converted = false;
+  if( mImpl && (mImpl->type == ARRAY) ) // type cannot change in mImpl so array is allocated
+  {
+    arrayValue = *(mImpl->arrayValue);
+    converted = true;
+  }
+  return converted;
 }
 
-void Property::Value::Get(Property::Map &out) const
+bool Property::Value::Get( Property::Map& mapValue ) const
 {
-  DALI_ASSERT_DEBUG(Property::MAP == GetType() && "Property type invalid");
-
-  out = AnyCast<Property::Map>(mImpl->mValue);
+  bool converted = false;
+  if( mImpl && (mImpl->type == MAP) ) // type cannot change in mImpl so map is allocated
+  {
+    mapValue = *(mImpl->mapValue);
+    converted = true;
+  }
+  return converted;
 }
 
-Property::Value& Property::Value::GetValue(const std::string& key) const
+Property::Array* Property::Value::GetArray() const
 {
-  DALI_ASSERT_DEBUG(Property::MAP == GetType() && "Property type invalid");
-
-  Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-
-  DALI_ASSERT_DEBUG(container);
-
-  if(container)
+  Property::Array* array = nullptr;
+  if( mImpl && (mImpl->type == ARRAY) ) // type cannot change in mImpl so array is allocated
   {
-    for(Property::Map::iterator iter = container->begin(); iter != container->end(); ++iter)
-    {
-      if(iter->first == key)
-      {
-        return iter->second;
-      }
-    }
+    array = mImpl->arrayValue;
   }
-
-  DALI_LOG_WARNING("Cannot find property map key %s", key.c_str());
-  DALI_ASSERT_ALWAYS(!"Cannot find property map key");
-
-  // should never return this
-  static Property::Value null;
-  return null;
+  return array;
 }
 
-bool Property::Value::HasKey(const std::string& key) const
+Property::Map* Property::Value::GetMap() const
 {
-  bool has = false;
-
-  if( Property::MAP == GetType() )
+  Property::Map* map = nullptr;
+  if( mImpl && (mImpl->type == MAP) ) // type cannot change in mImpl so map is allocated
   {
-    Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-
-    DALI_ASSERT_DEBUG(container && "Property::Map has no container?");
-
-    if(container)
-    {
-      for(Property::Map::iterator iter = container->begin(); iter != container->end(); ++iter)
-      {
-        if(iter->first == key)
-        {
-          has = true;
-        }
-      }
-    }
+    map = mImpl->mapValue;
   }
-
-  return has;
+  return map;
 }
 
-
-const std::string& Property::Value::GetKey(const int index) const
+bool Property::Value::Get( Extents& extentsValue ) const
 {
-  switch( GetType() )
+  bool converted = false;
+  if( mImpl )
   {
-    case Property::MAP:
+    if( mImpl->type == EXTENTS )
     {
-      int i = 0;
-      Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-      DALI_ASSERT_DEBUG(container && "Property::Map has no container?");
-      if(container)
-      {
-        if(0 <= index && index < static_cast<int>(container->size()))
-        {
-          for(Property::Map::iterator iter = container->begin(); iter != container->end(); ++iter)
-          {
-            if(i++ == index)
-            {
-              return iter->first;
-            }
-          }
-        }
-      }
+      extentsValue = *(mImpl->extentsValue);
+      converted = true;
     }
-    break;
-    case Property::NONE:
-    case Property::ARRAY:
-    case Property::BOOLEAN:
-    case Property::FLOAT:
-    case Property::UNSIGNED_INTEGER:
-    case Property::INTEGER:
-    case Property::VECTOR2:
-    case Property::VECTOR3:
-    case Property::VECTOR4:
-    case Property::MATRIX:
-    case Property::MATRIX3:
-    case Property::RECTANGLE:
-    case Property::ROTATION:
-    case Property::STRING:
-    case Property::TYPE_COUNT:
+    else if( mImpl->type == VECTOR4 )
     {
-      break;
+      extentsValue.start = static_cast< uint16_t >( mImpl->vector4Value->x );
+      extentsValue.end = static_cast< uint16_t >( mImpl->vector4Value->y );
+      extentsValue.top = static_cast< uint16_t >( mImpl->vector4Value->z );
+      extentsValue.bottom = static_cast< uint16_t >( mImpl->vector4Value->w );
+      converted = true;
     }
   }
-
-
-  // should never return this
-  static std::string null;
-  return null;
+  return converted;
 }
 
-
-void Property::Value::SetValue(const std::string& key, const Property::Value &value)
+std::ostream& operator<<( std::ostream& stream, const Property::Value& value )
 {
-  DALI_ASSERT_DEBUG(Property::MAP == GetType() && "Property type invalid");
-
-  Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-
-  if(container)
+  if( value.mImpl )
   {
-    for(Property::Map::iterator iter = container->begin(); iter != container->end(); ++iter)
+    const Property::Value::Impl& impl( *value.mImpl );
+
+    switch( impl.type )
     {
-      if(iter->first == key)
+      case Dali::Property::BOOLEAN:
       {
-        iter->second = value;
-        return;
+        stream << impl.integerValue;
+        break;
       }
-    }
-
-    // if we get here its a new key
-    container->push_back(Property::StringValuePair(key, value));
-
-  }
-}
-
-Property::Value& Property::Value::GetItem(const int index) const
-{
-  switch( GetType() )
-  {
-    case Property::MAP:
-    {
-      int i = 0;
-      Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-
-      DALI_ASSERT_DEBUG(container && "Property::Map has no container?");
-      if(container)
+      case Dali::Property::FLOAT:
       {
-        DALI_ASSERT_ALWAYS(index < static_cast<int>(container->size()) && "Property array index invalid");
-        DALI_ASSERT_ALWAYS(index >= 0 && "Property array index invalid");
-
-        for(Property::Map::iterator iter = container->begin(); iter != container->end(); ++iter)
-        {
-          if(i++ == index)
-          {
-            return iter->second;
-          }
-        }
+        stream << impl.floatValue;
+        break;
       }
-    }
-    break;
-
-    case Property::ARRAY:
-    {
-      int i = 0;
-      Property::Array *container = AnyCast<Property::Array>(&(mImpl->mValue));
-
-      DALI_ASSERT_DEBUG(container && "Property::Map has no container?");
-      if(container)
+      case Dali::Property::INTEGER:
       {
-        DALI_ASSERT_ALWAYS(index < static_cast<int>(container->size()) && "Property array index invalid");
-        DALI_ASSERT_ALWAYS(index >= 0 && "Property array index invalid");
-
-        for(Property::Array::iterator iter = container->begin(); iter != container->end(); ++iter)
-        {
-          if(i++ == index)
-          {
-            return *iter;
-          }
-        }
+         stream << impl.integerValue;
+         break;
       }
-    }
-    break;
-
-    case Property::NONE:
-    case Property::BOOLEAN:
-    case Property::FLOAT:
-    case Property::INTEGER:
-    case Property::UNSIGNED_INTEGER:
-    case Property::VECTOR2:
-    case Property::VECTOR3:
-    case Property::VECTOR4:
-    case Property::MATRIX3:
-    case Property::MATRIX:
-    case Property::RECTANGLE:
-    case Property::ROTATION:
-    case Property::STRING:
-    case Property::TYPE_COUNT:
-    {
-      DALI_ASSERT_ALWAYS(!"Cannot GetItem on property Type; not a container");
-      break;
-    }
-
-  } // switch GetType()
-
-
-  DALI_ASSERT_ALWAYS(!"Property value index not valid");
-
-  // should never return this
-  static Property::Value null;
-  return null;
-}
-
-void Property::Value::SetItem(const int index, const Property::Value &value)
-{
-  switch( GetType() )
-  {
-    case Property::MAP:
-    {
-      Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-      if( container && index < static_cast<int>(container->size()) )
-      {
-        int i = 0;
-        for(Property::Map::iterator iter = container->begin(); iter != container->end(); ++iter)
-        {
-          if(i++ == index)
-          {
-            iter->second = value;
-            break;
-          }
-        }
+      case Dali::Property::VECTOR2:
+      {
+        stream << *impl.vector2Value;
+        break;
       }
-    }
-    break;
-
-    case Property::ARRAY:
-    {
-      Property::Array *container = AnyCast<Property::Array>(&(mImpl->mValue));
-      if( container && index < static_cast<int>(container->size()) )
+      case Dali::Property::VECTOR3:
       {
-        (*container)[index] = value;
+        stream << *impl.vector3Value;
+        break;
       }
-    }
-    break;
-
-    case Property::NONE:
-    case Property::BOOLEAN:
-    case Property::FLOAT:
-    case Property::INTEGER:
-    case Property::UNSIGNED_INTEGER:
-    case Property::VECTOR2:
-    case Property::VECTOR3:
-    case Property::VECTOR4:
-    case Property::MATRIX3:
-    case Property::MATRIX:
-    case Property::RECTANGLE:
-    case Property::ROTATION:
-    case Property::STRING:
-    case Property::TYPE_COUNT:
-    {
-      DALI_ASSERT_ALWAYS(!"Cannot SetItem on property Type; not a container");
-      break;
-    }
-  }
-}
-
-int Property::Value::AppendItem(const Property::Value &value)
-{
-  DALI_ASSERT_DEBUG(Property::ARRAY == GetType() && "Property type invalid");
-
-  Property::Array *container = AnyCast<Property::Array>(&(mImpl->mValue));
-
-  if(container)
-  {
-    container->push_back(value);
-    return container->size() - 1;
-  }
-  else
-  {
-    return -1;
-  }
-
-}
-
-int Property::Value::GetSize() const
-{
-  int ret = 0;
-
-  switch(GetType())
-  {
-    case Property::MAP:
-    {
-      Property::Map *container = AnyCast<Property::Map>(&(mImpl->mValue));
-      if(container)
+      case Dali::Property::VECTOR4:
       {
-        ret = container->size();
+        stream << *impl.vector4Value;
+        break;
       }
-    }
-    break;
-
-    case Property::ARRAY:
-    {
-      Property::Array *container = AnyCast<Property::Array>(&(mImpl->mValue));
-      if(container)
+      case Dali::Property::MATRIX3:
       {
-        ret = container->size();
+        stream << *impl.matrix3Value;
+        break;
+      }
+      case Dali::Property::MATRIX:
+      {
+        stream << *impl.matrixValue;
+        break;
+      }
+      case Dali::Property::RECTANGLE:
+      {
+        stream << *impl.rectValue;
+        break;
+      }
+      case Dali::Property::ROTATION:
+      {
+        stream << *impl.angleAxisValue;
+        break;
+      }
+      case Dali::Property::STRING:
+      {
+        stream << *impl.stringValue;
+        break;
+      }
+      case Dali::Property::ARRAY:
+      {
+        stream << *(value.GetArray());
+        break;
+      }
+      case Dali::Property::MAP:
+      {
+        stream << *(value.GetMap());
+        break;
+      }
+      case Dali::Property::EXTENTS:
+      {
+        stream << *impl.extentsValue;
+        break;
+      }
+      case Dali::Property::NONE:
+      { // mImpl will be a nullptr, there's no way to get to this case
       }
     }
-    break;
-
-    case Property::NONE:
-    case Property::BOOLEAN:
-    case Property::FLOAT:
-    case Property::INTEGER:
-    case Property::UNSIGNED_INTEGER:
-    case Property::VECTOR2:
-    case Property::VECTOR3:
-    case Property::VECTOR4:
-    case Property::MATRIX3:
-    case Property::MATRIX:
-    case Property::RECTANGLE:
-    case Property::ROTATION:
-    case Property::STRING:
-    case Property::TYPE_COUNT:
-    {
-      break;
-    }
-
   }
-
-  return ret;
+  else
+  {
+    stream << "undefined type";
+  }
+  return stream;
 }