Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Implicit sharing for QgsFields
  • Loading branch information
nyalldawson committed May 3, 2015
1 parent 31e8611 commit bb64830
Show file tree
Hide file tree
Showing 6 changed files with 324 additions and 55 deletions.
34 changes: 26 additions & 8 deletions python/core/qgsfield.sip
@@ -1,10 +1,9 @@

/**
\class QgsField
\brief Class to encapsulate a field in an attribute table or data source.

QgsField stores metadata about an attribute field, including name, type
length, and if applicable, precision.
/** \class QgsField
* \ingroup core
* Encapsulate a field in an attribute table or data source.
* QgsField stores metadata about an attribute field, including name, type
* length, and if applicable, precision.
* \note QgsField objects are implicitly shared.
*/

class QgsField
Expand Down Expand Up @@ -39,7 +38,7 @@ public:
QgsField( const QgsField& other );

//! Destructor
~QgsField();
virtual ~QgsField();

bool operator==( const QgsField& other ) const;
bool operator!=( const QgsField& other ) const;
Expand Down Expand Up @@ -175,6 +174,15 @@ public:
}; // class QgsField


/** \class QgsFields
* \ingroup core
* Container of fields for a vector layer.
*
* In addition to storing a list of QgsField instances, it also:
* - allows quick lookups of field names to index in the list
*- keeps track of where the field definition comes from (vector data provider, joined layer or newly added from an editing operation)
* \note QgsFields objects are implicitly shared.
*/

class QgsFields
{
Expand All @@ -192,6 +200,16 @@ class QgsFields
OriginExpression //!< field is calculated from an expression
};

/** Constructor for an empty field container
*/
QgsFields();

/** Copy constructor
*/
QgsFields( const QgsFields& other );

virtual ~QgsFields();

//! Remove all fields
void clear();
//! Append a field. The field must have unique name, otherwise it is rejected (returns false)
Expand Down
113 changes: 97 additions & 16 deletions src/core/qgsfield.cpp
Expand Up @@ -178,33 +178,54 @@ bool QgsField::convertCompatible( QVariant& v ) const

////////////////////////////////////////////////////////////////////////////

QgsFields::QgsFields()
{
d = new QgsFieldsPrivate( );
}

QgsFields::QgsFields( const QgsFields &other )
: d( other.d )
{
}

QgsFields &QgsFields::operator =( const QgsFields & other )
{
d = other.d;
return *this;
}

QgsFields::~QgsFields()
{

}

void QgsFields::clear()
{
mFields.clear();
mNameToIndex.clear();
d->fields.clear();
d->nameToIndex.clear();
}

bool QgsFields::append( const QgsField& field, FieldOrigin origin, int originIndex )
{
if ( mNameToIndex.contains( field.name() ) )
if ( d->nameToIndex.contains( field.name() ) )
return false;

if ( originIndex == -1 && origin == OriginProvider )
originIndex = mFields.count();
mFields.append( Field( field, origin, originIndex ) );
originIndex = d->fields.count();
d->fields.append( Field( field, origin, originIndex ) );

mNameToIndex.insert( field.name(), mFields.count() - 1 );
d->nameToIndex.insert( field.name(), d->fields.count() - 1 );
return true;
}

bool QgsFields::appendExpressionField( const QgsField& field, int originIndex )
{
if ( mNameToIndex.contains( field.name() ) )
if ( d->nameToIndex.contains( field.name() ) )
return false;

mFields.append( Field( field, OriginExpression, originIndex ) );
d->fields.append( Field( field, OriginExpression, originIndex ) );

mNameToIndex.insert( field.name(), mFields.count() - 1 );
d->nameToIndex.insert( field.name(), d->fields.count() - 1 );
return true;
}

Expand All @@ -213,8 +234,8 @@ void QgsFields::remove( int fieldIdx )
if ( !exists( fieldIdx ) )
return;

