From 77e339e53e9fe16736e5195c6cfcdbfddc4cedd4 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 1 May 2015 20:28:39 +1000 Subject: [PATCH] Implement implicit sharing for QgsField --- python/core/qgsfield.sip | 18 ++-- src/core/qgsfield.cpp | 67 +++++++------- src/core/qgsfield.h | 100 +++++++++++++++------ tests/src/core/CMakeLists.txt | 1 + tests/src/core/testqgsfield.cpp | 151 ++++++++++++++++++++++++++++++++ 5 files changed, 269 insertions(+), 68 deletions(-) create mode 100644 tests/src/core/testqgsfield.cpp diff --git a/python/core/qgsfield.sip b/python/core/qgsfield.sip index 9dffcd00243d..dadc5d131100 100644 --- a/python/core/qgsfield.sip +++ b/python/core/qgsfield.sip @@ -34,6 +34,10 @@ public: int prec = 0, QString comment = QString() ); + /** Copy constructor + */ + QgsField( const QgsField& other ); + //! Destructor ~QgsField(); @@ -75,9 +79,9 @@ public: /** Set the field name. - @param nam Name of the field + @param name Name of the field */ - void setName( const QString & nam ); + void setName( const QString& name ); /** Set variant type. @@ -86,9 +90,9 @@ public: /** Set the field type. - @param typ Field type + @param typeName Field type */ - void setTypeName( const QString & typ ); + void setTypeName( const QString& typeName ); /** Set the field length. @@ -98,15 +102,15 @@ public: /** Set the field precision. - @param prec Precision of the field + @param precision Precision of the field */ - void setPrecision( int prec ); + void setPrecision( int precision ); /** Set the field comment */ - void setComment( const QString & comment ); + void setComment( const QString& comment ); /** Formats string for display*/ QString displayString( const QVariant& v ) const; diff --git a/src/core/qgsfield.cpp b/src/core/qgsfield.cpp index 9a2cb5c417a6..136274df47af 100644 --- a/src/core/qgsfield.cpp +++ b/src/core/qgsfield.cpp @@ -34,9 +34,14 @@ QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num, #endif QgsField::QgsField( QString name, QVariant::Type type, QString typeName, int len, int prec, QString comment ) - : mName( name ), mType( type ), mTypeName( typeName ) - , mLength( len ), mPrecision( prec ), mComment( comment ) { + d = new QgsField::FieldData( name, type, typeName, len, prec, comment ); +} + +QgsField::QgsField( const QgsField &other ) + : d( other.d ) +{ + } @@ -46,8 +51,7 @@ QgsField::~QgsField() bool QgsField::operator==( const QgsField& other ) const { - return (( mName == other.mName ) && ( mType == other.mType ) - && ( mLength == other.mLength ) && ( mPrecision == other.mPrecision ) ); + return *( other.d ) == *d; } bool QgsField::operator!=( const QgsField& other ) const @@ -55,64 +59,63 @@ bool QgsField::operator!=( const QgsField& other ) const return !( *this == other ); } - const QString & QgsField::name() const { - return mName; + return d->name; } QVariant::Type QgsField::type() const { - return mType; + return d->type; } const QString & QgsField::typeName() const { - return mTypeName; + return d->typeName; } int QgsField::length() const { - return mLength; + return d->length; } int QgsField::precision() const { - return mPrecision; + return d->precision; } const QString & QgsField::comment() const { - return mComment; + return d->comment; } -void QgsField::setName( const QString & nam ) +void QgsField::setName( const QString& name ) { - mName = nam; + d->name = name; } void QgsField::setType( QVariant::Type type ) { - mType = type; + d->type = type; } -void QgsField::setTypeName( const QString & typeName ) +void QgsField::setTypeName( const QString& typeName ) { - mTypeName = typeName; + d->typeName = typeName; } void QgsField::setLength( int len ) { - mLength = len; + d->length = len; } -void QgsField::setPrecision( int prec ) +void QgsField::setPrecision( int precision ) { - mPrecision = prec; + d->precision = precision; } -void QgsField::setComment( const QString & comment ) +void QgsField::setComment( const QString& comment ) { - mComment = comment; + d->comment = comment; } QString QgsField::displayString( const QVariant& v ) const @@ -123,8 +126,8 @@ QString QgsField::displayString( const QVariant& v ) const return settings.value( "qgis/nullValue", "NULL" ).toString(); } - if ( mType == QVariant::Double && mPrecision > 0 ) - return QString::number( v.toDouble(), 'f', mPrecision ); + if ( d->type == QVariant::Double && d->precision > 0 ) + return QString::number( v.toDouble(), 'f', d->precision ); return v.toString(); } @@ -133,33 +136,33 @@ bool QgsField::convertCompatible( QVariant& v ) const { if ( v.isNull() ) { - v.convert( mType ); + v.convert( d->type ); return true; } - if ( mType == QVariant::Int && v.toInt() != v.toLongLong() ) + if ( d->type == QVariant::Int && v.toInt() != v.toLongLong() ) { - v = QVariant( mType ); + v = QVariant( d->type ); return false; } - if ( !v.convert( mType ) ) + if ( !v.convert( d->type ) ) { - v = QVariant( mType ); + v = QVariant( d->type ); return false; } - if ( mType == QVariant::Double && mPrecision > 0 ) + if ( d->type == QVariant::Double && d->precision > 0 ) { - double s = qPow( 10, mPrecision ); + double s = qPow( 10, d->precision ); double d = v.toDouble() * s; v = QVariant(( d < 0 ? ceil( d - 0.5 ) : floor( d + 0.5 ) ) / s ); return true; } - if ( mType == QVariant::String && mLength > 0 && v.toString().length() > mLength ) + if ( d->type == QVariant::String && d->length > 0 && v.toString().length() > d->length ) { - v = v.toString().left( mLength ); + v = v.toString().left( d->length ); return false; } diff --git a/src/core/qgsfield.h b/src/core/qgsfield.h index 0fab69c20efa..0eea74021b40 100644 --- a/src/core/qgsfield.h +++ b/src/core/qgsfield.h @@ -19,6 +19,7 @@ #include #include #include +#include typedef QList QgsAttributeList; @@ -52,6 +53,10 @@ class CORE_EXPORT QgsField int prec = 0, QString comment = QString() ); + /** Copy constructor + */ + QgsField( const QgsField& other ); + //! Destructor ~QgsField(); @@ -59,7 +64,7 @@ class CORE_EXPORT QgsField bool operator!=( const QgsField& other ) const; //! Gets the name of the field - const QString & name() const; + const QString& name() const; //! Gets variant type of the field as it will be retrieved from data source QVariant::Type type() const; @@ -70,8 +75,7 @@ class CORE_EXPORT QgsField the data store reports it, with no attempt to standardize the value. @return QString containing the field type */ - const QString & typeName() const; - + const QString& typeName() const; /** Gets the length of the field. @@ -79,7 +83,6 @@ class CORE_EXPORT QgsField */ int length() const; - /** Gets the precision of the field. Not all field types have a related precision. @return int containing the precision or zero if not applicable to the field type. @@ -89,13 +92,13 @@ class CORE_EXPORT QgsField /** Returns the field comment */ - const QString & comment() const; + const QString& comment() const; /** Set the field name. - @param nam Name of the field + @param name Name of the field */ - void setName( const QString & nam ); + void setName( const QString& name ); /** Set variant type. @@ -104,9 +107,9 @@ class CORE_EXPORT QgsField /** Set the field type. - @param typ Field type + @param typeName Field type */ - void setTypeName( const QString & typ ); + void setTypeName( const QString& typeName ); /** Set the field length. @@ -116,15 +119,14 @@ class CORE_EXPORT QgsField /** Set the field precision. - @param prec Precision of the field + @param precision Precision of the field */ - void setPrecision( int prec ); - + void setPrecision( int precision ); /** Set the field comment */ - void setComment( const QString & comment ); + void setComment( const QString& comment ); /** Formats string for display*/ QString displayString( const QVariant& v ) const; @@ -140,23 +142,63 @@ class CORE_EXPORT QgsField private: - //! Name - QString mName; - - //! Variant type - QVariant::Type mType; - - //! Type name from provider - QString mTypeName; - - //! Length - int mLength; - - //! Precision - int mPrecision; + class FieldData : public QSharedData + { + public: + + FieldData( QString name = QString(), + QVariant::Type type = QVariant::Invalid, + QString typeName = QString(), + int len = 0, + int prec = 0, + QString comment = QString() ) + : name( name ) + , type( type ) + , typeName( typeName ) + , length( len ) + , precision( prec ) + , comment( comment ) + {} + + FieldData( const FieldData& other ) + : QSharedData( other ) + , name( other.name ) + , type( other.type ) + , typeName( other.typeName ) + , length( other.length ) + , precision( other.precision ) + , comment( other.comment ) + { + } + + ~FieldData() {} + + bool operator==( const FieldData& other ) const + { + return (( name == other.name ) && ( type == other.type ) + && ( length == other.length ) && ( precision == other.precision ) ); + } + + //! Name + QString name; + + //! Variant type + QVariant::Type type; + + //! Type name from provider + QString typeName; + + //! Length + int length; + + //! Precision + int precision; + + //! Comment + QString comment; + }; - //! Comment - QString mComment; + QSharedDataPointer d; }; // class QgsField diff --git a/tests/src/core/CMakeLists.txt b/tests/src/core/CMakeLists.txt index 80d6c407be0c..012a0d9d2b94 100644 --- a/tests/src/core/CMakeLists.txt +++ b/tests/src/core/CMakeLists.txt @@ -83,6 +83,7 @@ ADD_QGIS_TEST(applicationtest testqgsapplication.cpp) ADD_QGIS_TEST(diagramtest testqgsdiagram.cpp) ADD_QGIS_TEST(diagramexpressiontest testqgsdiagramexpression.cpp) ADD_QGIS_TEST(expressiontest testqgsexpression.cpp) +ADD_QGIS_TEST(fieldtest testqgsfield.cpp) ADD_QGIS_TEST(scaleexpressiontest testqgsscaleexpression.cpp) ADD_QGIS_TEST(filewritertest testqgsvectorfilewriter.cpp) ADD_QGIS_TEST(projecttest testqgsproject.cpp) diff --git a/tests/src/core/testqgsfield.cpp b/tests/src/core/testqgsfield.cpp new file mode 100644 index 000000000000..3e91b5b7e06d --- /dev/null +++ b/tests/src/core/testqgsfield.cpp @@ -0,0 +1,151 @@ +/*************************************************************************** + testqgsfield.cpp + ---------------- + Date : May 2015 + Copyright : (C) 2015 Nyall Dawson + Email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "qgsfield.h" + +class TestQgsField: public QObject +{ + Q_OBJECT + + private slots: + void initTestCase();// will be called before the first testfunction is executed. + void cleanupTestCase();// will be called after the last testfunction was executed. + void init();// will be called before each testfunction is executed. + void cleanup();// will be called after every testfunction. + void create();//test creating a data defined container + void copy();// test cpy destruction (double delete) + void assignment(); + void gettersSetters(); //test getters and setters + void equality(); //test equality operators + private: +}; + +void TestQgsField::initTestCase() +{ + +} + +void TestQgsField::cleanupTestCase() +{ + +} + +void TestQgsField::init() +{ + +} + +void TestQgsField::cleanup() +{ + +} + +void TestQgsField::create() +{ + QScopedPointer field( new QgsField( "name", QVariant::Double, "double", 5, 2, "comment" ) ); + QCOMPARE( field->name(), QString( "name" ) ); + QCOMPARE( field->type(), QVariant::Double ); + QCOMPARE( field->typeName(), QString( "double" ) ); + QCOMPARE( field->length(), 5 ); + QCOMPARE( field->precision(), 2 ); + QCOMPARE( field->comment(), QString( "comment" ) ); +} + +void TestQgsField::copy() +{ + QgsField original( "original", QVariant::Double, "double", 5, 2, "comment" ); + QgsField copy( original ); + QVERIFY( copy == original ); + + copy.setName( "copy" ); + QCOMPARE( original.name(), QString( "original" ) ); + QVERIFY( copy != original ); +} + +void TestQgsField::assignment() +{ + QgsField original( "original", QVariant::Double, "double", 5, 2, "comment" ); + QgsField copy; + copy = original; + QVERIFY( copy == original ); + + copy.setName( "copy" ); + QCOMPARE( original.name(), QString( "original" ) ); + QVERIFY( copy != original ); +} + +void TestQgsField::gettersSetters() +{ + QgsField field; + field.setName( "name" ); + QCOMPARE( field.name(), QString( "name" ) ); + field.setType( QVariant::Int ); + QCOMPARE( field.type(), QVariant::Int ); + field.setTypeName( "typeName" ); + QCOMPARE( field.typeName(), QString( "typeName" ) ); + field.setLength( 5 ); + QCOMPARE( field.length(), 5 ); + field.setPrecision( 2 ); + QCOMPARE( field.precision(), 2 ); + field.setComment( "comment" ); + QCOMPARE( field.comment(), QString( "comment" ) ); +} + +void TestQgsField::equality() +{ + QgsField field1; + field1.setName( "name" ); + field1.setType( QVariant::Int ); + field1.setLength( 5 ); + field1.setPrecision( 2 ); + field1.setTypeName( "typename1" ); //typename is NOT required for equality + field1.setComment( "comment1" ); //comment is NOT required for equality + QgsField field2; + field2.setName( "name" ); + field2.setType( QVariant::Int ); + field2.setLength( 5 ); + field2.setPrecision( 2 ); + field2.setTypeName( "typename2" ); //typename is NOT required for equality + field2.setComment( "comment2" ); //comment is NOT required for equality + QVERIFY( field1 == field2 ); + QVERIFY( !( field1 != field2 ) ); + + //test that all applicable components contribute to equality + field2.setName( "name2" ); + QVERIFY( !( field1 == field2 ) ); + QVERIFY( field1 != field2 ); + field2.setName( "name" ); + field2.setType( QVariant::Double ); + QVERIFY( !( field1 == field2 ) ); + QVERIFY( field1 != field2 ); + field2.setType( QVariant::Int ); + field2.setLength( 9 ); + QVERIFY( !( field1 == field2 ) ); + QVERIFY( field1 != field2 ); + field2.setLength( 5 ); + field2.setPrecision( 9 ); + QVERIFY( !( field1 == field2 ) ); + QVERIFY( field1 != field2 ); + field2.setPrecision( 2 ); +} + +QTEST_MAIN( TestQgsField ) +#include "testqgsfield.moc"