Add Internal::IndexedMap
[platform/core/uifw/dali-core.git] / dali / internal / event / common / type-info-impl.cpp
index 91e50cf..7133dce 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/debug.h>
-#include <dali/internal/event/common/type-registry-impl.h>
 #include <dali/internal/event/common/object-impl.h>
+#include <dali/internal/event/common/type-registry-impl.h>
 
 using std::find_if;
 
+namespace Dali
+{
+namespace Internal
+{
 namespace
 {
-
 /*
  * Functor to find by given type for vector of pairs
  */
-template <typename S, typename T>
+template<typename S, typename T>
 struct PairFinder
 {
   PairFinder(const S& find)
@@ -49,114 +52,212 @@ struct PairFinder
   }
 
 private:
-
   const S& mFind;
 };
 
 /**
  * Functor to find a matching property name
  */
-template <typename T>
+template<typename T>
 struct PropertyNameFinder
 {
-  PropertyNameFinder( const std::string& find )
-  : mFind( find )
+  PropertyNameFinder(ConstString find)
+  : mFind(find)
   {
   }
 
-  bool operator()(const T &p) const
+  bool operator()(const Tp) const
   {
     return p.second.name == mFind;
   }
 
 private:
-
-  const std::string& mFind;
+  ConstString mFind;
 };
 
-} // namespace anon
+/**
+ * Functor to find a matching property component index
+ */
+template<typename T>
+struct PropertyComponentFinder
+{
+  PropertyComponentFinder(Property::Index basePropertyIndex, const int find)
+  : mBasePropertyIndex(basePropertyIndex),
+    mFind(find)
+  {
+  }
 
-namespace Dali
+  bool operator()(const T& p) const
+  {
+    return (p.second.basePropertyIndex == mBasePropertyIndex && p.second.componentIndex == mFind);
+  }
+
+private:
+  Property::Index mBasePropertyIndex;
+  const int       mFind;
+};
+
+/**
+ * Helper function to find the right default property with given index and return the desired detail of it
+ */
+template<typename Parameter, typename Member>
+inline bool GetDefaultPropertyField(const Dali::PropertyDetails* propertyTable, Property::Index count, Property::Index index, Member member, Parameter& parameter)
 {
+  bool found = false;
+  // is index inside this table (bigger than first index but smaller than first + count)
+  if((index >= propertyTable->enumIndex) && (index < (propertyTable->enumIndex + count)))
+  {
+    // return the match. we're assuming here that there is no gaps between the indices in a table
+    parameter = propertyTable[index - propertyTable->enumIndex].*member;
+    found     = true;
+  }
+  // should never really get here
+  return found;
+}
 
-namespace Internal
+// static pointer value to mark that a base class address has not been resolved
+// 0x01 is not a valid pointer but used here to differentiate from nullptr
+// unfortunately it cannot be constexpr as C++ does not allow them to be initialised with reinterpret_cast
+Internal::TypeInfo* const UNRESOLVED = reinterpret_cast<Internal::TypeInfo*>(0x1);
+
+/**
+ * Helper function to resolve and return the pointer to the base type info
+ * Not a member function to avoid having to #include additional headers and to make sure this gets inlined inside this cpp
+ * @param[in/out] baseType pointer to resolve and set
+ * @param[in] typeRegistry reference to the type registry
+ * @param[in] baseTypeName string name of the base type
+ * @return true is base type exists
+ */
+inline bool GetBaseType(Internal::TypeInfo*& baseType, TypeRegistry& typeRegistry, const std::string& baseTypeName)
 {
+  // if greater than unresolved means we have a base type, null means no base
+  bool baseExists = (baseType > UNRESOLVED);
+  // base only needs to be resolved once
+  if(UNRESOLVED == baseType)
+  {
+    TypeRegistry::TypeInfoPointer base = typeRegistry.GetTypeInfo(baseTypeName);
+    if(base)
+    {
+      baseType   = base.Get(); // dont pass ownership, just return raw pointer
+      baseExists = true;
+    }
+    else
+    {
+      // no type info found so assuming no base as all type registration is done in startup for now
+      baseType = nullptr;
+    }
+  }
+  return baseExists;
+}
 
-TypeInfo::TypeInfo(const std::string &name, const std::string &baseTypeName, Dali::TypeInfo::CreateFunction creator)
-  : mTypeName(name), mBaseTypeName(baseTypeName), mCreate(creator)
+} // unnamed namespace
+
+TypeInfo::TypeInfo(const std::string& name, const std::string& baseTypeName, Dali::TypeInfo::CreateFunction creator, const Dali::PropertyDetails* defaultProperties, Property::Index defaultPropertyCount)
+: mTypeRegistry(*TypeRegistry::Get()),
+  mBaseType(UNRESOLVED),
+  mTypeName(name),
+  mBaseTypeName(baseTypeName),
+  mCreate(creator),
+  mDefaultProperties(defaultProperties),
+  mDefaultPropertyCount(defaultPropertyCount),
+  mCSharpType(false)
 {
   DALI_ASSERT_ALWAYS(!name.empty() && "Type info construction must have a name");
   DALI_ASSERT_ALWAYS(!baseTypeName.empty() && "Type info construction must have a base type name");
 }
 
