Add QgsFeature::approximateMemoryUsage()

This commit is contained in:
Even Rouault 2020-10-17 17:31:19 +02:00 committed by Nyall Dawson
parent 7ac4b51885
commit a04fcce548
4 changed files with 81 additions and 0 deletions

View File

@ -547,6 +547,17 @@ before this method can be used.
:return: -1 if field does not exist or field map is not associated.
.. seealso:: :py:func:`setFields`
%End
int approximateMemoryUsage() const;
%Docstring
Returns the approximate RAM usage of the feature, in bytes.
This method takes into account the size of variable elements (strings,
geometry, ...), but the value returned should be considered as a lower
bound estimation.
.. versionadded:: 3.16
%End
operator QVariant() const;

View File

@ -18,6 +18,8 @@ email : sherman at mrcc.com
#include "qgsfields.h"
#include "qgsgeometry.h"
#include "qgsrectangle.h"
#include "qgsfield_p.h" // for approximateMemoryUsage()
#include "qgsfields_p.h" // for approximateMemoryUsage()
#include "qgsmessagelog.h"
@ -279,6 +281,58 @@ int QgsFeature::fieldNameIndex( const QString &fieldName ) const
return d->fields.lookupField( fieldName );
}
static size_t qgsQStringApproximateMemoryUsage( const QString &str )
{
return sizeof( QString ) + str.size() * sizeof( QChar );
}
static size_t qgsQVariantApproximateMemoryUsage( const QVariant &v )
{
// A QVariant has a private structure that is a union of things whose larger
// size if a long long, and a int
size_t s = sizeof( QVariant ) + sizeof( long long ) + sizeof( int );
if ( v.type() == QVariant::String )
{
s += qgsQStringApproximateMemoryUsage( v.toString() );
}
else if ( v.type() == QVariant::StringList )
{
for ( const QString &str : v.toStringList() )
s += qgsQStringApproximateMemoryUsage( str );
}
else if ( v.type() == QVariant::List )
{
for ( const QVariant &subV : v.toList() )
s += qgsQVariantApproximateMemoryUsage( subV );
}
return s;
}
int QgsFeature::approximateMemoryUsage() const
{
size_t s = sizeof( *this ) + sizeof( *d );
// Attributes
for ( const QVariant &attr : qgis::as_const( d->attributes ) )
{
s += qgsQVariantApproximateMemoryUsage( attr );
}
// Geometry
s += sizeof( QAtomicInt ) + sizeof( void * ); // ~ sizeof(QgsGeometryPrivate)
// For simplicity we consider that the RAM usage is the one of the WKB
// representation
s += d->geometry.wkbSize();
// Fields
s += sizeof( QgsFieldsPrivate );
// TODO potentially: take into account the length of the name, comment, default value, etc...
s += d->fields.size() * ( sizeof( QgsField ) + sizeof( QgsFieldPrivate ) );
return static_cast<int>( s );
}
/***************************************************************************
* This class is considered CRITICAL and any change MUST be accompanied with
* full unit tests in testqgsfeature.cpp.

View File

@ -536,6 +536,17 @@ class CORE_EXPORT QgsFeature
*/
int fieldNameIndex( const QString &fieldName ) const;
/**
* Returns the approximate RAM usage of the feature, in bytes.
*
* This method takes into account the size of variable elements (strings,
* geometry, ...), but the value returned should be considered as a lower
* bound estimation.
*
* \since QGIS 3.16
*/
int approximateMemoryUsage() const;
//! Allows direct construction of QVariants from features.
operator QVariant() const
{

View File

@ -124,6 +124,7 @@ void TestQgsFeature::attributesTest()
void TestQgsFeature::constructorTest()
{
QgsFeature f;
QVERIFY( f.approximateMemoryUsage() > 0 );
QVERIFY( FID_IS_NULL( f.id() ) );
QgsFeature f2 { QgsFields() };
QVERIFY( FID_IS_NULL( f2.id() ) );
@ -222,6 +223,7 @@ void TestQgsFeature::attributes()
feature.setAttributes( mAttrs );
QCOMPARE( feature.attributes(), mAttrs );
QCOMPARE( feature.attributes(), mAttrs );
QVERIFY( feature.approximateMemoryUsage() > QgsFeature().approximateMemoryUsage() );
//test implicit sharing detachment
QgsFeature copy( feature );
@ -286,6 +288,7 @@ void TestQgsFeature::geometry()
//test no double delete of geometry when setting:
feature.setGeometry( QgsGeometry( mGeometry2 ) );
QVERIFY( feature.hasGeometry() );
QVERIFY( feature.approximateMemoryUsage() > QgsFeature().approximateMemoryUsage() );
feature.setGeometry( QgsGeometry( mGeometry ) );
QCOMPARE( feature.geometry().asWkb(), mGeometry.asWkb() );
@ -355,6 +358,8 @@ void TestQgsFeature::fields()
QVERIFY( original.fields().isEmpty() );
original.setFields( mFields );
QCOMPARE( original.fields(), mFields );
QVERIFY( original.approximateMemoryUsage() > QgsFeature().approximateMemoryUsage() );
QgsFeature copy( original );
QCOMPARE( copy.fields(), original.fields() );