Skip to content

Commit bb64830

Browse files
committed
Implicit sharing for QgsFields
1 parent 31e8611 commit bb64830

File tree

6 files changed

+324
-55
lines changed

6 files changed

+324
-55
lines changed

python/core/qgsfield.sip

+26-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
2-
/**
3-
\class QgsField
4-
\brief Class to encapsulate a field in an attribute table or data source.
5-
6-
QgsField stores metadata about an attribute field, including name, type
7-
length, and if applicable, precision.
1+
/** \class QgsField
2+
* \ingroup core
3+
* Encapsulate a field in an attribute table or data source.
4+
* QgsField stores metadata about an attribute field, including name, type
5+
* length, and if applicable, precision.
6+
* \note QgsField objects are implicitly shared.
87
*/
98

109
class QgsField
@@ -39,7 +38,7 @@ public:
3938
QgsField( const QgsField& other );
4039

4140
//! Destructor
42-
~QgsField();
41+
virtual ~QgsField();
4342

4443
bool operator==( const QgsField& other ) const;
4544
bool operator!=( const QgsField& other ) const;
@@ -175,6 +174,15 @@ public:
175174
}; // class QgsField
176175

177176

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

179187
class QgsFields
180188
{
@@ -192,6 +200,16 @@ class QgsFields
192200
OriginExpression //!< field is calculated from an expression
193201
};
194202

203+
/** Constructor for an empty field container
204+
*/
205+
QgsFields();
206+
207+
/** Copy constructor
208+
*/
209+
QgsFields( const QgsFields& other );
210+
211+
virtual ~QgsFields();
212+
195213
//! Remove all fields
196214
void clear();
197215
//! Append a field. The field must have unique name, otherwise it is rejected (returns false)

src/core/qgsfield.cpp

+97-16
Original file line numberDiff line numberDiff line change
@@ -178,33 +178,54 @@ bool QgsField::convertCompatible( QVariant& v ) const
178178

179179
////////////////////////////////////////////////////////////////////////////
180180

181+
QgsFields::QgsFields()
182+
{
183+
d = new QgsFieldsPrivate( );
184+
}
185+
186+
QgsFields::QgsFields( const QgsFields &other )
187+
: d( other.d )
188+
{
189+
}
190+
191+
QgsFields &QgsFields::operator =( const QgsFields & other )
192+
{
193+
d = other.d;
194+
return *this;
195+
}
196+
197+
QgsFields::~QgsFields()
198+
{
199+
200+
}
201+
181202
void QgsFields::clear()
182203
{
183-
mFields.clear();
184-
mNameToIndex.clear();
204+
d->fields.clear();
205+
d->nameToIndex.clear();
185206
}
186207

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

192213
if ( originIndex == -1 && origin == OriginProvider )
193-
originIndex = mFields.count();
194-
mFields.append( Field( field, origin, originIndex ) );
214+
originIndex = d->fields.count();
215+
d->fields.append( Field( field, origin, originIndex ) );
195216

196-
mNameToIndex.insert( field.name(), mFields.count() - 1 );
217+
d->nameToIndex.insert( field.name(), d->fields.count() - 1 );
197218
return true;
198219
}
199220

200221
bool QgsFields::appendExpressionField( const QgsField& field, int originIndex )
201222
{
202-
if ( mNameToIndex.contains( field.name() ) )
223+
if ( d->nameToIndex.contains( field.name() ) )
203224
return false;
204225

205-
mFields.append( Field( field, OriginExpression, originIndex ) );
226+
d->fields.append( Field( field, OriginExpression, originIndex ) );
206227

207-
mNameToIndex.insert( field.name(), mFields.count() - 1 );
228+
d->nameToIndex.insert( field.name(), d->fields.count() - 1 );
208229
return true;
209230
}
210231

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

216-
mNameToIndex.remove( mFields[fieldIdx].field.name() );
217-
mFields.remove( fieldIdx );
237+
d->nameToIndex.remove( d->fields[fieldIdx].field.name() );
238+
d->fields.remove( fieldIdx );
218239
}
219240