-TypeInfo::~TypeInfo()
+TypeInfo::TypeInfo(const std::string& name, const std::string& baseTypeName, Dali::CSharpTypeInfo::CreateFunction creator)
+: mTypeRegistry(*TypeRegistry::Get()),
+  mBaseType(UNRESOLVED),
+  mTypeName(name),
+  mBaseTypeName(baseTypeName),
+  mCSharpCreate(creator),
+  mCSharpType(true)
 {
+  DALI_ASSERT_ALWAYS(!name.empty() && "Type info construction must have a name");
+  DALI_ASSERT_ALWAYS(!baseTypeName.empty() && "Type info construction must have a base type name");
 }
 
+TypeInfo::~TypeInfo() = default;
+
 BaseHandle TypeInfo::CreateInstance() const
 {
   BaseHandle ret;
 
   if(mCreate)
   {
-    ret = mCreate();
+    if(mCSharpType)
+    {
+      // CSharp currently only registers one create function for all custom controls
+      // it uses the type name to decide which one to create
+      ret = *mCSharpCreate(mTypeName.c_str());
+    }
+    else
+    {
+      ret = mCreate();
+    }
 
-    if ( ret )
+    if(ret)
     {
       BaseObject& handle = ret.GetBaseObject();
-      Object *object = dynamic_cast<Internal::Object*>(&handle);
+      Object*     object = dynamic_cast<Internal::Object*>(&handle);
 
-      if ( object )
+      if(object)
       {
-        object->SetTypeInfo( this );
+        object->SetTypeInfo(this);
       }
     }
   }
   return ret;
 }
 
-bool TypeInfo::DoActionTo(BaseObject *object, const std::string &actionName, const std::vector<Property::Value> &properties)
+bool TypeInfo::DoActionTo(BaseObject* object, const std::string& actionName, const Property::Map& properties)
 {
   bool done = false;
 
-  ActionContainer::iterator iter = find_if(mActions.begin(), mActions.end(), PairFinder<std::string, ActionPair>(actionName));
-
-  if( iter != mActions.end() )
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  auto iter = mActions.Get(ConstString(actionName));
+#else
+  ActionContainer::iterator    iter = find_if(mActions.begin(), mActions.end(), PairFinder<std::string, ActionPair>(actionName));
+#endif
+  if(iter != mActions.end())
   {
     done = (iter->second)(object, actionName, properties);
   }
-  else
-  {
-    DALI_LOG_WARNING("Type '%s' cannot do action '%s'\n", mTypeName.c_str(), actionName.c_str());
-  }
 
   if(!done)
   {
-    Dali::TypeInfo base = Dali::TypeRegistry::Get().GetTypeInfo( mBaseTypeName );
-    while( base )
+    if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
     {
-      done = GetImplementation(base).DoActionTo(object, actionName, properties);
-      if( done )
-      {
-        break;
-      }
-      base =  Dali::TypeRegistry::Get().GetTypeInfo( base.GetBaseName() );
+      // call base type recursively
+      done = mBaseType->DoActionTo(object, actionName, properties);
     }
   }
 
   return done;
 }
 
-bool TypeInfo::ConnectSignal( BaseObject* object, ConnectionTrackerInterface* connectionTracker, const std::string& signalName, FunctorDelegate* functor )
+bool TypeInfo::ConnectSignal(BaseObject* object, ConnectionTrackerInterface* connectionTracker, const std::string& signalName, FunctorDelegate* functor)
 {
-  bool connected( false );
-
-  ConnectorContainer::iterator iter = find_if( mSignalConnectors.begin(), mSignalConnectors.end(),
-                                                 PairFinder<std::string, ConnectionPair>(signalName) );
+  bool connected(false);
+
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  auto iter = mSignalConnectors.Get(ConstString(signalName));
+#else
+  ConnectorContainer::iterator iter = find_if(mSignalConnectors.begin(), mSignalConnectors.end(), PairFinder<std::string, ConnectionPair>(signalName));
+#endif
+  if(iter != mSignalConnectors.end())
+  {
+    connected = (iter->second)(object, connectionTracker, signalName, functor);
+  }
 
-  if( iter != mSignalConnectors.end() )
+  if(!connected)
   {
-    connected = (iter->second)( object, connectionTracker, signalName, functor );
+    if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+    {
+      // call base type recursively
+      connected = mBaseType->ConnectSignal(object, connectionTracker, signalName, functor);
+    }
   }
 
   return connected;
@@ -177,353 +278,882 @@ Dali::TypeInfo::CreateFunction TypeInfo::GetCreator() const
   return mCreate;
 }
 
-void TypeInfo::GetActions( Dali::TypeInfo::NameContainer& ret ) const
+uint32_t TypeInfo::GetActionCount() const
 {
-  for(ActionContainer::const_iterator iter = mActions.begin(); iter != mActions.end(); ++iter)
-  {
-    ret.push_back(iter->first);
-  }
+  uint32_t count = static_cast<uint32_t>(mActions.size());
 
-  Dali::TypeInfo base = Dali::TypeRegistry::Get().GetTypeInfo( mBaseTypeName );
-  while( base )
+  if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
   {
-    for(ActionContainer::const_iterator iter = GetImplementation(base).mActions.begin();
-        iter != GetImplementation(base).mActions.end(); ++iter)
-    {
-      ret.push_back(iter->first);
-    }
-
-    base = Dali::TypeRegistry::Get().GetTypeInfo( base.GetBaseName() );
+    // call base type recursively
+    count += mBaseType->GetActionCount();
   }
+
+  return count;
 }
 