mNameToIndex.remove( mFields[fieldIdx].field.name() );
mFields.remove( fieldIdx );
d->nameToIndex.remove( d->fields[fieldIdx].field.name() );
d->fields.remove( fieldIdx );
}

void QgsFields::extend( const QgsFields& other )
Expand All @@ -225,27 +246,87 @@ void QgsFields::extend( const QgsFields& other )
}
}

bool QgsFields::isEmpty() const
{
return d->fields.isEmpty();
}

int QgsFields::count() const
{
return d->fields.count();
}

int QgsFields::size() const
{
return d->fields.count();
}

bool QgsFields::exists( int i ) const
{
return i >= 0 && i < d->fields.count();
}

QgsField &QgsFields::operator[]( int i )
{
return d->fields[i].field;
}

const QgsField &QgsFields::at( int i ) const
{
return d->fields[i].field;
}

const QgsField &QgsFields::field( int fieldIdx ) const
{
return d->fields[fieldIdx].field;
}

const QgsField &QgsFields::field( const QString &name ) const
{
return d->fields[ indexFromName( name )].field;
}

const QgsField &QgsFields::operator[]( int i ) const
{
return d->fields[i].field;
}

QgsFields::FieldOrigin QgsFields::fieldOrigin( int fieldIdx ) const
{
if ( !exists( fieldIdx ) )
return OriginUnknown;

return mFields[fieldIdx].origin;
return d->fields[fieldIdx].origin;
}

int QgsFields::fieldOriginIndex( int fieldIdx ) const
{
return d->fields[fieldIdx].originIndex;
}

int QgsFields::indexFromName( const QString &name ) const
{
return d->nameToIndex.value( name, -1 );
}

QList<QgsField> QgsFields::toList() const
{
QList<QgsField> lst;
for ( int i = 0; i < mFields.count(); ++i )
lst.append( mFields[i].field );
for ( int i = 0; i < d->fields.count(); ++i )
lst.append( d->fields[i].field );
return lst;
}

bool QgsFields::operator==( const QgsFields &other ) const
{
return d->fields == other.d->fields;
}

