/*
- * 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.
namespace
{
-
-const int INVALID_CALLBACK_INDEX = -1;
-
-// Predicate for std::remove_if algorithm
-bool IsNullPredicate(void* ptr)
-{
- return ptr == NULL;
-}
+const int32_t INVALID_CALLBACK_INDEX = -1;
} // unnamed namespace
namespace Dali
{
-
BaseSignal::BaseSignal()
-: mEmittingFlag( false )
+: mEmittingFlag(false)
{
}
BaseSignal::~BaseSignal()
{
// We can't assert in a destructor
- if( mEmittingFlag )
+ if(mEmittingFlag)
{
- DALI_LOG_ERROR( "Invalid destruction of Signal during Emit()\n" );
+ DALI_LOG_ERROR("Invalid destruction of Signal during Emit()\n");
}
// The signal is being destroyed. We have to inform any slots
// that are connected, that the signal is dead.
- const std::size_t count( mSignalConnections.Count() );
- for( std::size_t i=0; i < count; i++ )
+ const std::size_t count(mSignalConnections.size());
+ for(std::size_t i = 0; i < count; i++)
{
- SignalConnection* connection = mSignalConnections[ i ];
-
- // Note that values are set to NULL in DeleteConnection
- if( connection )
- {
- connection->Disconnect( this );
- delete connection;
- }
- }
-
- mSignalConnections.Clear();
-}
+ auto& connection = mSignalConnections[i];
-bool BaseSignal::Empty() const
-{
- return ( 0 == GetConnectionCount() );
-}
-
-std::size_t BaseSignal::GetConnectionCount() const
-{
- std::size_t count( 0 );
-
- const std::size_t size( mSignalConnections.Count() );
- for( std::size_t i = 0; i < size; ++i )
- {
// Note that values are set to NULL in DeleteConnection
- if ( NULL != mSignalConnections[i] )
- {
- ++count;
- }
- }
-
- return count;
-}
-
-void BaseSignal::Emit()
-{
- // Guards against nested Emit() calls
- EmitGuard guard( mEmittingFlag ); // Guards against nested Emit() calls
- if( guard.ErrorOccurred() )
- {
- return;
- }
-
- // If more connections are added by callbacks, these are ignore until the next Emit()
- // Note that mSignalConnections.Count() count cannot be reduced while iterating
- const std::size_t initialCount( mSignalConnections.Count() );
-
- for( std::size_t i = 0; i < initialCount; ++i )
- {
- CallbackBase* callback( GetCallback(i) );
-
- // Note that connections will be set to NULL when disconnected
- // This is preferable to reducing the connection count while iterating
- if( callback )
+ if(connection)
{
- CallbackBase::Execute( *callback );
+ connection.Disconnect(this);
}
}
-
- // Cleanup NULL values from Connection container
- CleanupConnections();
}
-void BaseSignal::OnConnect( CallbackBase* callback )
+void BaseSignal::OnConnect(CallbackBase* callback)
{
- DALI_ASSERT_ALWAYS( NULL != callback && "Invalid member function pointer passed to Connect()" );
+ DALI_ASSERT_ALWAYS(nullptr != callback && "Invalid member function pointer passed to Connect()");
- int index = FindCallback( callback );
+ int32_t index = FindCallback(callback);
// Don't double-connect the same callback
- if( INVALID_CALLBACK_INDEX == index )
+ if(INVALID_CALLBACK_INDEX == index)
{
// create a new signal connection object, to allow the signal to track the connection.
- SignalConnection* connection = new SignalConnection( callback );
+ //SignalConnection* connection = new SignalConnection(callback);
- mSignalConnections.PushBack( connection );
+ mSignalConnections.push_back(SignalConnection(callback));
}
else
{
}
}
-void BaseSignal::OnDisconnect( CallbackBase* callback )
+void BaseSignal::OnDisconnect(CallbackBase* callback)
{
- DALI_ASSERT_ALWAYS( NULL != callback && "Invalid member function pointer passed to Disconnect()" );
+ DALI_ASSERT_ALWAYS(nullptr != callback && "Invalid member function pointer passed to Disconnect()");
- int index = FindCallback( callback );
+ int32_t index = FindCallback(callback);
- if( index > INVALID_CALLBACK_INDEX )
+ if(index > INVALID_CALLBACK_INDEX)
{
- DeleteConnection( index );
+ DeleteConnection(index);
}
// call back is a temporary created to find which slot should be disconnected.
delete callback;
}
-void BaseSignal::OnConnect( ConnectionTrackerInterface* tracker, CallbackBase* callback )
+void BaseSignal::OnConnect(ConnectionTrackerInterface* tracker, CallbackBase* callback)
{
- DALI_ASSERT_ALWAYS( NULL != tracker && "Invalid ConnectionTrackerInterface pointer passed to Connect()" );
- DALI_ASSERT_ALWAYS( NULL != callback && "Invalid member function pointer passed to Connect()" );
+ DALI_ASSERT_ALWAYS(nullptr != tracker && "Invalid ConnectionTrackerInterface pointer passed to Connect()");
+ DALI_ASSERT_ALWAYS(nullptr != callback && "Invalid member function pointer passed to Connect()");
- int index = FindCallback( callback );
+ int32_t index = FindCallback(callback);
// Don't double-connect the same callback
- if( INVALID_CALLBACK_INDEX == index )
+ if(INVALID_CALLBACK_INDEX == index)
{
// create a new signal connection object, to allow the signal to track the connection.
- SignalConnection* connection = new SignalConnection( tracker, callback );
+ //SignalConnection* connection = new SignalConnection(tracker, callback);
- mSignalConnections.PushBack( connection );
+ mSignalConnections.push_back({tracker, callback});
// Let the connection tracker know that a connection between a signal and a slot has been made.
- tracker->SignalConnected( this, callback );
+ tracker->SignalConnected(this, callback);
}
else
{
}
}
-void BaseSignal::OnDisconnect( ConnectionTrackerInterface* tracker, CallbackBase* callback )
+void BaseSignal::OnDisconnect(ConnectionTrackerInterface* tracker, CallbackBase* callback)
{
- DALI_ASSERT_ALWAYS( NULL != tracker && "Invalid ConnectionTrackerInterface pointer passed to Disconnect()" );
- DALI_ASSERT_ALWAYS( NULL != callback && "Invalid member function pointer passed to Disconnect()" );
+ DALI_ASSERT_ALWAYS(nullptr != tracker && "Invalid ConnectionTrackerInterface pointer passed to Disconnect()");
+ DALI_ASSERT_ALWAYS(nullptr != callback && "Invalid member function pointer passed to Disconnect()");
- int index = FindCallback( callback );
+ int32_t index = FindCallback(callback);
- if( index > INVALID_CALLBACK_INDEX )
+ if(index > INVALID_CALLBACK_INDEX)
{
// temporary pointer to disconnected callback
- CallbackBase* disconnectedCallback = mSignalConnections[index]->GetCallback();
+ CallbackBase* disconnectedCallback = mSignalConnections[index].GetCallback();
// close the signal side connection first.
- DeleteConnection( index );
+ DeleteConnection(index);
// close the slot side connection
- tracker->SignalDisconnected( this, disconnectedCallback );
+ tracker->SignalDisconnected(this, disconnectedCallback);
}
// call back is a temporary created to find which slot should be disconnected.
}
// for SlotObserver::SlotDisconnected
-void BaseSignal::SlotDisconnected( CallbackBase* callback )
+void BaseSignal::SlotDisconnected(CallbackBase* callback)
{
- const std::size_t count( mSignalConnections.Count() );
- for( std::size_t i=0; i < count; ++i )
+ const std::size_t count(mSignalConnections.size());
+ for(std::size_t i = 0; i < count; ++i)
{
- const CallbackBase* connectionCallback = GetCallback( i );
+ const CallbackBase* connectionCallback = GetCallback(i);
// Pointer comparison i.e. SignalConnection contains pointer to same callback instance
- if( connectionCallback &&
- connectionCallback == callback )
+ if(connectionCallback &&
+ connectionCallback == callback)
{
- DeleteConnection( i );
+ DeleteConnection(i);
// Disconnection complete
return;
}
}
- DALI_ASSERT_ALWAYS( false && "Callback lost in SlotDisconnected()" );
+ DALI_ABORT("Callback lost in SlotDisconnected()");
}
-CallbackBase* BaseSignal::GetCallback( std::size_t connectionIndex ) const
-{
- DALI_ASSERT_ALWAYS( connectionIndex < mSignalConnections.Count() && "GetCallback called with invalid index" );
-
- CallbackBase* callback( NULL );
-
- SignalConnection* connection( mSignalConnections[ connectionIndex ] );
-
- // Note that values are set to NULL in DeleteConnection
- if( connection )
- {
- callback = connection->GetCallback();
- }
-
- return callback;
-}
-int BaseSignal::FindCallback( CallbackBase* callback )
+int32_t BaseSignal::FindCallback(CallbackBase* callback) const noexcept
{
- int index( INVALID_CALLBACK_INDEX );
+ int32_t index(INVALID_CALLBACK_INDEX);
// A signal can have multiple slots connected to it.
// We need to search for the slot which has the same call back function (if it's static)
// Or the same object / member function (for non-static)
- const std::size_t count( mSignalConnections.Count() );
- for( std::size_t i=0; i < count; ++i )
+ for(auto i = 0u; i < mSignalConnections.size(); ++i)
{
- const CallbackBase* connectionCallback = GetCallback( i );
+ const CallbackBase* connectionCallback = GetCallback(i);
// Note that values are set to NULL in DeleteConnection
- if( connectionCallback &&
- ( *connectionCallback == *callback ) )
+ if(connectionCallback && (*connectionCallback == *callback))
{
- index = i;
+ index = static_cast<int>(i); // only 2,147,483,647 connections supported, no error check
break;
}
}
return index;
}
-void BaseSignal::DeleteConnection( std::size_t connectionIndex )
+void BaseSignal::DeleteConnection(std::size_t connectionIndex)
{
- DALI_ASSERT_ALWAYS( connectionIndex < mSignalConnections.Count() && "DeleteConnection called with invalid index" );
-
- // delete the object
- SignalConnection* connection( mSignalConnections[ connectionIndex ] );
- delete connection;
- // IMPORTANT - do not remove from items from mSignalConnections, set to NULL instead.
- // Signal Emit() methods require that connection count is not reduced while iterating
- // i.e. DeleteConnection can be called from within callbacks, while iterating through mSignalConnections.
- mSignalConnections[ connectionIndex ] = NULL;
+ if(mEmittingFlag)
+ {
+ // IMPORTANT - do not remove from items from mSignalConnections, reset instead.
+ // Signal Emit() methods require that connection count is not reduced while iterating
+ // i.e. DeleteConnection can be called from within callbacks, while iterating through mSignalConnections.
+ mSignalConnections[connectionIndex] = {nullptr};
+ ++mNullConnections;
+ }
+ else
+ {
+ // If application connects and disconnects without the signal never emitting,
+ // the mSignalConnections vector keeps growing and growing as CleanupConnections() is done from Emit.
+ mSignalConnections.erase(mSignalConnections.begin() + connectionIndex);
+ }
}
void BaseSignal::CleanupConnections()
{
- const std::size_t total = mSignalConnections.Count();
- // only do something if there are items
- if( total > 0 )
+ if(!mSignalConnections.empty())
{
- std::size_t index = 0;
- // process the whole vector
- for( std::size_t i = 0; i < total; ++i )
- {
- if( mSignalConnections[ index ] == NULL )
- {
- // items will be moved so don't increase index (erase will decrease the count of vector)
- mSignalConnections.Erase( mSignalConnections.Begin() + index );
- }
- else
- {
- // increase to next element
- ++index;
- }
- }
+ //Remove Signals that are already markeed nullptr.
+ mSignalConnections.erase(std::remove_if(mSignalConnections.begin(),
+ mSignalConnections.end(),
+ [](auto& elm) { return (elm) ? false : true; }),
+ mSignalConnections.end());
}
+ mNullConnections = 0;
}
// BaseSignal::EmitGuard
-BaseSignal::EmitGuard::EmitGuard( bool& flag )
-: mFlag( NULL )
+BaseSignal::EmitGuard::EmitGuard(bool& flag)
+: mFlag(nullptr)
{
- if( !flag )
+ if(!flag)
{
mFlag = &flag;
- flag = true;
+ flag = true;
}
else
{
// mFlag is NULL when Emit() is called during Emit()
- DALI_LOG_ERROR( "Cannot call Emit() from inside Emit()" );
+ DALI_LOG_ERROR("Cannot call Emit() from inside Emit()\n");
}
}
BaseSignal::EmitGuard::~EmitGuard()
{
- if( mFlag )
+ if(mFlag)
{
*mFlag = false;
}
bool BaseSignal::EmitGuard::ErrorOccurred()
{
// mFlag is NULL when Emit() is called during Emit()
- return (NULL == mFlag);
+ return (nullptr == mFlag);
}
} // namespace Dali