-void TypeInfo::GetSignals(Dali::TypeInfo::NameContainer& ret) const
+std::string TypeInfo::GetActionName(uint32_t index) const
 {
-  for(ConnectorContainer::const_iterator iter = mSignalConnectors.begin(); iter != mSignalConnectors.end(); ++iter)
+  std::string    name;
+  const uint32_t count = static_cast<uint32_t>(mActions.size());
+
+  if(index < count)
   {
-    ret.push_back(iter->first);
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+    name = std::string(mActions.GetKeyByIndex(index).GetStringView());
+#else
+    name = mActions[index].first;
+#endif
   }
-
-  Dali::TypeInfo base = Dali::TypeRegistry::Get().GetTypeInfo( mBaseTypeName );
-  while( base )
+  else
   {
-    for(ConnectorContainer::const_iterator iter = GetImplementation(base).mSignalConnectors.begin();
-        iter != GetImplementation(base).mSignalConnectors.end(); ++iter)
+    if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
     {
-      ret.push_back(iter->first);
+      // call base type recursively
+      return mBaseType->GetActionName(index - count);
     }
-
-    base = Dali::TypeRegistry::Get().GetTypeInfo( base.GetBaseName() );
   }
+
+  return name;
 }
 
-void TypeInfo::GetProperties( Dali::TypeInfo::NameContainer& ret ) const
+uint32_t TypeInfo::GetSignalCount() const
 {
-  Property::IndexContainer indices;
+  uint32_t count = static_cast<uint32_t>(mSignalConnectors.size());
 
-  GetPropertyIndices(indices);
+  if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    count += mBaseType->GetSignalCount();
+  }
+
+  return count;
+}
 
-  ret.reserve(indices.size());
+std::string TypeInfo::GetSignalName(uint32_t index) const
+{
+  std::string    name;
+  const uint32_t count = static_cast<uint32_t>(mSignalConnectors.size());
 
-  for(Property::IndexContainer::iterator iter = indices.begin(); iter != indices.end(); ++iter)
+  if(index < count)
   {
-    const std::string& name = GetPropertyName( *iter );
-    if(name.size())
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+    name = std::string(mSignalConnectors.GetKeyByIndex(index).GetStringView());
+#else
+    name = mSignalConnectors[index].first;
+#endif
+  }
+  else
+  {
+    if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
     {
-      ret.push_back( name );
+      // call base type recursively
+      return mBaseType->GetSignalName(index - count);
     }
-    else
+  }
+
+  return name;
+}
+
+void TypeInfo::GetPropertyIndices(Property::IndexContainer& indices) const
+{
+  // Default Properties
+  if(mDefaultProperties)
+  {
+    indices.Reserve(indices.Size() + mDefaultPropertyCount);
+    for(Property::Index index = 0; index < mDefaultPropertyCount; ++index)
     {
-      DALI_LOG_WARNING("Property had no name\n");
+      indices.PushBack(mDefaultProperties[index].enumIndex);
     }
   }
+
+  if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    mBaseType->GetPropertyIndices(indices);
+  }
+
+  AppendProperties(indices, mRegisteredProperties);
 }
 
-void TypeInfo::GetPropertyIndices( Property::IndexContainer& indices ) const
+void TypeInfo::GetChildPropertyIndices(Property::IndexContainer& indices) const
 {
-  Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
-  if ( base )
+  if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
   {
-    const TypeInfo& baseImpl( GetImplementation( base ) );
-    baseImpl.GetPropertyIndices( indices );
+    // call base type recursively
+    mBaseType->GetChildPropertyIndices(indices);
   }
 
-  if ( ! mRegisteredProperties.empty() )
+  AppendProperties(indices, mRegisteredChildProperties);
+}
+
+/**
+ * Append the indices in RegisteredProperties to the given index container.
+ */
+void TypeInfo::AppendProperties(Dali::Property::IndexContainer&              indices,
+                                const TypeInfo::RegisteredPropertyContainer& registeredProperties) const
+{
+  if(!registeredProperties.empty())
   {
-    indices.reserve( indices.size() + mRegisteredProperties.size() );
+    indices.Reserve(indices.Size() + registeredProperties.size());
 
-    const RegisteredPropertyContainer::const_iterator endIter = mRegisteredProperties.end();
-    for ( RegisteredPropertyContainer::const_iterator iter = mRegisteredProperties.begin(); iter != endIter; ++iter )
+    for(auto&& elem : registeredProperties)
     {
-      indices.push_back( iter->first );
+      indices.PushBack(elem.first);
     }
   }
 }
 
-const std::string& TypeInfo::GetPropertyName( Property::Index index ) const
+std::string_view TypeInfo::GetRegisteredPropertyName(Property::Index index) const
 {
-  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
-                                                          PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
-
-  if ( iter != mRegisteredProperties.end() )
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
+#else
+  RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
+  if(iter != mRegisteredProperties.end())
   {
-    return iter->second.name;
+    return iter->second.name.GetStringView();
   }
+  if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    return mBaseType->GetRegisteredPropertyName(index);
+  }
+  static std::string empty;
+  return empty;
+}
 