int QgsFields::fieldNameIndex( const QString& fieldName ) const
{
for ( int idx = 0; idx < count(); ++idx )
{
if ( QString::compare( mFields[idx].field.name(), fieldName, Qt::CaseInsensitive ) == 0 )
if ( QString::compare( d->fields[idx].field.name(), fieldName, Qt::CaseInsensitive ) == 0 )
{
return idx;
}
Expand All @@ -256,7 +337,7 @@ int QgsFields::fieldNameIndex( const QString& fieldName ) const
QgsAttributeList QgsFields::allAttributesList() const
{
QgsAttributeList lst;
for ( int i = 0; i < mFields.count(); ++i )
for ( int i = 0; i < d->fields.count(); ++i )
lst.append( i );
return lst;
}
70 changes: 41 additions & 29 deletions src/core/qgsfield.h
Expand Up @@ -25,11 +25,14 @@ typedef QList<int> QgsAttributeList;

class QgsExpression;
class QgsFieldPrivate;
class QgsFieldsPrivate;

/** \ingroup core
/** \class QgsField
* \ingroup core
* Encapsulate a field in an attribute table or data source.
* QgsField stores metadata about an attribute field, including name, type
* length, and if applicable, precision.
* \note QgsField objects are implicitly shared.
*/

class CORE_EXPORT QgsField
Expand Down Expand Up @@ -63,7 +66,7 @@ class CORE_EXPORT QgsField
QgsField& operator =( const QgsField &other );

//! Destructor
~QgsField();
virtual ~QgsField();

bool operator==( const QgsField& other ) const;
bool operator!=( const QgsField& other ) const;
Expand Down Expand Up @@ -152,13 +155,14 @@ class CORE_EXPORT QgsField
}; // class QgsField


/**
\ingroup core
Container of fields for a vector layer.
In addition to storing a list of QgsField instances, it also:
- allows quick lookups of field names to index in the list
- keeps track of where the field definition comes from (vector data provider, joined layer or newly added from an editing operation)
/** \class QgsFields
* \ingroup core
* Container of fields for a vector layer.
*
* In addition to storing a list of QgsField instances, it also:
* - allows quick lookups of field names to index in the list
*- keeps track of where the field definition comes from (vector data provider, joined layer or newly added from an editing operation)
* \note QgsFields objects are implicitly shared.
*/
class CORE_EXPORT QgsFields
{
Expand Down Expand Up @@ -188,6 +192,20 @@ class CORE_EXPORT QgsFields
int originIndex; //!< index specific to the origin
} Field;

/** Constructor for an empty field container
*/
QgsFields();

/** Copy constructor
*/
QgsFields( const QgsFields& other );

/** Assignment operator
*/
QgsFields& operator =( const QgsFields &other );

virtual ~QgsFields();

//! Remove all fields
void clear();
//! Append a field. The field must have unique name, otherwise it is rejected (returns false)
Expand All @@ -200,34 +218,34 @@ class CORE_EXPORT QgsFields
void extend( const QgsFields& other );

//! Check whether the container is empty
inline bool isEmpty() const { return mFields.isEmpty(); }
bool isEmpty() const;
//! Return number of items
inline int count() const { return mFields.count(); }
int count() const;
//! Return number of items
inline int size() const { return mFields.count(); }
int size() const;
//! Return if a field index is valid
//! @param i Index of the field which needs to be checked
//! @return True if the field exists
inline bool exists( int i ) const { return i >= 0 && i < mFields.count(); }
bool exists( int i ) const;

//! Get field at particular index (must be in range 0..N-1)
inline const QgsField& operator[]( int i ) const { return mFields[i].field; }
const QgsField& operator[]( int i ) const;
//! Get field at particular index (must be in range 0..N-1)
inline QgsField& operator[]( int i ) { return mFields[i].field; }
QgsField& operator[]( int i );
//! Get field at particular index (must be in range 0..N-1)
const QgsField& at( int i ) const { return mFields[i].field; }
const QgsField& at( int i ) const;
//! Get field at particular index (must be in range 0..N-1)
const QgsField& field( int fieldIdx ) const { return mFields[fieldIdx].field; }
const QgsField& field( int fieldIdx ) const;
//! Get field at particular index (must be in range 0..N-1)
const QgsField& field( const QString& name ) const { return mFields[ indexFromName( name )].field; }
const QgsField& field( const QString& name ) const;

//! Get field's origin (value from an enumeration)
FieldOrigin fieldOrigin( int fieldIdx ) const;
//! Get field's origin index (its meaning is specific to each type of origin)
int fieldOriginIndex( int fieldIdx ) const { return mFields[fieldIdx].originIndex; }
int fieldOriginIndex( int fieldIdx ) const;

//! Look up field's index from name. Returns -1 on error
int indexFromName( const QString& name ) const { return mNameToIndex.value( name, -1 ); }
int indexFromName( const QString& name ) const;

//! Look up field's index from name - case insensitive
//! TODO: sort out case sensitive (indexFromName()) vs insensitive (fieldNameIndex()) calls
Expand All @@ -242,20 +260,14 @@ class CORE_EXPORT QgsFields
QList<QgsField> toList() const;

//! @note added in 2.6
bool operator==( const QgsFields& other ) const { return mFields == other.mFields; }
bool operator==( const QgsFields& other ) const;
//! @note added in 2.6
bool operator!=( const QgsFields& other ) const { return !( *this == other ); }

protected:
//! internal storage of the container
QVector<Field> mFields;
private:

//! map for quick resolution of name to index
QHash<QString, int> mNameToIndex;
QSharedDataPointer<QgsFieldsPrivate> d;

};




#endif

0 comments on commit bb64830

Please sign in to comment.