qskinny/src/common/QskObjectCounter.cpp

274 lines
6.6 KiB
C++
Raw Normal View History

2017-07-21 18:21:34 +02:00
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskObjectCounter.h"
2018-07-19 14:10:48 +02:00
#include <qdebug.h>
2018-08-03 08:15:28 +02:00
#include <qset.h>
2017-07-21 18:21:34 +02:00
QSK_QT_PRIVATE_BEGIN
#include <private/qhooks_p.h>
#include <private/qobject_p.h>
2018-08-03 08:15:28 +02:00
#include <private/qquickitem_p.h>
2017-07-21 18:21:34 +02:00
QSK_QT_PRIVATE_END
static inline bool qskIsItem( const QObject* object )
{
QObjectPrivate* o_p = QObjectPrivate::get( const_cast< QObject* >( object ) );
/*
The addObject hook is called from the constructor of QObject,
where we don't have the derived class constructed yet.
2018-02-07 15:40:05 +01:00
So we can't cast the object itself and also have to rely on
RTTI being enabled. TODO ...
*/
2017-07-21 18:21:34 +02:00
return dynamic_cast< QQuickItemPrivate* >( o_p ) != nullptr;
}
2018-02-07 15:40:05 +01:00
static void qskStartupHook();
static void qskAddObjectHook( QObject* );
static void qskRemoveObjectHook( QObject* );
2017-07-21 18:21:34 +02:00
class QskObjectCounterHook
{
2018-08-03 08:15:28 +02:00
public:
2018-02-07 15:40:05 +01:00
QskObjectCounterHook()
{
2018-08-03 08:15:28 +02:00
m_otherStartup = qtHookData[ QHooks::Startup ];
m_otherAddObject = qtHookData[ QHooks::AddQObject ];
m_otherRemoveObject = qtHookData[ QHooks::RemoveQObject ];
2018-02-07 15:40:05 +01:00
2018-08-03 08:15:28 +02:00
qtHookData[ QHooks::Startup ] = reinterpret_cast< quintptr >( &qskStartupHook );
qtHookData[ QHooks::AddQObject ] = reinterpret_cast< quintptr >( &qskAddObjectHook );
qtHookData[ QHooks::RemoveQObject ] = reinterpret_cast< quintptr >( &qskRemoveObjectHook );
2018-02-07 15:40:05 +01:00
}
~QskObjectCounterHook()
{
2018-08-03 08:15:28 +02:00
qtHookData[ QHooks::Startup ] = m_otherStartup;
qtHookData[ QHooks::AddQObject ] = m_otherAddObject;
qtHookData[ QHooks::RemoveQObject ] = m_otherRemoveObject;
2018-02-07 15:40:05 +01:00
}
2017-07-21 18:21:34 +02:00
void registerCounter( QskObjectCounter* counter, bool on )
{
if ( on )
m_counterSet.insert( counter );
else
m_counterSet.remove( counter );
}
bool isCounterRegistered( const QskObjectCounter* counter ) const
{
return m_counterSet.contains( const_cast< QskObjectCounter* >( counter ) );
}
2018-02-07 15:40:05 +01:00
bool isActive() const
{
return !m_counterSet.isEmpty();
}
void startup()
2017-07-21 18:21:34 +02:00
{
#if 0
qDebug() << "** QskObjectCounterHook enabled";
#endif
2018-02-07 15:40:05 +01:00
if ( m_otherStartup )
reinterpret_cast< QHooks::StartupCallback >( m_otherStartup )();
2017-07-21 18:21:34 +02:00
}
void addObject( QObject* object )
{
2017-10-30 14:38:30 +01:00
for ( auto counter : qskAsConst( m_counterSet ) )
2017-07-21 18:21:34 +02:00
counter->addObject( object );
2018-02-07 15:40:05 +01:00
if ( m_otherAddObject )
reinterpret_cast< QHooks::AddQObjectCallback >( m_otherAddObject )( object );
2017-07-21 18:21:34 +02:00
}
void removeObject( QObject* object )
{
2017-10-30 14:38:30 +01:00
for ( auto counter : qskAsConst( m_counterSet ) )
2017-07-21 18:21:34 +02:00
counter->removeObject( object );
2018-02-07 15:40:05 +01:00
if ( m_otherRemoveObject )
reinterpret_cast< QHooks::RemoveQObjectCallback >( m_otherRemoveObject )( object );
2017-07-21 18:21:34 +02:00
}
2018-02-07 15:40:05 +01:00
static bool autoDelete;
2018-08-03 08:15:28 +02:00
private:
2017-07-21 18:21:34 +02:00
QSet< QskObjectCounter* > m_counterSet;
2018-02-07 15:40:05 +01:00
quintptr m_otherStartup;
quintptr m_otherAddObject;
quintptr m_otherRemoveObject;
2017-07-21 18:21:34 +02:00
};
2018-02-07 15:40:05 +01:00
bool QskObjectCounterHook::autoDelete = false;
static QskObjectCounterHook* qskCounterHook = nullptr;
2017-07-21 18:21:34 +02:00
static void qskStartupHook()
{
2018-02-07 15:40:05 +01:00
if ( qskCounterHook )
qskCounterHook->startup();
2017-07-21 18:21:34 +02:00
}
static void qskAddObjectHook( QObject* object )
{
2018-02-07 15:40:05 +01:00
if ( qskCounterHook )
qskCounterHook->addObject( object );
2017-07-21 18:21:34 +02:00
}
static void qskRemoveObjectHook( QObject* object )
{
2018-02-07 15:40:05 +01:00
if ( qskCounterHook )
qskCounterHook->removeObject( object );
2017-07-21 18:21:34 +02:00
}
2018-02-07 15:40:05 +01:00
static void qskCleanupHook()
2017-07-21 18:21:34 +02:00
{
2018-02-07 15:40:05 +01:00
if ( qskCounterHook && !qskCounterHook->isActive() )
2017-07-21 18:21:34 +02:00
{
2018-02-07 15:40:05 +01:00
delete qskCounterHook;
qskCounterHook = nullptr;
2017-07-21 18:21:34 +02:00
}
2018-02-07 15:40:05 +01:00
// From now on we remove the hooks as soon as there are no counters
QskObjectCounterHook::autoDelete = true;
2017-07-21 18:21:34 +02:00
}
2018-02-07 15:40:05 +01:00
static void qskInstallCleanupHookHandler()
{
qAddPostRoutine( qskCleanupHook );
}
Q_COREAPP_STARTUP_FUNCTION( qskInstallCleanupHookHandler )
2018-08-03 08:15:28 +02:00
QskObjectCounter::QskObjectCounter( bool debugAtDestruction )
: m_debugAtDestruction( debugAtDestruction )
2017-07-21 18:21:34 +02:00
{
setActive( true );
}
QskObjectCounter::~QskObjectCounter()
{
setActive( false );
if ( m_debugAtDestruction )
dump();
}
void QskObjectCounter::setActive( bool on )
{
2018-02-07 15:40:05 +01:00
if ( on )
{
if ( qskCounterHook == nullptr )
qskCounterHook = new QskObjectCounterHook();
qskCounterHook->registerCounter( this, on );
}
else
{
qskCounterHook->registerCounter( this, on );
if ( !qskCounterHook->isActive() )
{
if ( QskObjectCounterHook::autoDelete )
{
delete qskCounterHook;
qskCounterHook = nullptr;
}
}
}
2017-07-21 18:21:34 +02:00
}
bool QskObjectCounter::isActive() const
{
2018-02-07 15:40:05 +01:00
return qskCounterHook && qskCounterHook->isCounterRegistered( this );
2017-07-21 18:21:34 +02:00
}
void QskObjectCounter::addObject( QObject* object )
{
2018-08-03 08:15:28 +02:00
m_counter[ Objects ].increment();
2017-07-21 18:21:34 +02:00
if ( qskIsItem( object ) )
2018-08-03 08:15:28 +02:00
m_counter[ Items ].increment();
2017-07-21 18:21:34 +02:00
}
void QskObjectCounter::removeObject( QObject* object )
{
2018-08-03 08:15:28 +02:00
m_counter[ Objects ].decrement();
2017-07-21 18:21:34 +02:00
if ( qskIsItem( object ) )
2018-08-03 08:15:28 +02:00
m_counter[ Items ].decrement();
2017-07-21 18:21:34 +02:00
}
void QskObjectCounter::reset()
{
2018-08-03 08:15:28 +02:00
m_counter[ Objects ].reset();
m_counter[ Items ].reset();
2017-07-21 18:21:34 +02:00
}
int QskObjectCounter::created( ObjectType objectType ) const
{
2018-08-03 08:15:28 +02:00
return m_counter[ objectType ].created;
2017-07-21 18:21:34 +02:00
}
int QskObjectCounter::destroyed( ObjectType objectType ) const
{
2018-08-03 08:15:28 +02:00
return m_counter[ objectType ].destroyed;
2017-07-21 18:21:34 +02:00
}
int QskObjectCounter::current( ObjectType objectType ) const
{
2018-08-03 08:15:28 +02:00
return m_counter[ objectType ].current;
2017-07-21 18:21:34 +02:00
}
int QskObjectCounter::maximum( ObjectType objectType ) const
{
2018-08-03 08:15:28 +02:00
return m_counter[ objectType ].maximum;
2017-07-21 18:21:34 +02:00
}
void QskObjectCounter::debugStatistics( QDebug debug, ObjectType objectType ) const
{
2018-08-03 08:15:28 +02:00
const Counter& c = m_counter[ objectType ];
2017-07-21 18:21:34 +02:00
QDebugStateSaver saver( debug );
debug.nospace();
debug << '(';
debug << "created: " << c.created
<< ", destroyed: " << c.destroyed
<< ", current: " << c.current
<< ", maximum: " << c.maximum;
debug << ')';
}
void QskObjectCounter::dump() const
{
QDebug debug = qDebug();
QDebugStateSaver saver( debug );
debug.nospace();
debug << "* Statistics\n";
debug << " Objects: ";
debugStatistics( debug, Objects );
debug << "\n Items: ";
debugStatistics( debug, Items );
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<( QDebug debug, const QskObjectCounter& counter )
{
counter.debugStatistics( debug, QskObjectCounter::Objects );
return debug;
}
#endif