-  Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
-  if ( base )
+std::string_view TypeInfo::GetPropertyName(Property::Index index) const
+{
+  std::string_view propertyName;
+  // default or custom
+  if(mDefaultProperties && (index < DEFAULT_PROPERTY_MAX_COUNT))
   {
-    return GetImplementation(base).GetPropertyName( index );
+    std::string_view name;
+    if(GetDefaultPropertyField(mDefaultProperties, mDefaultPropertyCount, index, &Dali::PropertyDetails::name, name))
+    {
+      propertyName = name;
+    }
+  }
+  else
+  {
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+    const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
+#else
+    RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
+    if(iter != mRegisteredProperties.end())
+    {
+      return iter->second.name.GetStringView();
+    }
+  }
+  // if not our property, go to parent
+  if(propertyName.empty())
+  {
+    if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+    {
+      // call base type recursively
+      return mBaseType->GetPropertyName(index);
+    }
   }
 
-  DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
+  return propertyName;
 }
 
-void TypeInfo::AddActionFunction( const std::string &actionName, Dali::TypeInfo::ActionFunction function )
+void TypeInfo::AddActionFunction(std::string actionName, Dali::TypeInfo::ActionFunction function)
 {
-  if( NULL == function)
+  if(nullptr == function)
   {
     DALI_LOG_WARNING("Action function is empty\n");
   }
   else
   {
-    ActionContainer::iterator iter = std::find_if(mActions.begin(), mActions.end(),
-                                                  PairFinder<std::string, ActionPair>(actionName));
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+    if(!mActions.Register(ConstString(actionName), function))
+    {
+      DALI_LOG_WARNING("Action already exists in TypeRegistry Type\n", actionName.c_str());
+    }
+#else
+    ActionContainer::iterator                   iter = std::find_if(mActions.begin(), mActions.end(), PairFinder<std::string, ActionPair>(actionName));
 
-    if( iter == mActions.end() )
+    if(iter == mActions.end())
     {
-      mActions.push_back( ActionPair( actionName, function ) );
+      mActions.push_back(ActionPair(std::move(actionName), function));
     }
     else
     {
-      DALI_LOG_WARNING("Action already exists in TypeRegistry Type", actionName.c_str());
+      DALI_LOG_WARNING("Action already exists in TypeRegistry Type\n", actionName.c_str());
     }
+#endif
   }
 }
 
-void TypeInfo::AddConnectorFunction( const std::string& signalName, Dali::TypeInfo::SignalConnectorFunction function )
+void TypeInfo::AddConnectorFunction(std::string signalName, Dali::TypeInfo::SignalConnectorFunction function)
 {
-  if( NULL == function)
+  if(nullptr == function)
   {
     DALI_LOG_WARNING("Connector function is empty\n");
   }
   else
   {
-    ConnectorContainer::iterator iter = find_if( mSignalConnectors.begin(), mSignalConnectors.end(),
-                                                   PairFinder<std::string, ConnectionPair>(signalName) );
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+    if(!mSignalConnectors.Register(ConstString(signalName), function))
+    {
+      DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function\n", signalName.c_str());
+    }
+#else
+    ConnectorContainer::iterator iter = find_if(mSignalConnectors.begin(), mSignalConnectors.end(), PairFinder<std::string, ConnectionPair>(signalName));
 
-    if( iter == mSignalConnectors.end() )
+    if(iter == mSignalConnectors.end())
     {
-      mSignalConnectors.push_back( ConnectionPair( signalName, function ) );
+      mSignalConnectors.push_back(ConnectionPair(std::move(signalName), function));
     }
     else
     {
-      DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function", signalName.c_str());
+      DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function\n", signalName.c_str());
     }
+#endif
   }
 }
 