220241
void QgsFields::extend( const QgsFields& other )
@@ -225,27 +246,87 @@ void QgsFields::extend( const QgsFields& other )
225246
}
226247
}
227248

249+
bool QgsFields::isEmpty() const
250+
{
251+
return d->fields.isEmpty();
252+
}
253+
254+
int QgsFields::count() const
255+
{
256+
return d->fields.count();
257+
}
258+
259+
int QgsFields::size() const
260+
{
261+
return d->fields.count();
262+
}
263+
264+
bool QgsFields::exists( int i ) const
265+
{
266+
return i >= 0 && i < d->fields.count();
267+
}
268+
269+
QgsField &QgsFields::operator[]( int i )
270+
{
271+
return d->fields[i].field;
272+
}
273+
274+
const QgsField &QgsFields::at( int i ) const
275+
{
276+
return d->fields[i].field;
277+
}
278+
279+
const QgsField &QgsFields::field( int fieldIdx ) const
280+
{
281+
return d->fields[fieldIdx].field;
282+
}
283+
284+
const QgsField &QgsFields::field( const QString &name ) const
285+
{
286+
return d->fields[ indexFromName( name )].field;
287+
}
288+
289+
const QgsField &QgsFields::operator[]( int i ) const
290+
{
291+
return d->fields[i].field;
292+
}
293+
228294
QgsFields::FieldOrigin QgsFields::fieldOrigin( int fieldIdx ) const
229295
{
230296
if ( !exists( fieldIdx ) )
231297
return OriginUnknown;
232298

233-
return mFields[fieldIdx].origin;
299+
return d->fields[fieldIdx].origin;
300+
}
301+
302+
int QgsFields::fieldOriginIndex( int fieldIdx ) const
303+
{
304+
return d->fields[fieldIdx].originIndex;
305+
}
306+
307+
int QgsFields::indexFromName( const QString &name ) const
308+
{
309+
return d->nameToIndex.value( name, -1 );
234310
}
235311

236312
QList<QgsField> QgsFields::toList() const
237313
{
238314
QList<QgsField> lst;
239-
for ( int i = 0; i < mFields.count(); ++i )
240-
lst.append( mFields[i].field );
315+
for ( int i = 0; i < d->fields.count(); ++i )
316+
lst.append( d->fields[i].field );
241317
return lst;
242318
}
243319

