Add move semantics to Array, Map & Value 51/203751/11
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 17 Apr 2019 15:30:55 +0000 (16:30 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 24 Apr 2019 16:27:56 +0000 (17:27 +0100)
Change-Id: If1a9cc26637a2bd5a3cc1fa8c5c76f6c744727e1

automated-tests/src/dali/utc-Dali-PropertyArray.cpp
automated-tests/src/dali/utc-Dali-PropertyMap.cpp
automated-tests/src/dali/utc-Dali-PropertyValue.cpp
dali/public-api/object/property-array.cpp
dali/public-api/object/property-array.h
dali/public-api/object/property-map.cpp
dali/public-api/object/property-map.h
dali/public-api/object/property-value.cpp
dali/public-api/object/property-value.h

index 4f3cd74..b4e5577 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -278,3 +278,100 @@ int UtcDaliPropertyArrayOstream02(void)
 
   END_TEST;
 }
+
+int UtcDaliPropertyArrayCopyConstructor(void)
+{
+  Property::Array array1;
+  array1.PushBack( 0 );
+  array1.PushBack( 1 );
+  array1.PushBack( 2 );
+  DALI_TEST_EQUALS( 3u, array1.Size(), TEST_LOCATION );
+
+  Property::Array array2( array1 );
+  DALI_TEST_EQUALS( 3u, array1.Size(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 3u, array2.Size(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyArrayAssignmentOperator(void)
+{
+  Property::Array array1;
+  array1.PushBack( 0 );
+  array1.PushBack( 1 );
+  array1.PushBack( 2 );
+  DALI_TEST_EQUALS( 3u, array1.Size(), TEST_LOCATION );
+
+  Property::Array array2;
+  array2.PushBack( 4 );
+  DALI_TEST_EQUALS( 1u, array2.Size(), TEST_LOCATION );
+
+  array2 = array1;
+  DALI_TEST_EQUALS( 3u, array1.Size(), TEST_LOCATION );
+  DALI_TEST_EQUALS( 3u, array2.Size(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyArrayMoveConstructor(void)
+{
+  Property::Array array1;
+  array1.PushBack( 0 );
+  array1.PushBack( 1 );
+  array1.PushBack( 2 );
+  DALI_TEST_EQUALS( 3u, array1.Size(), TEST_LOCATION );
+
+  Property::Array array2( std::move( array1 ) );
+  DALI_TEST_EQUALS( 3u, array2.Size(), TEST_LOCATION );
+
+  // Calling any methods on array1 will debug assert
+  const char * exceptionMessage = "Cannot use an object previously used as an r-value";
+  DALI_TEST_ASSERTION( array1.Count(),                                      exceptionMessage );
+  DALI_TEST_ASSERTION( array1.PushBack( Property::Value() ),                exceptionMessage );
+  DALI_TEST_ASSERTION( array1.Count(),                                      exceptionMessage );
+  DALI_TEST_ASSERTION( array1.Clear(),                                      exceptionMessage );
+  DALI_TEST_ASSERTION( array1.Reserve( 1 ),                                 exceptionMessage );
+  DALI_TEST_ASSERTION( array1.Resize( 1 ),                                  exceptionMessage );
+  DALI_TEST_ASSERTION( array1.Capacity(),                                   exceptionMessage );
+  DALI_TEST_ASSERTION( array1[ 0 ],                                         exceptionMessage );
+  DALI_TEST_ASSERTION( const_cast< const Property::Array& >( array1 )[ 0 ], exceptionMessage );
+  DALI_TEST_ASSERTION( Property::Array temp; array1 = temp,                 exceptionMessage );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyArrayMoveAssignmentOperator(void)
+{
+  Property::Array array1;
+  array1.PushBack( 0 );
+  array1.PushBack( 1 );
+  array1.PushBack( 2 );
+  DALI_TEST_EQUALS( 3u, array1.Size(), TEST_LOCATION );
+
+  Property::Array array2;
+  array2.PushBack( 4 );
+  DALI_TEST_EQUALS( 1u, array2.Size(), TEST_LOCATION );
+
+  array2 = std::move( array1 );
+  DALI_TEST_EQUALS( 3u, array2.Size(), TEST_LOCATION );
+
+  // Calling any methods on array1 will debug assert
+  const char * exceptionMessage = "Cannot use an object previously used as an r-value";
+  DALI_TEST_ASSERTION( array1.Count(),                                      exceptionMessage );
+  DALI_TEST_ASSERTION( array1.PushBack( Property::Value() ),                exceptionMessage );
+  DALI_TEST_ASSERTION( array1.Count(),                                      exceptionMessage );
+  DALI_TEST_ASSERTION( array1.Clear(),                                      exceptionMessage );
+  DALI_TEST_ASSERTION( array1.Reserve( 1 ),                                 exceptionMessage );
+  DALI_TEST_ASSERTION( array1.Resize( 1 ),                                  exceptionMessage );
+  DALI_TEST_ASSERTION( array1.Capacity(),                                   exceptionMessage );
+  DALI_TEST_ASSERTION( array1[ 0 ],                                         exceptionMessage );
+  DALI_TEST_ASSERTION( const_cast< const Property::Array& >( array1 )[ 0 ], exceptionMessage );
+  DALI_TEST_ASSERTION( Property::Array temp; array1 = temp,                 exceptionMessage );
+
+  // Self assignemnt
+  array2 = std::move( array2 );
+  DALI_TEST_EQUALS( 3u, array2.Size(), TEST_LOCATION ); // still works, no debug assert
+
+  END_TEST;
+}
+
index 7283e1c..46da84c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -80,6 +80,94 @@ int UtcDaliPropertyMapCopyAndAssignment(void)
   END_TEST;
 }
 
+int UtcDaliPropertyMapMoveConstructor(void)
+{
+  Property::Map map1;
+  map1[ "hello" ] = 1;
+  map1[ "world" ] = 2;
+  map1[ 10 ] = "DALi";
+  DALI_TEST_EQUALS( 3u, map1.Count(), TEST_LOCATION );
+
+  Property::Map map2( std::move( map1 ) );
+  DALI_TEST_EQUALS( 3u, map2.Count(), TEST_LOCATION );
+
+  // Calling any methods on map1 will debug assert
+  const char * exceptionMessage = "Cannot use an object previously used as an r-value";
+  DALI_TEST_ASSERTION( map1.Count(),                                            exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Empty(),                                            exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Insert( (const char *)"key", Property::Value() ),   exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Insert( std::string( "key" ), Property::Value() ),  exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Insert( 0, Property::Value() ),                     exceptionMessage );
+  DALI_TEST_ASSERTION( map1.GetValue( 0 ),                                      exceptionMessage );
+  DALI_TEST_ASSERTION( map1.GetKey( 0 ),                                        exceptionMessage );
+  DALI_TEST_ASSERTION( map1.GetKeyAt( 1 ),                                      exceptionMessage );
+  DALI_TEST_ASSERTION( map1.GetPair( 0 ),                                       exceptionMessage );
+  DALI_TEST_ASSERTION( map1.GetKeyValue( 0 ),                                   exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( (const char *)"key" ),                        exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( std::string( "key" ) ),                       exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( 0 ),                                          exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( 0, "key" ),                                   exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( "key", Property::INTEGER ),                   exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( 0, Property::INTEGER ),                       exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Clear(),                                            exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Merge( Property::Map() ),                           exceptionMessage );
+  DALI_TEST_ASSERTION( map1[ "key" ],                                           exceptionMessage );
+  DALI_TEST_ASSERTION( const_cast< const Property::Map& >( map1 )[ "key" ],     exceptionMessage );
+  DALI_TEST_ASSERTION( map1[ 0 ],                                               exceptionMessage );
+  DALI_TEST_ASSERTION( const_cast< const Property::Map& >( map1 )[ 0 ],         exceptionMessage );
+  DALI_TEST_ASSERTION( Property::Map temp; map1 = temp,                         exceptionMessage );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyMapMoveAssignmentOperator(void)
+{
+  Property::Map map1;
+  map1[ "hello" ] = 1;
+  map1[ "world" ] = 2;
+  map1[ 10 ] = "DALi";
+  DALI_TEST_EQUALS( 3u, map1.Count(), TEST_LOCATION );
+
+  Property::Map map2;
+  map2[ 10 ] = "DALi again";
+  DALI_TEST_EQUALS( 1u, map2.Count(), TEST_LOCATION );
+
+  map2 = std::move( map1 );
+  DALI_TEST_EQUALS( 3u, map2.Count(), TEST_LOCATION );
+
+  // Calling any methods on map1 will debug assert
+  const char * exceptionMessage = "Cannot use an object previously used as an r-value";
+  DALI_TEST_ASSERTION( map1.Count(),                                            exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Empty(),                                            exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Insert( (const char *)"key", Property::Value() ),   exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Insert( std::string( "key" ), Property::Value() ),  exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Insert( 0, Property::Value() ),                     exceptionMessage );
+  DALI_TEST_ASSERTION( map1.GetValue( 0 ),                                      exceptionMessage );
+  DALI_TEST_ASSERTION( map1.GetKey( 0 ),                                        exceptionMessage );
+  DALI_TEST_ASSERTION( map1.GetKeyAt( 1 ),                                      exceptionMessage );
+  DALI_TEST_ASSERTION( map1.GetPair( 0 ),                                       exceptionMessage );
+  DALI_TEST_ASSERTION( map1.GetKeyValue( 0 ),                                   exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( (const char *)"key" ),                        exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( std::string( "key" ) ),                       exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( 0 ),                                          exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( 0, "key" ),                                   exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( "key", Property::INTEGER ),                   exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Find( 0, Property::INTEGER ),                       exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Clear(),                                            exceptionMessage );
+  DALI_TEST_ASSERTION( map1.Merge( Property::Map() ),                           exceptionMessage );
+  DALI_TEST_ASSERTION( map1[ "key" ],                                           exceptionMessage );
+  DALI_TEST_ASSERTION( const_cast< const Property::Map& >( map1 )[ "key" ],     exceptionMessage );
+  DALI_TEST_ASSERTION( map1[ 0 ],                                               exceptionMessage );
+  DALI_TEST_ASSERTION( const_cast< const Property::Map& >( map1 )[ 0 ],         exceptionMessage );
+  DALI_TEST_ASSERTION( Property::Map temp; map1 = temp,                         exceptionMessage );
+
+  // Self assignment
+  map2 = std::move( map2 );
+  DALI_TEST_EQUALS( 3u, map2.Count(), TEST_LOCATION ); // No debug assert as nothing should happen
+
+  END_TEST;
+}
+
 int UtcDaliPropertyMapConstOperator(void)
 {
   Property::Map map;
index 78fbe46..3fd0fc6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -506,6 +506,61 @@ int UtcDaliPropertyValueCopyConstructorMapP(void)
   END_TEST;
 }
 
+int UtcDaliPropertyValueMoveConstructor(void)
+{
+  Property::Value value1( Vector4::ONE );
+  DALI_TEST_EQUALS( Property::VECTOR4, value1.GetType(), TEST_LOCATION );
+
+  Vector4 valueVector;
+  DALI_TEST_EQUALS( true, value1.Get( valueVector ), TEST_LOCATION ); // Able to convert
+  DALI_TEST_EQUALS( valueVector, Vector4::ONE, TEST_LOCATION );
+
+  Property::Value value2( std::move( value1 ) );
+  DALI_TEST_EQUALS( Property::NONE, value1.GetType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, value1.Get( valueVector ), TEST_LOCATION ); // Unable to convert, but no crash either
+  DALI_TEST_EQUALS( Property::VECTOR4, value2.GetType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, value2.Get( valueVector ), TEST_LOCATION ); // Able to convert
+  DALI_TEST_EQUALS( valueVector, Vector4::ONE, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyValueMoveConstructorArray(void)
+{
+  Property::Array array;
+  array.PushBack( 1 );
+  array.PushBack( 2 );
+  array.PushBack( 3 );
+  DALI_TEST_EQUALS( 3u, array.Size(), TEST_LOCATION );
+
+  Property::Value value( std::move( array ) );
+  DALI_TEST_ASSERTION( array.Size(), "Cannot use an object previously used as an r-value" ); // Our local variable should become invalid
+
+  Property::Array* arrayPtr = value.GetArray();
+  DALI_TEST_CHECK( arrayPtr );
+  DALI_TEST_EQUALS( 3u, arrayPtr->Size(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPropertyValueMoveConstructorMap(void)
+{
+  Property::Map map;
+  map[ 1 ] = 1;
+  map[ 2 ] = 2;
+  map[ 3 ] = 3;
+  DALI_TEST_EQUALS( 3u, map.Count(), TEST_LOCATION );
+
+  Property::Value value( std::move( map ) );
+  DALI_TEST_ASSERTION( map.Count(), "Cannot use an object previously used as an r-value" ); // Our local variable should become invalid
+
+  Property::Map* mapPtr = value.GetMap();
+  DALI_TEST_CHECK( mapPtr );
+  DALI_TEST_EQUALS( 3u, mapPtr->Count(), TEST_LOCATION );
+
+  END_TEST;
+}
+
 int UtcDaliPropertyValueAssignmentSelfP(void)
 {
   Property::Value value;
@@ -712,6 +767,38 @@ int UtcDaliPropertyValueAssignmentOperatorExtentsP(void)
   END_TEST;
 }
 
+int UtcDaliPropertyValueMoveAssignmentOperator(void)
+{
+  Property::Value value1( Vector4::ONE );
+  DALI_TEST_EQUALS( Property::VECTOR4, value1.GetType(), TEST_LOCATION );
+
+  Vector4 valueVector;
+  DALI_TEST_EQUALS( true, value1.Get( valueVector ), TEST_LOCATION ); // Able to convert
+  DALI_TEST_EQUALS( valueVector, Vector4::ONE, TEST_LOCATION );
+
+  Property::Value value2;
+  value2 = std::move( value1 );
+  DALI_TEST_EQUALS( Property::NONE, value1.GetType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( false, value1.Get( valueVector ), TEST_LOCATION ); // Unable to convert, but no crash either
+  DALI_TEST_EQUALS( Property::VECTOR4, value2.GetType(), TEST_LOCATION );
+  DALI_TEST_EQUALS( true, value2.Get( valueVector ), TEST_LOCATION ); // Able to convert
+  DALI_TEST_EQUALS( valueVector, Vector4::ONE, TEST_LOCATION );
+
+  // Change to another value type
+  value2 = std::move( Property::Value( 1.0f ) );
+  DALI_TEST_EQUALS( false, value2.Get( valueVector ), TEST_LOCATION ); // Should not be able to convert to a Vector4 now
+  float valueFloat;
+  DALI_TEST_EQUALS( true, value2.Get( valueFloat ), TEST_LOCATION ); // Should be able to convert to a float now
+  DALI_TEST_EQUALS( valueFloat, 1.0f, TEST_LOCATION );
+
+  // Ensure self assignment doesn't do anything silly
+  value2 = std::move( value2 );
+  DALI_TEST_EQUALS( true, value2.Get( valueFloat ), TEST_LOCATION );
+  DALI_TEST_EQUALS( valueFloat, 1.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
 int UtcDaliPropertyValueGetTypeP(void)
 {
   Property::Value value;
@@ -1177,7 +1264,7 @@ int UtcDaliPropertyValueOutputStream(void)
     Property::Value empty;
     std::ostringstream stream;
     stream << empty;
-    DALI_TEST_EQUALS( stream.str(), "empty type", TEST_LOCATION );
+    DALI_TEST_EQUALS( stream.str(), "undefined type", TEST_LOCATION );
   }
 
   {
index 7fe8447..bbdeb56 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -46,6 +46,12 @@ Property::Array::Array( const Property::Array& other )
   mImpl->mArray = other.mImpl->mArray;
 }
 
+Property::Array::Array( Property::Array&& other )
+: mImpl( other.mImpl )
+{
+  other.mImpl = nullptr;
+}
+
 Property::Array::~Array()
 {
   delete mImpl;
@@ -53,55 +59,78 @@ Property::Array::~Array()
 
 Property::Array::SizeType Property::Array::Count() const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   return mImpl->mArray.size();
 }
 
 void Property::Array::PushBack( const Value& value )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   mImpl->mArray.push_back( value );
 }
 
 void Property::Array::Clear()
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   mImpl->mArray.clear();
 }
 
 void Property::Array::Reserve( SizeType size )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   mImpl->mArray.reserve(size);
 }
 
 void Property::Array::Resize( SizeType size )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   mImpl->mArray.resize(size);
 }
 
 Property::Array::SizeType Property::Array::Capacity()
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   return mImpl->mArray.capacity();
 }
 
 const Property::Value& Property::Array::operator[]( SizeType index ) const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
+  // Note says no bounds checking is performed so we don't need to verify mImpl as Count() will return 0 anyway
   return mImpl->mArray[ index ];
 }
 
 Property::Value& Property::Array::operator[]( SizeType index )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
+  // Note says no bounds checking is performed so we don't need to verify mImpl as Count() will return 0 anyway
   return mImpl->mArray[ index ];
 }
 
 Property::Array& Property::Array::operator=( const Property::Array& other )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   if( this != &other )
   {
-    delete mImpl;
-    mImpl = new Impl;
     mImpl->mArray = other.mImpl->mArray;
   }
   return *this;
 }
 
+Property::Array& Property::Array::operator=( Property::Array&& other )
+{
+  if( this != &other )
+  {
+    delete mImpl;
+    mImpl = other.mImpl;
+    other.mImpl = nullptr;
+  }
+  return *this;
+}
+
 std::ostream& operator<<( std::ostream& stream, const Property::Array& array )
 {
   stream << "Array(" << array.Count() << ") = [";
index 331d1e9..e4ac804 100755 (executable)
@@ -1,8 +1,8 @@
-#ifndef __DALI_PROPERTY_ARRAY_H__
-#define __DALI_PROPERTY_ARRAY_H__
+#ifndef DALI_PROPERTY_ARRAY_H
+#define DALI_PROPERTY_ARRAY_H
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -58,6 +58,15 @@ public:
   Array( const Array& other );
 
   /**
+   * @brief Move Constructor.
+   *
+   * @SINCE_1_4.17
+   * @param[in] other The Array to move from
+   * @note The other array is an r-value so becomes invalid and is no longer usable.
+   */
+  Array( Array&& other );
+
+  /**
    * @brief Non-virtual destructor.
    * @SINCE_1_0.0
    */
@@ -197,6 +206,18 @@ public:
   Array& operator=( const Array& other );
 
   /**
+   * @brief Move Assignment Operator.
+   *
+   * @SINCE_1_4.17
+   * @param[in] other The array to copy from
+   *
+   * @return The moved array.
+   *
+   * @note The other array is an r-value so becomes invalid and is no longer usable.
+   */
+  Array& operator=( Array&& other );
+
+  /**
    * @brief Output to stream.
    * @SINCE_1_1.28
    */
@@ -222,4 +243,4 @@ DALI_CORE_API std::ostream& operator<<( std::ostream& stream, const Property::Ar
  */
 } // namespace Dali
 
-#endif // __DALI_PROPERTY_ARRAY_H__
+#endif // DALI_PROPERTY_ARRAY_H
index 675d910..61329a8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -55,6 +55,12 @@ Property::Map::Map( const Property::Map& other )
   mImpl->mIndexValueContainer = other.mImpl->mIndexValueContainer;
 }
 
+Property::Map::Map( Property::Map&& other )
+: mImpl( other.mImpl )
+{
+  other.mImpl = nullptr;
+}
+
 Property::Map::~Map()
 {
   delete mImpl;
@@ -62,31 +68,37 @@ Property::Map::~Map()
 
 Property::Map::SizeType Property::Map::Count() const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   return mImpl->mStringValueContainer.size() + mImpl->mIndexValueContainer.size();
 }
 
 bool Property::Map::Empty() const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   return mImpl->mStringValueContainer.empty() && mImpl->mIndexValueContainer.empty();
 }
 
 void Property::Map::Insert( const char* key, const Value& value )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   mImpl->mStringValueContainer.push_back( std::make_pair( key, value ) );
 }
 
 void Property::Map::Insert( const std::string& key, const Value& value )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   mImpl->mStringValueContainer.push_back( std::make_pair( key, value ) );
 }
 
 void Property::Map::Insert( Property::Index key, const Value& value )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   mImpl->mIndexValueContainer.push_back( std::make_pair( key, value ) );
 }
 
 Property::Value& Property::Map::GetValue( SizeType position ) const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   SizeType numStringKeys = mImpl->mStringValueContainer.size();
   SizeType numIndexKeys  = mImpl->mIndexValueContainer.size();
   DALI_ASSERT_ALWAYS( position < ( numStringKeys + numIndexKeys ) && "position out-of-bounds" );
@@ -105,6 +117,7 @@ const std::string& Property::Map::GetKey( SizeType position ) const
 {
   DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: GetKey() is deprecated and will be removed from next release.\n" );
 
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
   SizeType numStringKeys = mImpl->mStringValueContainer.size();
   DALI_ASSERT_ALWAYS( position < numStringKeys && "position out-of-bounds" );
 
@@ -113,6 +126,8 @@ const std::string& Property::Map::GetKey( SizeType position ) const
 
 Property::Key Property::Map::GetKeyAt( SizeType position ) const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   SizeType numStringKeys = mImpl->mStringValueContainer.size();
   SizeType numIndexKeys  = mImpl->mIndexValueContainer.size();
   DALI_ASSERT_ALWAYS( position < ( numStringKeys + numIndexKeys ) && "position out-of-bounds" );
@@ -133,6 +148,8 @@ StringValuePair& Property::Map::GetPair( SizeType position ) const
 {
   DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: GetPair() is deprecated and will be removed from next release.\n" );
 
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   SizeType numStringKeys = mImpl->mStringValueContainer.size();
 
   DALI_ASSERT_ALWAYS( position < ( numStringKeys ) && "position out-of-bounds" );
@@ -142,6 +159,8 @@ StringValuePair& Property::Map::GetPair( SizeType position ) const
 
 KeyValuePair Property::Map::GetKeyValue( SizeType position ) const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   SizeType numStringKeys = mImpl->mStringValueContainer.size();
   SizeType numIndexKeys  = mImpl->mIndexValueContainer.size();
 
@@ -163,6 +182,8 @@ KeyValuePair Property::Map::GetKeyValue( SizeType position ) const
 
 Property::Value* Property::Map::Find( const char* key ) const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   for ( StringValueContainer::iterator iter = mImpl->mStringValueContainer.begin(), endIter = mImpl->mStringValueContainer.end(); iter != endIter; ++iter )
   {
     if ( iter->first == key )
@@ -180,6 +201,8 @@ Property::Value* Property::Map::Find( const std::string& key ) const
 
 Property::Value* Property::Map::Find( Property::Index key ) const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   for ( IndexValueContainer::iterator iter = mImpl->mIndexValueContainer.begin(), endIter = mImpl->mIndexValueContainer.end(); iter != endIter; ++iter )
   {
     if ( iter->first == key )
@@ -202,6 +225,8 @@ Property::Value* Property::Map::Find( Property::Index indexKey, const std::strin
 
 Property::Value* Property::Map::Find( const std::string& key, Property::Type type ) const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   for ( StringValueContainer::iterator iter = mImpl->mStringValueContainer.begin(), endIter = mImpl->mStringValueContainer.end(); iter != endIter; ++iter )
   {
     if( (iter->second.GetType() == type) && (iter->first == key) )
@@ -214,6 +239,8 @@ Property::Value* Property::Map::Find( const std::string& key, Property::Type typ
 
 Property::Value* Property::Map::Find( Property::Index key, Property::Type type ) const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   for ( IndexValueContainer::iterator iter = mImpl->mIndexValueContainer.begin(), endIter = mImpl->mIndexValueContainer.end(); iter != endIter; ++iter )
   {
     if( (iter->second.GetType() == type) && (iter->first == key) )
@@ -226,12 +253,16 @@ Property::Value* Property::Map::Find( Property::Index key, Property::Type type )
 
 void Property::Map::Clear()
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   mImpl->mStringValueContainer.clear();
   mImpl->mIndexValueContainer.clear();
 }
 
 void Property::Map::Merge( const Property::Map& from )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   // Ensure we're not attempting to merge with ourself
   if ( this != &from )
   {
@@ -257,6 +288,8 @@ void Property::Map::Merge( const Property::Map& from )
 
 const Property::Value& Property::Map::operator[]( const std::string& key ) const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   for ( StringValueContainer::const_iterator iter = mImpl->mStringValueContainer.begin(), endIter = mImpl->mStringValueContainer.end(); iter != endIter; ++iter )
   {
     if ( iter->first == key )
@@ -270,6 +303,8 @@ const Property::Value& Property::Map::operator[]( const std::string& key ) const
 
 Property::Value& Property::Map::operator[]( const std::string& key )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   for ( StringValueContainer::iterator iter = mImpl->mStringValueContainer.begin(), endIter = mImpl->mStringValueContainer.end(); iter != endIter; ++iter )
   {
     if ( iter->first == key )
@@ -285,6 +320,8 @@ Property::Value& Property::Map::operator[]( const std::string& key )
 
 const Property::Value& Property::Map::operator[]( Property::Index key ) const
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   for ( IndexValueContainer::const_iterator iter = mImpl->mIndexValueContainer.begin(), endIter = mImpl->mIndexValueContainer.end(); iter != endIter; ++iter )
   {
     if ( iter->first == key )
@@ -298,6 +335,8 @@ const Property::Value& Property::Map::operator[]( Property::Index key ) const
 
 Property::Value& Property::Map::operator[]( Property::Index key )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   for ( IndexValueContainer::iterator iter = mImpl->mIndexValueContainer.begin(), endIter = mImpl->mIndexValueContainer.end(); iter != endIter; ++iter )
   {
     if ( iter->first == key )
@@ -313,39 +352,53 @@ Property::Value& Property::Map::operator[]( Property::Index key )
 
 Property::Map& Property::Map::operator=( const Property::Map& other )
 {
+  DALI_ASSERT_DEBUG( mImpl && "Cannot use an object previously used as an r-value" );
+
   if( this != &other )
   {
-    delete mImpl;
-    mImpl = new Impl;
     mImpl->mStringValueContainer = other.mImpl->mStringValueContainer;
     mImpl->mIndexValueContainer = other.mImpl->mIndexValueContainer;
   }
   return *this;
 }
 
+Property::Map& Property::Map::operator=( Property::Map&& other )
+{
+  if( this != &other )
+  {
+    delete mImpl;
+    mImpl = other.mImpl;
+    other.mImpl = nullptr;
+  }
+  return *this;
+}
+
 std::ostream& operator<<( std::ostream& stream, const Property::Map& map )
 {
   stream << "Map(" << map.Count() << ") = {";
 
-  int32_t count = 0;
-  // Output the String-Value pairs
-  for ( StringValueContainer::iterator iter = map.mImpl->mStringValueContainer.begin(), endIter = map.mImpl->mStringValueContainer.end(); iter != endIter; ++iter )
+  if ( map.mImpl )
   {
-    if( count++ > 0 )
+    int32_t count = 0;
+    // Output the String-Value pairs
+    for ( StringValueContainer::iterator iter = map.mImpl->mStringValueContainer.begin(), endIter = map.mImpl->mStringValueContainer.end(); iter != endIter; ++iter )
     {
-      stream<<", ";
+      if( count++ > 0 )
+      {
+        stream<<", ";
+      }
+      stream<< iter->first << ":"<<iter->second;
     }
-    stream<< iter->first << ":"<<iter->second;
-  }
 
-  // Output the Index-Value pairs
-  for ( IndexValueContainer::iterator iter = map.mImpl->mIndexValueContainer.begin(), endIter = map.mImpl->mIndexValueContainer.end(); iter != endIter; ++iter )
-  {
-    if( count++ > 0 )
+    // Output the Index-Value pairs
+    for ( IndexValueContainer::iterator iter = map.mImpl->mIndexValueContainer.begin(), endIter = map.mImpl->mIndexValueContainer.end(); iter != endIter; ++iter )
     {
-      stream<<", ";
+      if( count++ > 0 )
+      {
+        stream<<", ";
+      }
+      stream<< iter->first << ":"<<iter->second;
     }
-    stream<< iter->first << ":"<<iter->second;
   }
 
   stream << "}";
index 44a132f..f23f2b3 100755 (executable)
@@ -1,8 +1,8 @@
-#ifndef __DALI_PROPERTY_MAP_H__
-#define __DALI_PROPERTY_MAP_H__
+#ifndef DALI_PROPERTY_MAP_H
+#define DALI_PROPERTY_MAP_H
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -63,6 +63,15 @@ public:
   Map( const Map& other );
 
   /**
+   * @brief Move Constructor.
+   *
+   * @SINCE_1_4.17
+   * @param[in] other The Map to move from
+   * @note The other array is an r-value so becomes invalid and is no longer usable.
+   */
+  Map( Map&& other );
+
+  /**
    * @brief Non-virtual destructor.
    * @SINCE_1_0.0
    */
@@ -360,6 +369,18 @@ public:
   Map& operator=( const Map& other );
 
   /**
+   * @brief Move Assignment Operator.
+   *
+   * @SINCE_1_4.17
+   * @param[in] other The map to move from
+   *
+   * @return The moved map
+   *
+   * @note The other array is an r-value so becomes invalid and is no longer usable.
+   */
+  Map& operator=( Map&& other );
+
+  /**
    * @brief Output to stream.
    * @SINCE_1_1.28
    */
@@ -385,4 +406,4 @@ DALI_CORE_API std::ostream& operator<<( std::ostream& stream, const Property::Ma
  */
 } // namespace Dali
 
-#endif // __DALI_PROPERTY_MAP_H__
+#endif // DALI_PROPERTY_MAP_H
index cd7ae5a..fbcfc2b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -53,11 +53,6 @@ inline bool IsIntegerType( Property::Type type )
 
 struct Property::Value::Impl
 {
-  Impl()
-  : type( Property::NONE ),
-    integerValue( 0 )
-  { }
-
   Impl( bool booleanValue )
   : type( Property::BOOLEAN ),
     integerValue( booleanValue )
@@ -113,7 +108,7 @@ struct Property::Value::Impl
     quaternionValue.ToAxisAngle( angleAxisValue->axis, angleAxisValue->angle );
   }
 
-  Impl(const std::string& stringValue)
+  Impl( const std::string& stringValue )
   : type( Property::STRING ),
     stringValue( new std::string( stringValue ) )
   {
@@ -131,12 +126,24 @@ struct Property::Value::Impl
   {
   }
 
+  Impl( Property::Array&& arrayValue )
+  : type( Property::ARRAY ),
+    arrayValue( new Property::Array( std::move( arrayValue ) ) )
+  {
+  }
+
   Impl( const Property::Map& mapValue )
   : type( Property::MAP ),
     mapValue( new Property::Map( mapValue ) )
   {
   }
 
+  Impl( Property::Map&& mapValue )
+  : type( Property::MAP ),
+    mapValue( new Property::Map( std::move( mapValue ) ) )
+  {
+  }
+
   Impl( const Extents& extentsValue )
   : type( Property::EXTENTS ),
     extentsValue( new Extents( extentsValue ) )
@@ -245,7 +252,7 @@ private:
 };
 
 Property::Value::Value()
-: mImpl( NULL )
+: mImpl( nullptr )
 {
 }
 
@@ -310,9 +317,9 @@ Property::Value::Value( const std::string& stringValue )
 }
 
 Property::Value::Value( const char* stringValue )
-: mImpl( NULL )
+: mImpl( nullptr )
 {
-  if( stringValue ) // string constructor is undefined with NULL pointer
+  if( stringValue ) // string constructor is undefined with nullptr
   {
     mImpl = new Impl( std::string(stringValue) );
   }
@@ -327,18 +334,28 @@ Property::Value::Value( Property::Array& arrayValue )
 {
 }
 
+Property::Value::Value( Property::Array&& arrayValue )
+: mImpl( new Impl( std::move( arrayValue ) ) )
+{
+}
+
 Property::Value::Value( Property::Map& mapValue )
 : mImpl( new Impl( mapValue ) )
 {
 }
 
+Property::Value::Value( Property::Map&& mapValue )
+: mImpl( new Impl( std::move( mapValue ) ) )
+{
+}
+
 Property::Value::Value( const Extents& extentsValue )
 : mImpl( new Impl( extentsValue ) )
 {
 }
 
 Property::Value::Value( Type type )
-: mImpl( NULL )
+: mImpl( nullptr )
 {
   switch (type)
   {
@@ -414,19 +431,25 @@ Property::Value::Value( Type type )
     }
     case Property::NONE:
     {
-      mImpl = new Impl();
+      // No need to create an Impl
       break;
     }
   }
 }
 
 Property::Value::Value( const Property::Value& value )
-: mImpl( NULL )
+: mImpl( nullptr )
 {
   // 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 )
@@ -438,7 +461,7 @@ Property::Value& Property::Value::operator=( const Property::Value& value )
   if( !value.mImpl )
   {
     delete mImpl;
-    mImpl = NULL;
+    mImpl = nullptr;
     return *this;
   }
   // first check if the type is the same, no need to change impl, just assign
@@ -517,14 +540,14 @@ Property::Value& Property::Value::operator=( const Property::Value& value )
         break;
       }
       case Property::NONE:
-      { // mImpl will be NULL, there's no way to get to this case
+      { // mImpl will be a nullptr, there's no way to get to this case
       }
     }
   }
   else
   {
     // different type, release old impl and create new
-    Impl* newImpl( NULL );
+    Impl* newImpl( nullptr );
     switch ( value.mImpl->type )
     {
       case Property::BOOLEAN:
@@ -598,7 +621,7 @@ Property::Value& Property::Value::operator=( const Property::Value& value )
         break;
       }
       case Property::NONE:
-      { // NULL value will be used for "empty" value
+      { // nullptr value will be used for "empty" value
       }
     }
     delete mImpl;
@@ -608,6 +631,18 @@ Property::Value& Property::Value::operator=( const Property::Value& value )
   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;
@@ -821,7 +856,7 @@ bool Property::Value::Get( Property::Map& mapValue ) const
 
 Property::Array* Property::Value::GetArray() const
 {
-  Property::Array* array = NULL;
+  Property::Array* array = nullptr;
   if( mImpl && (mImpl->type == ARRAY) ) // type cannot change in mImpl so array is allocated
   {
     array = mImpl->arrayValue;
@@ -831,7 +866,7 @@ Property::Array* Property::Value::GetArray() const
 
 Property::Map* Property::Value::GetMap() const
 {
-  Property::Map* map = NULL;
+  Property::Map* map = nullptr;
   if( mImpl && (mImpl->type == MAP) ) // type cannot change in mImpl so map is allocated
   {
     map = mImpl->mapValue;
@@ -940,15 +975,13 @@ std::ostream& operator<<( std::ostream& stream, const Property::Value& value )
         break;
       }
       case Dali::Property::NONE:
-      {
-        stream << "undefined type";
-        break;
+      { // mImpl will be a nullptr, there's no way to get to this case
       }
     }
   }
   else
   {
-    stream << "empty type";
+    stream << "undefined type";
   }
   return stream;
 }
index b054810..d8f074a 100755 (executable)
@@ -2,7 +2,7 @@
 #define __DALI_PROPERTY_VALUE_H__
 
 /*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
@@ -170,14 +170,30 @@ public:
   Value( Property::Array& arrayValue );
 
   /**
+   * @brief Creates an array property value.
+   *
+   * @SINCE_1_4.16
+   * @param[in] arrayValue An r-value array
+   */
+  Value( Property::Array&& arrayValue );
+
+  /**
    * @brief Creates a map property value.
    *
    * @SINCE_1_0.0
-   * @param[in] mapValue An array
+   * @param[in] mapValue A map
    */
   Value( Property::Map& mapValue );
 
   /**
+   * @brief Creates a map property value.
+   *
+   * @SINCE_1_4.16
+   * @param[in] mapValue An r-value map
+   */
+  Value( Property::Map&& mapValue );
+
+  /**
    * @brief Creates an extents property value.
    *
    * @SINCE_1_2.62
@@ -202,6 +218,14 @@ public:
   Value( const Value& value );
 
   /**
+   * @brief Move constructor.
+   *
+   * @SINCE_1_4.16
+   * @param[in] value The property value to move from
+   */
+  Value( Value&& value );
+
+  /**
    * @brief Assigns a property value.
    *
    * @SINCE_1_0.0
@@ -211,6 +235,15 @@ public:
   Value& operator=( const Value& value );
 
   /**
+   * @brief Move assignment operator.
+   *
+   * @SINCE_1_4.16
+   * @param[in] value The property value to move from
+   * @return a reference to this
+   */
+  Value& operator=( Value&& value );
+
+  /**
    * @brief Non-virtual destructor.
    *
    * This class is not a base class.