-void TypeInfo::AddProperty( const std::string& name, Property::Index index, Property::Type type, Dali::TypeInfo::SetPropertyFunction setFunc, Dali::TypeInfo::GetPropertyFunction getFunc )
+void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Type type, Dali::TypeInfo::SetPropertyFunction setFunc, Dali::TypeInfo::GetPropertyFunction getFunc)
 {
   // The setter can be empty as a property can be read-only.
 
-  if ( NULL == getFunc )
+  if(nullptr == getFunc)
   {
-    DALI_ASSERT_ALWAYS( ! "GetProperty Function is empty" );
+    DALI_ASSERT_ALWAYS(!"GetProperty Function is empty");
   }
   else
   {
-    RegisteredPropertyContainer::iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
-                                                          PairFinder< Property::Index, RegisteredPropertyPair>(index) );
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+    if(!mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
+    {
+      DALI_ASSERT_ALWAYS(!"Property index already added to Type");
+    }
+#else
+    RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+    if(iter == mRegisteredProperties.end())
+    {
+      mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
+    }
+    else
+    {
+      DALI_ASSERT_ALWAYS(!"Property index already added to Type");
+    }
+#endif
+  }
+}
+
+void TypeInfo::AddProperty(std::string name, Property::Index index, Property::Type type, Dali::CSharpTypeInfo::SetPropertyFunction setFunc, Dali::CSharpTypeInfo::GetPropertyFunction getFunc)
+{
+  // The setter can be empty as a property can be read-only.
 
-    if ( iter == mRegisteredProperties.end() )
+  if(nullptr == getFunc)
+  {
+    DALI_ASSERT_ALWAYS(!"GetProperty Function is empty");
+  }
+  else
+  {
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+    if(!mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
     {
-      mRegisteredProperties.push_back( RegisteredPropertyPair( index, RegisteredProperty( type, setFunc, getFunc, name ) ) );
+      DALI_ASSERT_ALWAYS(!"Property index already added to Type");
+    }
+#else
+    RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+    if(iter == mRegisteredProperties.end())
+    {
+      mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, setFunc, getFunc, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
     }
     else
     {
-      DALI_ASSERT_ALWAYS( ! "Property index already added to Type" );
+      DALI_ASSERT_ALWAYS(!"Property index already added to Type");
     }
+#endif
   }
 }
 
-unsigned int TypeInfo::GetPropertyCount() const
+void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Property::Type type)
 {
-  unsigned int count( mRegisteredProperties.size() );
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  if(!mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
+  {
+    DALI_ASSERT_ALWAYS(!"Property index already added to Type");
+  }
+#else
+  RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+  if(iter == mRegisteredProperties.end())
+  {
+    mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
+  }
+  else
+  {
+    DALI_ASSERT_ALWAYS(!"Property index already added to Type");
+  }
+#endif
+}
 
-  Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
-  while ( base )
+void TypeInfo::AddAnimatableProperty(std::string name, Property::Index index, Property::Value defaultValue)
+{
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  if(!mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(defaultValue.GetType(), ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
   {
-    const TypeInfo& baseImpl( GetImplementation(base) );
-    count += baseImpl.mRegisteredProperties.size();
-    base = TypeRegistry::Get()->GetTypeInfo( baseImpl.mBaseTypeName );
+    DALI_ASSERT_ALWAYS(!"Property index already added to Type");
+  }
+  else
+  {
+    mPropertyDefaultValues.Register(static_cast<std::uint32_t>(index), std::move(defaultValue));
+  }
+#else
+  RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+  if(iter == mRegisteredProperties.end())
+  {
+    mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(defaultValue.GetType(), ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
+    mPropertyDefaultValues.push_back(PropertyDefaultValuePair(index, std::move(defaultValue)));
+  }
+  else
+  {
+    DALI_ASSERT_ALWAYS(!"Property index already added to Type");
+  }
+#endif
+}
+
+void TypeInfo::AddAnimatablePropertyComponent(std::string name, Property::Index index, Property::Index baseIndex, uint32_t componentIndex)
+{
+  Property::Type type = GetPropertyType(baseIndex);
+  DALI_ASSERT_ALWAYS((type == Property::VECTOR2 || type == Property::VECTOR3 || type == Property::VECTOR4) && "Base property does not support component");
+
+  bool success = false;
+
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  if(mRegisteredProperties.Get(static_cast<std::uint32_t>(index)) == mRegisteredProperties.end())
+  {
+    const auto& iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyComponentFinder<RegisteredPropertyPair>(baseIndex, componentIndex));
+
+    if(iter == mRegisteredProperties.end())
+    {
+      mRegisteredProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, ConstString(name), baseIndex, componentIndex));
+      success = true;
+    }
+  }
+#else
+  RegisteredPropertyContainer::iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+  if(iter == mRegisteredProperties.end())
+  {
+    iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyComponentFinder<RegisteredPropertyPair>(baseIndex, componentIndex));
+
+    if(iter == mRegisteredProperties.end())
+    {
+      mRegisteredProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), baseIndex, componentIndex)));
+      success = true;
+    }
+  }
+#endif
+
+  DALI_ASSERT_ALWAYS(success && "Property component already registered");
+}
+
+void TypeInfo::AddChildProperty(std::string name, Property::Index index, Property::Type type)
+{
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  if(!mRegisteredChildProperties.Register(static_cast<std::uint32_t>(index), RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)))
+#else
+  RegisteredPropertyContainer::iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+  if(iter == mRegisteredChildProperties.end())
+  {
+    mRegisteredChildProperties.push_back(RegisteredPropertyPair(index, RegisteredProperty(type, ConstString(name), Property::INVALID_INDEX, Property::INVALID_COMPONENT_INDEX)));
+  }
+  else
+#endif
+  {
+    DALI_ASSERT_ALWAYS(!"Property index already added to Type");
+  }
+}
+
+uint32_t TypeInfo::GetPropertyCount() const
+{
+  uint32_t count = mDefaultPropertyCount + static_cast<uint32_t>(mRegisteredProperties.size());
+
+  if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    count += mBaseType->GetPropertyCount();
   }
 
   return count;
 }
 