320+
bool QgsFields::operator==( const QgsFields &other ) const
321+
{
322+
return d->fields == other.d->fields;
323+
}
324+
244325
int QgsFields::fieldNameIndex( const QString& fieldName ) const
245326
{
246327
for ( int idx = 0; idx < count(); ++idx )
247328
{
248-
if ( QString::compare( mFields[idx].field.name(), fieldName, Qt::CaseInsensitive ) == 0 )
329+
if ( QString::compare( d->fields[idx].field.name(), fieldName, Qt::CaseInsensitive ) == 0 )
249330
{
250331
return idx;
251332
}
@@ -256,7 +337,7 @@ int QgsFields::fieldNameIndex( const QString& fieldName ) const
256337
QgsAttributeList QgsFields::allAttributesList() const
257338
{
258339
QgsAttributeList lst;
259-
for ( int i = 0; i < mFields.count(); ++i )
340+
for ( int i = 0; i < d->fields.count(); ++i )
260341
lst.append( i );
261342
return lst;
262343
}

src/core/qgsfield.h

+41-29
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ typedef QList<int> QgsAttributeList;
2525

2626
class QgsExpression;
2727
class QgsFieldPrivate;
28+
class QgsFieldsPrivate;
2829

29-
/** \ingroup core
30+
/** \class QgsField
31+
* \ingroup core
3032
* Encapsulate a field in an attribute table or data source.
3133
* QgsField stores metadata about an attribute field, including name, type
3234
* length, and if applicable, precision.
35+
* \note QgsField objects are implicitly shared.
3336
*/
3437

3538
class CORE_EXPORT QgsField
@@ -63,7 +66,7 @@ class CORE_EXPORT QgsField
6366
QgsField& operator =( const QgsField &other );
6467

6568
//! Destructor
66-
~QgsField();
69+
virtual ~QgsField();
6770

6871
bool operator==( const QgsField& other ) const;
6972
bool operator!=( const QgsField& other ) const;
@@ -152,13 +155,14 @@ class CORE_EXPORT QgsField
152155
}; // class QgsField
153156

154157

155-
/**
156-
\ingroup core
157-
Container of fields for a vector layer.
158-
159-
In addition to storing a list of QgsField instances, it also:
160-
- allows quick lookups of field names to index in the list
161-
- keeps track of where the field definition comes from (vector data provider, joined layer or newly added from an editing operation)
158+
/** \class QgsFields
159+
* \ingroup core
160+
* Container of fields for a vector layer.
161+
*
162+
* In addition to storing a list of QgsField instances, it also:
163+
* - allows quick lookups of field names to index in the list
164+
*- keeps track of where the field definition comes from (vector data provider, joined layer or newly added from an editing operation)
165+
* \note QgsFields objects are implicitly shared.
162166
*/
163167
class CORE_EXPORT QgsFields
164168
{
@@ -188,6 +192,20 @@ class CORE_EXPORT QgsFields
188192
int originIndex; //!< index specific to the origin
189193
} Field;
190194

195+
/** Constructor for an empty field container
196+
*/
197+
QgsFields();
198+
199+
/** Copy constructor
200+
*/
201+
QgsFields( const QgsFields& other );
202+
203+
/** Assignment operator
204+
*/
205+
QgsFields& operator =( const QgsFields &other );
206+
207+
virtual ~QgsFields();
208+
191209
//! Remove all fields
192210
void clear();
193211
//! Append a field. The field must have unique name, otherwise it is rejected (returns false)
@@ -200,34 +218,34 @@ class CORE_EXPORT QgsFields
200218
void extend( const QgsFields& other );
201219

202220
//! Check whether the container is empty
203-
inline bool isEmpty() const { return mFields.isEmpty(); }
221+
bool isEmpty() const;
204222
//! Return number of items
205-
inline int count() const { return mFields.count(); }
223+
int count() const;
206224
//! Return number of items
207-
inline int size() const { return mFields.count(); }
225+
int size() const;
208226
//! Return if a field index is valid
209227
//! @param i Index of the field which needs to be checked
210228
//! @return True if the field exists
211-
inline bool exists( int i ) const { return i >= 0 && i < mFields.count(); }
229+
bool exists( int i ) const;
212230

213231
//! Get field at particular index (must be in range 0..N-1)
214-
inline const QgsField& operator[]( int i ) const { return mFields[i].field; }
232+
const QgsField& operator[]( int i ) const;
215233
//! Get field at particular index (must be in range 0..N-1)
216-
inline QgsField& operator[]( int i ) { return mFields[i].field; }
234+
QgsField& operator[]( int i );
217235
//! Get field at particular index (must be in range 0..N-1)
218-
const QgsField& at( int i ) const { return mFields[i].field; }
236+
const QgsField& at( int i ) const;
219237
//! Get field at particular index (must be in range 0..N-1)
220-
const QgsField& field( int fieldIdx ) const { return mFields[fieldIdx].field; }
238+
const QgsField& field( int fieldIdx ) const;
221239
//! Get field at particular index (must be in range 0..N-1)
222-
const QgsField& field( const QString& name ) const { return mFields[ indexFromName( name )].field; }
240+
const QgsField& field( const QString& name ) const;
223241

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

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

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

244262
//! @note added in 2.6
245-
bool operator==( const QgsFields& other ) const { return mFields == other.mFields; }
263+
bool operator==( const QgsFields& other ) const;
246264
//! @note added in 2.6
247265
bool operator!=( const QgsFields& other ) const { return !( *this == other ); }
248266

249-
protected:
250-
//! internal storage of the container
251-
QVector<Field> mFields;
267+
private:
252268

253-
//! map for quick resolution of name to index
254-
QHash<QString, int> mNameToIndex;
269+
QSharedDataPointer<QgsFieldsPrivate> d;
255270

256271
};
257272

258-
259-
260-
261273
#endif

0 commit comments

Comments
 (0)