qskinny/src/common/QskObjectCounter.cpp

231 lines
5.5 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"
#include <QQuickItem>
#include <QSet>
#include <QDebug>
QSK_QT_PRIVATE_BEGIN
#include <private/qhooks_p.h>
#include <private/qquickitem_p.h>
#include <private/qobject_p.h>
QSK_QT_PRIVATE_END
static struct
{
QHooks::StartupCallback startup;
QHooks::AddQObjectCallback addObject;
QHooks::RemoveQObjectCallback removeObject;
} qskOtherHooks;
2017-07-21 18:21:34 +02:00
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.
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;
}
class QskObjectCounterHook
{
public:
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 ) );
}
void startup() const
{
#if 0
qDebug() << "** QskObjectCounterHook enabled";
#endif
}
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 );
}
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 );
}
private:
QSet< QskObjectCounter* > m_counterSet;
};
static QskObjectCounterHook* qskCounterHook();
static void qskStartupHook()
{
qskCounterHook()->startup();
if ( qskOtherHooks.startup )
qskOtherHooks.startup();
2017-07-21 18:21:34 +02:00
}
static void qskAddObjectHook( QObject* object )
{
qskCounterHook()->addObject( object );
if ( qskOtherHooks.addObject )
qskOtherHooks.addObject( object );
2017-07-21 18:21:34 +02:00
}
static void qskRemoveObjectHook( QObject* object )
{
qskCounterHook()->removeObject( object );
if ( qskOtherHooks.removeObject )
qskOtherHooks.removeObject( object );
2017-07-21 18:21:34 +02:00
}
static QskObjectCounterHook* qskCounterHook()
{
static bool isInitialized = false;
2017-07-21 18:21:34 +02:00
if ( !isInitialized )
2017-07-21 18:21:34 +02:00
{
qskOtherHooks.startup = reinterpret_cast< QHooks::StartupCallback >( qtHookData[QHooks::Startup] );
qskOtherHooks.addObject = reinterpret_cast< QHooks::AddQObjectCallback >( qtHookData[QHooks::AddQObject] );
qskOtherHooks.removeObject = reinterpret_cast< QHooks::RemoveQObjectCallback >( qtHookData[QHooks::RemoveQObject] );
2017-07-21 18:21:34 +02:00
qtHookData[QHooks::Startup] = reinterpret_cast< quintptr >( &qskStartupHook );
qtHookData[QHooks::AddQObject] = reinterpret_cast< quintptr >( &qskAddObjectHook );
qtHookData[QHooks::RemoveQObject] = reinterpret_cast< quintptr >( &qskRemoveObjectHook );
isInitialized = true;
2017-07-21 18:21:34 +02:00
}
static QskObjectCounterHook counterHook;
return &counterHook;
2017-07-21 18:21:34 +02:00
}
QskObjectCounter::QskObjectCounter( bool debugAtDestruction ):
m_debugAtDestruction( debugAtDestruction )
{
setActive( true );
}
QskObjectCounter::~QskObjectCounter()
{
setActive( false );
if ( m_debugAtDestruction )
dump();
}
void QskObjectCounter::setActive( bool on )
{
qskCounterHook()->registerCounter( this, on );
}
bool QskObjectCounter::isActive() const
{
return qskCounterHook()->isCounterRegistered( this );
}
void QskObjectCounter::addObject( QObject* object )
{
m_counter[Objects].increment();
if ( qskIsItem( object ) )
m_counter[Items].increment();
}
void QskObjectCounter::removeObject( QObject* object )
{
m_counter[Objects].decrement();
if ( qskIsItem( object ) )
m_counter[Items].decrement();
}
void QskObjectCounter::reset()
{
m_counter[Objects].reset();
m_counter[Items].reset();
}
int QskObjectCounter::created( ObjectType objectType ) const
{
2017-10-30 08:08:58 +01:00
return m_counter[objectType].created;
2017-07-21 18:21:34 +02:00
}
int QskObjectCounter::destroyed( ObjectType objectType ) const
{
2017-10-30 08:08:58 +01:00
return m_counter[objectType].destroyed;
2017-07-21 18:21:34 +02:00
}
int QskObjectCounter::current( ObjectType objectType ) const
{
2017-10-30 08:08:58 +01:00
return m_counter[objectType].current;
2017-07-21 18:21:34 +02:00
}
int QskObjectCounter::maximum( ObjectType objectType ) const
{
2017-10-30 08:08:58 +01:00
return m_counter[objectType].maximum;
2017-07-21 18:21:34 +02:00
}
void QskObjectCounter::debugStatistics( QDebug debug, ObjectType objectType ) const
{
const Counter& c = m_counter[objectType];
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