-Property::Index TypeInfo::GetPropertyIndex( const std::string& name ) const
+Property::Index TypeInfo::GetPropertyIndex(ConstString name) const
+{
+  Property::Index index = Property::INVALID_INDEX;
+  bool            found = false;
+
+  // check default properties
+  if(mDefaultProperties)
+  {
+    auto stringView = name.GetStringView();
+    for(Property::Index tableIndex = 0; tableIndex < mDefaultPropertyCount; ++tableIndex)
+    {
+      if(mDefaultProperties[tableIndex].name == stringView)
+      {
+        index = mDefaultProperties[tableIndex].enumIndex;
+        found = true;
+        break;
+      }
+    }
+  }
+  if(!found)
+  {
+    // Slow but should not be done that often
+    RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyNameFinder<RegisteredPropertyPair>(name));
+    if(iter != mRegisteredProperties.end())
+    {
+      index = iter->first;
+    }
+    else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+    {
+      // call base type recursively
+      index = mBaseType->GetPropertyIndex(name);
+    }
+  }
+
+  return index;
+}
+
+Property::Index TypeInfo::GetBasePropertyIndex(Property::Index index) const
+{
+  Property::Index basePropertyIndex = Property::INVALID_INDEX;
+
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
+#else
+  RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
+  if(iter != mRegisteredProperties.end())
+  {
+    basePropertyIndex = iter->second.basePropertyIndex;
+  }
+  else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    basePropertyIndex = mBaseType->GetBasePropertyIndex(index);
+  }
+
+  return basePropertyIndex;
+}
+
+int32_t TypeInfo::GetComponentIndex(Property::Index index) const
+{
+  int componentIndex = Property::INVALID_COMPONENT_INDEX;
+
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
+#else
+  RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
+  if(iter != mRegisteredProperties.end())
+  {
+    componentIndex = iter->second.componentIndex;
+  }
+  else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    componentIndex = mBaseType->GetComponentIndex(index);
+  }
+
+  return componentIndex;
+}
+
+Property::Index TypeInfo::GetChildPropertyIndex(ConstString name) const
 {
   Property::Index index = Property::INVALID_INDEX;
 
   // Slow but should not be done that often
-  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
-                                                          PropertyNameFinder< RegisteredPropertyPair >( name ) );
+  RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PropertyNameFinder<RegisteredPropertyPair>(name));
 
-  if ( iter != mRegisteredProperties.end() )
+  if(iter != mRegisteredChildProperties.end())
   {
     index = iter->first;
   }
-  else
+  else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
   {
-    Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
-    if ( base )
-    {
-      index = GetImplementation(base).GetPropertyIndex( name );
-    }
+    // call base type recursively
+    index = mBaseType->GetChildPropertyIndex(name);
   }
 
   return index;
 }
 
-bool TypeInfo::IsPropertyWritable( Property::Index index ) const
+std::string_view TypeInfo::GetChildPropertyName(Property::Index index) const
 {
-  bool writable( false );
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  const auto& iter = mRegisteredChildProperties.Get(static_cast<std::uint32_t>(index));
+#else
+  RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
+  if(iter != mRegisteredChildProperties.end())
+  {
+    return iter->second.name.GetStringView();
+  }
+
+  if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    return mBaseType->GetChildPropertyName(index);
+  }
 
-  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
-                                                          PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
+  DALI_LOG_ERROR("Property index %d not found\n", index);
 
-  if ( iter != mRegisteredProperties.end() )
+  return {};
+}
+
+Property::Type TypeInfo::GetChildPropertyType(Property::Index index) const
+{
+  Property::Type type(Property::NONE);
+
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  const auto& iter = mRegisteredChildProperties.Get(static_cast<std::uint32_t>(index));
+#else
+  RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredChildProperties.begin(), mRegisteredChildProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
+  if(iter != mRegisteredChildProperties.end())
+  {
+    type = iter->second.type;
+  }
+  else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    type = mBaseType->GetChildPropertyType(index);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Property index %d not found\n", index);
+  }
+
+  return type;
+}
+
+bool TypeInfo::IsPropertyWritable(Property::Index index) const
+{
+  bool writable = false;
+  bool found    = false;
+
+  // default property?
+  if((index < DEFAULT_PROPERTY_MAX_COUNT) && mDefaultProperties)
   {
-    writable = iter->second.setFunc ? true : false;
+    found = GetDefaultPropertyField(mDefaultProperties, mDefaultPropertyCount, index, &Dali::PropertyDetails::writable, writable);
+  }
+  else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
+  {
+    writable = true; // animatable property is writable
+    found    = true;
   }
   else
   {
-    Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
-    if ( base )
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+    const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
+#else
+    RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
+    if(iter != mRegisteredProperties.end())
+    {
+      writable = iter->second.setFunc ? true : false;
+      found    = true;
+    }
+  }
+
+  // if not found, continue to base
+  if(!found)
+  {
+    if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
     {
-      writable = GetImplementation(base).IsPropertyWritable( index );
+      // call base type recursively
+      writable = mBaseType->IsPropertyWritable(index);
     }
     else
     {
-      DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
+      DALI_LOG_ERROR("Property index %d not found\n", index);
     }
   }
 
   return writable;
 }
 
-Property::Type TypeInfo::GetPropertyType( Property::Index index ) const
+bool TypeInfo::IsPropertyAnimatable(Property::Index index) const
 {
-  Property::Type type( Property::NONE );
-
-  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
-                                                          PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
+  bool animatable = false;
+  bool found      = false;
 
-  if ( iter != mRegisteredProperties.end() )
+  // default property?
+  if((index < DEFAULT_PROPERTY_MAX_COUNT) && mDefaultProperties)
   {
-    type = iter->second.type;
+    found = GetDefaultPropertyField(mDefaultProperties, mDefaultPropertyCount, index, &Dali::PropertyDetails::animatable, animatable);
   }
-  else
+  else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
+  {
+    // Type Registry event-thread only properties are not animatable.
+    animatable = false;
+    found      = true;
+  }
+  else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
   {
-    Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
-    if ( base )
+    animatable = true;
+    found      = true;
+  }
+
+  // if not found, continue to base
+  if(!found)
+  {
+    if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
     {
-      type = GetImplementation(base).GetPropertyType( index );
+      // call base type recursively
+      animatable = mBaseType->IsPropertyAnimatable(index);
     }
     else
     {
-      DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
+      DALI_LOG_ERROR("Property index %d not found\n", index);
     }
   }
 
-  return type;
+  return animatable;
 }
 
-void TypeInfo::SetProperty( BaseObject *object, Property::Index index, const Property::Value& value ) const
+bool TypeInfo::IsPropertyAConstraintInput(Property::Index index) const
 {
-  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
-                                                              PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
-  if ( iter != mRegisteredProperties.end() )
+  bool constraintInput = false;
+  bool found           = false;
+
+  // default property?
+  if((index < DEFAULT_PROPERTY_MAX_COUNT) && mDefaultProperties)
+  {
+    found = GetDefaultPropertyField(mDefaultProperties, mDefaultPropertyCount, index, &Dali::PropertyDetails::constraintInput, constraintInput);
+  }
+  else if((index >= PROPERTY_REGISTRATION_START_INDEX) && (index <= PROPERTY_REGISTRATION_MAX_INDEX))
+  {
+    // Type Registry event-thread only properties cannot be used as constraint input
+    constraintInput = false;
+    found           = true;
+  }
+  else if((index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX) && (index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX))
+  {
+    constraintInput = true;
+    found           = true;
+  }
+
+  // if not found, continue to base
+  if(!found)
   {
-    if( iter->second.setFunc )
+    if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
     {
-      iter->second.setFunc( object, index, value );
+      // call base type recursively
+      constraintInput = mBaseType->IsPropertyAConstraintInput(index);
     }
+    else
+    {
+      DALI_LOG_ERROR("Property index %d not found\n", index);
+    }
+  }
+
+  return constraintInput;
+}
+
+Property::Type TypeInfo::GetPropertyType(Property::Index index) const
+{
+  Property::Type type(Property::NONE);
+  bool           found = false;
+
+  // default property?
+  if((index < DEFAULT_PROPERTY_MAX_COUNT) && mDefaultProperties)
+  {
+    found = GetDefaultPropertyField(mDefaultProperties, mDefaultPropertyCount, index, &Dali::PropertyDetails::type, type);
   }
   else
   {
-    Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
-    if ( base )
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+    const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
+#else
+    RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
+    if(iter != mRegisteredProperties.end())
     {
-      GetImplementation(base).SetProperty( object, index, value );
+      if(iter->second.componentIndex == Property::INVALID_COMPONENT_INDEX)
+      {
+        type  = iter->second.type;
+        found = true;
+      }
+      else
+      {
+        // If component index is set, then we should return FLOAT
+        type  = Property::FLOAT;
+        found = true;
+      }
+    }
+  }
+
+  if(!found)
+  {
+    if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+    {
+      // call base type recursively
+      type = mBaseType->GetPropertyType(index);
     }
     else
     {
-      DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
+      DALI_LOG_ERROR("Property index %d not found\n", index);
     }
   }
+
+  return type;
+}
+
+Property::Value TypeInfo::GetPropertyDefaultValue(Property::Index index) const
+{
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  const auto& iter = mPropertyDefaultValues.Get(static_cast<std::uint32_t>(index));
+#else
+  PropertyDefaultValueContainer::const_iterator iter = find_if(mPropertyDefaultValues.begin(), mPropertyDefaultValues.end(), PairFinder<Property::Index, PropertyDefaultValuePair>(index));
+#endif
+  if(iter != mPropertyDefaultValues.end())
+  {
+    return iter->second;
+  }
+  // we didn't have a value so ask base
+  if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    return mBaseType->GetPropertyDefaultValue(index);
+  }
+  return Property::Value(); // return none
 }
 
-void TypeInfo::SetProperty( BaseObject *object, const std::string& name, const Property::Value& value ) const
+void TypeInfo::SetProperty(BaseObject* object, Property::Index index, Property::Value value) const
 {
-  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
-                                                              PropertyNameFinder< RegisteredPropertyPair >( name ) );
-  if ( iter != mRegisteredProperties.end() )
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
+#else
+  RegisteredPropertyContainer::const_iterator   iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
+  if(iter != mRegisteredProperties.end())
   {
-    DALI_ASSERT_ALWAYS( iter->second.setFunc && "Trying to write to a read-only property" );
-    iter->second.setFunc( object, iter->first, value );
+    if(iter->second.setFunc)
+    {
+      if(mCSharpType)
+      {
+        // CSharp wants a property name not an index
+        auto name = (iter->second).name;
+
+        iter->second.cSharpSetFunc(object, name.GetCString(), const_cast<Property::Value*>(&value));
+      }
+      else
+      {
+        iter->second.setFunc(object, index, std::move(value));
+      }
+    }
+  }
+  else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    mBaseType->SetProperty(object, index, std::move(value));
   }
   else
   {
-    Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
-    if ( base )
+    DALI_LOG_ERROR("Property index %d not found\n", index);
+  }
+}
+
+void TypeInfo::SetProperty(BaseObject* object, const std::string& name, Property::Value value) const
+{
+  // Slow but should not be done that often
+  RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyNameFinder<RegisteredPropertyPair>(ConstString(name)));
+  if(iter != mRegisteredProperties.end())
+  {
+    DALI_ASSERT_ALWAYS(iter->second.setFunc && "Trying to write to a read-only property");
+
+    if(mCSharpType)
     {
-      GetImplementation(base).SetProperty( object, name, value );
+      // CSharp wants a property name not an index
+      iter->second.cSharpSetFunc(object, name.c_str(), const_cast<Property::Value*>(&value));
     }
     else
     {
-      DALI_ASSERT_ALWAYS( ! "Cannot find property name" );
+      iter->second.setFunc(object, iter->first, std::move(value));
     }
   }
+  else if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
+  {
+    // call base type recursively
+    mBaseType->SetProperty(object, name, std::move(value));
+  }
+  else
+  {
+    DALI_LOG_ERROR("Property %s not found", name.c_str());
+  }
 }
 
-Property::Value TypeInfo::GetProperty( const BaseObject *object, Property::Index index ) const
+Property::Value TypeInfo::GetProperty(const BaseObject* object, Property::Index index) const
 {
-  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
-                                                          PairFinder< Property::Index, RegisteredPropertyPair >( index ) );
-  if( iter != mRegisteredProperties.end() )
+#ifdef USE_INDEXED_MAP_CONTAINER_AT_TYPE_INFO
+  const auto& iter = mRegisteredProperties.Get(static_cast<std::uint32_t>(index));
+#else
+  RegisteredPropertyContainer::const_iterator   iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PairFinder<Property::Index, RegisteredPropertyPair>(index));
+#endif
+  if(iter != mRegisteredProperties.end())
   {
-    // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
-    return iter->second.getFunc( const_cast< BaseObject* >( object ), index );
+    if(mCSharpType) // using csharp property get which returns a pointer to a Property::Value
+    {
+      // CSharp wants a property name not an index
+      // CSharp callback can't return an object by value, it can only return a pointer
+      // CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
+      auto name = (iter->second).name;
+
+      return *(iter->second.cSharpGetFunc(const_cast<BaseObject*>(object), name.GetCString()));
+    }
+    else
+    {
+      // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
+      return iter->second.getFunc(const_cast<BaseObject*>(object), index);
+    }
   }
 
-  Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
-  if ( base )
+  if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
   {
-    return GetImplementation( base ).GetProperty( object, index );
+    // call base type recursively
+    return mBaseType->GetProperty(object, index);
   }
 
-  DALI_ASSERT_ALWAYS( ! "Cannot find property index" ); // use the same assert as Object
+  DALI_LOG_ERROR("Property index %d not found\n", index);
+  return Property::Value();
 }
 
-Property::Value TypeInfo::GetProperty( const BaseObject *object, const std::string& name ) const
+Property::Value TypeInfo::GetProperty(const BaseObject* object, const std::string& name) const
 {
-  RegisteredPropertyContainer::const_iterator iter = find_if( mRegisteredProperties.begin(), mRegisteredProperties.end(),
-                                                          PropertyNameFinder< RegisteredPropertyPair >( name ) );
-  if( iter != mRegisteredProperties.end() )
+  RegisteredPropertyContainer::const_iterator iter = find_if(mRegisteredProperties.begin(), mRegisteredProperties.end(), PropertyNameFinder<RegisteredPropertyPair>(ConstString(name)));
+
+  if(iter != mRegisteredProperties.end())
   {
-    // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
-    return iter->second.getFunc( const_cast< BaseObject* >( object ), iter->first );
+    if(mCSharpType) // using csharp property get which returns a pointer to a Property::Value
+    {
+      // CSharp wants a property name not an index
+      // CSharp callback can't return an object by value, it can only return a pointer
+      // CSharp has ownership of the pointer contents, which is fine because we are returning by from this function by value
+      return *(iter->second.cSharpGetFunc(const_cast<BaseObject*>(object), name.c_str()));
+    }
+    else
+    {
+      // Need to remove the constness here as CustomActor will not be able to call Downcast with a const pointer to the object
+      return iter->second.getFunc(const_cast<BaseObject*>(object), iter->first);
+    }
   }
 
-  Dali::TypeInfo base = TypeRegistry::Get()->GetTypeInfo( mBaseTypeName );
-  if ( base )
+  if(GetBaseType(mBaseType, mTypeRegistry, mBaseTypeName))
   {
-    return GetImplementation( base ).GetProperty( object, name );
+    // call base type recursively
+    return mBaseType->GetProperty(object, name);
   }
 
-  DALI_ASSERT_ALWAYS( ! "Cannot find property name" );
+  DALI_LOG_ERROR("Property %s not found", name.c_str());
+  return Property::Value();
 }
 
 } // namespace Internal