Skip to content

Commit 267d952

Browse files
committedMay 20, 2015
Implicit sharing for QgsFeature
1 parent c33b9fa commit 267d952

File tree

5 files changed

+423
-276
lines changed

5 files changed

+423
-276
lines changed
 

‎python/core/qgsfeature.sip

Lines changed: 114 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ typedef QMap<int, QgsField> QgsFieldMap;
104104
/** \ingroup core
105105
* The feature class encapsulates a single feature including its id,
106106
* geometry and a list of field/values attributes.
107-
*
107+
* \note QgsFeature objects are implicitly shared.
108108
* @author Gary E.Sherman
109109
*/
110110
class QgsFeature
@@ -218,42 +218,57 @@ class QgsFeature
218218
sipCpp->deleteAttribute(fieldIdx);
219219
%End
220220

221-
//! Constructor
221+
/** Constructor for QgsFeature
222+
* @param id feature id
223+
*/
222224
QgsFeature( qint64 id = 0 );
223225

226+
/** Constructor for QgsFeature
227+
* @param fields feature's fields
228+
* @param id feature id
229+
*/
224230
QgsFeature( const QgsFields& fields, qint64 id = 0 );
225231

226-
/** copy ctor needed due to internal pointer */
232+
/** Copy constructor
233+
*/
227234
QgsFeature( const QgsFeature & rhs );
228235

229236
//! Destructor
230237
~QgsFeature();
231238

232-
/**
233-
* Get the feature id for this feature
234-
* @return Feature id
239+
/** Get the feature ID for this feature.
240+
* @returns feature ID
241+
* @see setFeatureId
235242
*/
236243
qint64 id() const;
237244

238-
/**
239-
* Set the feature id for this feature
240-
* @param id Feature id
245+
/** Sets the feature ID for this feature.
246+
* @param id feature id
247+
* @see id
241248
*/
242249
void setFeatureId( qint64 id );
243250

251+
/** Returns the feature's attributes.
252+
* @link attributes @endlink method.
253+
* @returns list of feature's attributes
254+
* @see setAttributes
255+
* @note added in QGIS 2.9
256+
*/
244257
QgsAttributes attributes() const;
245258

259+
/** Sets the feature's attributes.
260+
* @param attrs attribute list
261+
* @see setAttribute
262+
* @see attributes
263+
*/
246264
void setAttributes( const QgsAttributes& attrs );
247265

248-
/**
249-
* Set an attribute by id
250-
*
251-
* @param field The index of the field to set
252-
* @param attr The value of the attribute
253-
*
254-
* @return false, if the field id does not exist
255-
*
266+
/** Set an attribute's value by field index.
267+
* @param field the index of the field to set
268+
* @param attr the value of the attribute
269+
* @return false, if the field index does not exist
256270
* @note For Python: raises a KeyError exception instead of returning false
271+
* @see setAttributes
257272
*/
258273
bool setAttribute( int field, const QVariant& attr /GetWrapper/);
259274
%MethodCode
@@ -275,17 +290,14 @@ class QgsFeature
275290
}
276291
%End
277292

278-
/**
279-
* Initialize this feature with the given number of fields. Discard any previously set attribute data.
293+
/** Initialize this feature with the given number of fields. Discard any previously set attribute data.
280294
* @param fieldCount Number of fields to initialize
281295
*/
282296
void initAttributes( int fieldCount );
283297

284-
/**
285-
* Deletes an attribute and its value
286-
*
287-
* @param field The index of the field
288-
*
298+
/** Deletes an attribute and its value.
299+
* @param field the index of the field
300+
* @see setAttribute
289301
* @note For Python: raises a KeyError exception if the field is not found
290302
*/
291303
void deleteAttribute( int field );
@@ -298,92 +310,123 @@ class QgsFeature
298310
sipIsErr = 1;
299311
}
300312
%End
301-
/**
302-
* Return the validity of this feature. This is normally set by
313+
/** Returns the validity of this feature. This is normally set by
303314
* the provider to indicate some problem that makes the feature
304315
* invalid or to indicate a null feature.
316+
* @see setValid
305317
*/
306318
bool isValid() const;
307319

308-
/**
309-
* Set the validity of the feature.
320+
/** Sets the validity of the feature.
321+
* @param validity set to true if feature is valid
322+
* @see isValid
310323
*/
311324
void setValid( bool validity );
312325

313-
/**
314-
* Get the geometry object associated with this feature
326+
/** Get the geometry object associated with this feature. If the geometry
327+
* is not going to be modified than calling the const @link constGeometry @endlink
328+
* method is preferable as it avoids a potentially expensive detach operation.
315329
*
316330
* It is possible to modify the geometry in place but this will
317331
* be removed in 3.0 and therefore @link setGeometry @endlink should be called explicitly.
318332
*
319333
* @note will be modified to return by value in QGIS 3.0: `QgsGeometry geometry() const;`
334+
*
335+
* @returns pointer to feature's geometry
336+
* @see constGeometry
337+
* @see geometryAndOwnership
338+
* @see setGeometry
320339
*/
321340
QgsGeometry* geometry();
322341

323-
/** Gets a const pointer to the geometry object associated with this feature.
342+
/** Gets a const pointer to the geometry object associated with this feature. If the geometry
343+
* is not going to be modified than this method is preferable to the non-const
344+
* @link geometry @endlink method.
324345
* @note this is a temporary method for 2.x release cycle. Will be removed in QGIS 3.0.
346+
* @returns const pointer to feature's geometry
347+
* @see geometry
348+
* @see geometryAndOwnership
349+
* @see setGeometry
325350
* @note added in QGIS 2.9
326351
* @note will be removed in QGIS 3.0
327352
*/
328353
const QgsGeometry* constGeometry() const;
329354

330-
/**
331-
* Get the geometry object associated with this feature
332-
* The caller assumes responsibility for the QgsGeometry*'s destruction.
333-
* @deprecated will be removed in QGIS 3.0
355+
/** Get the geometry object associated with this feature, and transfer ownership of the
356+
* geometry to the caller. The caller assumes responsibility for the QgsGeometry*'s destruction.
357+
* @returns pointer to feature's geometry
358+
* @see geometry
359+
* @see setGeometry
334360
*/
335361
QgsGeometry *geometryAndOwnership() /Factory,Deprecated/;
336362

337-
/** Set this feature's geometry from another QgsGeometry object (deep copy)
363+
/** Set this feature's geometry from another QgsGeometry object. This method performs a deep copy
364+
* of the geometry.
365+
* @param geom new feature geometry
366+
* @see geometry
367+
* @see constGeometry
368+
* @see geometryAndOwnership
369+
* @see setGeometryAndOwnership
338370
*/
339371
void setGeometry( const QgsGeometry& geom );
340372

341-
/** Set this feature's geometry (takes geometry ownership)
342-
*
373+
/** Set this feature's geometry from a QgsGeometry pointer. Ownership of the geometry is transferred
374+
* to the feature.
375+
* @param geom new feature geometry
343376
* @note not available in python bindings
377+
* @see geometry
378+
* @see constGeometry
379+
* @see geometryAndOwnership
380+
* @see setGeometryAndOwnership
344381
* @deprecated will be removed in QGIS 3.0
345382
*/
346383
// void setGeometry( QgsGeometry* geom /Transfer/ );
347384

348-
/**
349-
* Set this feature's geometry from WKB
350-
*
351-
* This feature assumes responsibility for destroying geom.
352-
*
385+
/** Set this feature's geometry from WKB. This feature assumes responsibility for destroying the
386+
* created geometry.
387+
* @param geom geometry as WKB
388+
* @param length size of WKB
389+
* @see setGeometry
390+
* @see geometry
391+
* @see constGeometry
392+
* @see geometryAndOwnership
353393
* @deprecated will be removed in QGIS 3.0
354394
*/
355395
void setGeometryAndOwnership( unsigned char * geom /Transfer/, size_t length );
356396

357-
/** Assign a field map with the feature to allow attribute access by attribute name
358-
*
359-
* @param fields The attribute fields which this feature holds. When used from python, make sure
360-
* a copy of the fields is held by python, as ownership stays there.
361-
* I.e. Do not call feature.setFields( myDataProvider.fields() ) but instead call
362-
* myFields = myDataProvider.fields()
363-
* feature.setFields( myFields )
397+
/** Assign a field map with the feature to allow attribute access by attribute name.
398+
* @param fields The attribute fields which this feature holds
364399
* @param initAttributes If true, attributes are initialized. Clears any data previously assigned.
365400
* C++: Defaults to false
366401
* Python: Defaults to true
367-
*
368-
* TODO: QGIS3 - take reference, not pointer
402+
* @deprecated use setFields( const QgsFields& fields, bool initAttributes = false ) instead
403+
* @note not available in Python bindings
369404
*/
370-
void setFields( const QgsFields* fields, bool initAttributes = true );
405+
//void setFields( const QgsFields* fields, bool initAttributes = true );
371406

372-
/** Get associated field map.
373-
*
374-
* TODO: QGIS 3 - return reference or value, not pointer
407+
/** Assign a field map with the feature to allow attribute access by attribute name.
408+
* @param fields The attribute fields which this feature holds
409+
* @param initAttributes If true, attributes are initialized. Clears any data previously assigned.
410+
* C++: Defaults to false
411+
* Python: Defaults to true
412+
* @note added in QGIS 2.9
413+
* @see fields
414+
*/
415+
void setFields( const QgsFields& fields, bool initAttributes = true );
416+
417+
/** Returns the field map associated with the feature.
418+
* @see setFields
419+
* TODO: QGIS 3 - return value, not pointer
375420
*/
376421
const QgsFields* fields() const;
377422

378423
/** Insert a value into attribute. Returns false if attribute name could not be converted to index.
379-
* Field map must be associated to make this work.
380-
*
424+
* Field map must be associated using @link setFields @endlink before this method can be used.
381425
* @param name The name of the field to set
382426
* @param value The value to set
383-
*
384427
* @return false if attribute name could not be converted to index (C++ only)
385-
*
386428
* @note For Python: raises a KeyError exception instead of returning false
429+
* @see setFields
387430
*/
388431
void setAttribute( const QString& name, QVariant value /GetWrapper/ );
389432
%MethodCode
@@ -405,15 +448,12 @@ class QgsFeature
405448
}
406449
}
407450
%End
408-
/** Remove an attribute value.
409-
* Returns false if attribute name could not be converted to index.
410-
* Field map must be associated to make this work.
411-
*
451+
/** Removes an attribute value by field name. Field map must be associated using @link setFields @endlink
452+
* before this method can be used.
412453
* @param name The name of the field to delete
413-
*
414454
* @return false if attribute name could not be converted to index (C++ only)
415-
*
416455
* @note For Python: raises a KeyError exception instead of returning false
456+
* @see setFields
417457
*/
418458
bool deleteAttribute( const QString& name );
419459
%MethodCode
@@ -428,15 +468,12 @@ class QgsFeature
428468
sipCpp->deleteAttribute( fieldIdx );
429469
}
430470
%End
431-
/** Lookup attribute value from attribute name.
432-
* Returns invalid variant if attribute name could not be converted to index (C++ only)
433-
* Field map must be associated to make this work.
434-
*
471+
/** Lookup attribute value from attribute name. Field map must be associated using @link setFields @endlink
472+
* before this method can be used.
435473
* @param name The name of the attribute to get
436-
*
437474
* @return The value of the attribute (C++: Invalid variant if no such name exists )
438-
*
439475
* @note For Python: raises a KeyError exception if field is not found
476+
* @see setFields
440477
*/
441478
SIP_PYOBJECT attribute( const QString& name ) const;
442479
%MethodCode
@@ -452,8 +489,11 @@ class QgsFeature
452489
sipRes = sipConvertFromNewType( v, sipType_QVariant, Py_None );
453490
}
454491
%End
455-
/** Utility method to get attribute index from name. Returns -1 if field does not exist or field map is not associated.
456-
* Field map must be associated to make this work.
492+
/** Utility method to get attribute index from name. Field map must be associated using @link setFields @endlink
493+
* before this method can be used.
494+
* @param fieldName name of field to get attribute index of
495+
* @returns -1 if field does not exist or field map is not associated.
496+
* @see setFields
457497
*/
458498
int fieldNameIndex( const QString& fieldName ) const;
459499

‎src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,7 @@ SET(QGIS_CORE_HDRS
503503
qgsexpression.h
504504
qgsexpressionfieldbuffer.h
505505
qgsfeature.h
506+
qgsfeature_p.h
506507
qgsfeatureiterator.h
507508
qgsfeaturerequest.h
508509
qgsfeaturestore.h

‎src/core/qgsfeature.cpp

Lines changed: 91 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -14,127 +14,92 @@ email : sherman at mrcc.com
1414
***************************************************************************/
1515

1616
#include "qgsfeature.h"
17+
#include "qgsfeature_p.h"
1718
#include "qgsfield.h"
1819
#include "qgsgeometry.h"
1920
#include "qgsrectangle.h"
2021

2122
#include "qgsmessagelog.h"
2223

23-
/** \class QgsFeature
24-
* \brief Encapsulates a spatial feature with attributes
25-
*/
26-
2724
QgsFeature::QgsFeature( QgsFeatureId id )
28-
: mFid( id )
29-
, mGeometry( 0 )
30-
, mOwnsGeometry( 0 )
31-
, mValid( false )
3225
{
33-
// NOOP
26+
d = new QgsFeaturePrivate( id );
3427
}
3528

3629
QgsFeature::QgsFeature( const QgsFields &fields, QgsFeatureId id )
37-
: mFid( id )
38-
, mGeometry( 0 )
39-
, mOwnsGeometry( 0 )
40-
, mValid( false )
41-
, mFields( fields )
4230
{
43-
initAttributes( fields.count() );
31+
d = new QgsFeaturePrivate( id );
32+
d->fields = fields;
33+
initAttributes( d->fields.count() );
4434
}
4535

4636
QgsFeature::QgsFeature( QgsFeature const & rhs )
47-
: mFid( rhs.mFid )
48-
, mAttributes( rhs.mAttributes )
49-
, mGeometry( 0 )
50-
, mOwnsGeometry( false )
51-
, mValid( rhs.mValid )
52-
, mFields( rhs.mFields )
37+
: d( rhs.d )
5338
{
54-
55-
// copy embedded geometry
56-
if ( rhs.mGeometry )
57-
{
58-
setGeometry( *rhs.mGeometry );
59-
}
6039
}
6140

62-
6341
QgsFeature & QgsFeature::operator=( QgsFeature const & rhs )
6442
{
65-
if ( &rhs == this )
66-
return *this;
67-
68-
mFid = rhs.mFid;
69-
mAttributes = rhs.mAttributes;
70-
mValid = rhs.mValid;
71-
mFields = rhs.mFields;
72-
73-
// make sure to delete the old geometry (if exists)
74-
if ( mGeometry && mOwnsGeometry )
75-
delete mGeometry;
76-
77-
mGeometry = 0;
78-
mOwnsGeometry = false;
79-
80-
if ( rhs.mGeometry )
81-
setGeometry( *rhs.mGeometry );
82-
43+
d = rhs.d;
8344
return *this;
84-
} // QgsFeature::operator=( QgsFeature const & rhs )
85-
86-
45+
}
8746

88-
//! Destructor
8947
QgsFeature::~QgsFeature()
9048
{
91-
// Destruct the attached geometry only if we still own it.
92-
if ( mOwnsGeometry && mGeometry )
93-
delete mGeometry;
9449
}
9550

96-
/**
97-
* Get the feature id for this feature
98-
* @return Feature id
99-
*/
10051
QgsFeatureId QgsFeature::id() const
10152
{
102-
return mFid;
53+
return d->fid;
10354
}
10455

105-
/**Deletes an attribute and its value*/
10656
void QgsFeature::deleteAttribute( int field )
10757
{
108-
mAttributes.remove( field );
58+
d.detach();
59+
d->attributes.remove( field );
10960
}
11061

111-
11262
QgsGeometry *QgsFeature::geometry()
11363
{
114-
return mGeometry;
64+
d.detach();
65+
return d->geometry;
11566
}
11667

11768
const QgsGeometry* QgsFeature::constGeometry() const
11869
{
119-
return mGeometry;
70+
return d->geometry;
12071
}
12172

12273
QgsGeometry *QgsFeature::geometryAndOwnership()
12374
{
124-
mOwnsGeometry = false;
75+
d.detach();
76+
d->ownsGeometry = false;
12577

126-
return mGeometry;
78+
return d->geometry;
12779
}
12880

81+
void QgsFeature::setFeatureId( QgsFeatureId id )
82+
{
83+
if ( id == d->fid )
84+
return;
12985

86+
d.detach();
87+
d->fid = id;
88+
}
13089

131-
/** Set the feature id
132-
*/
133-
void QgsFeature::setFeatureId( QgsFeatureId id )
90+
QgsAttributes QgsFeature::attributes() const
13491
{
135-
mFid = id;
92+
return d->attributes;
13693
}
13794

95+
void QgsFeature::setAttributes( const QgsAttributes &attrs )
96+
{
97+
if ( attrs == d->attributes )
98+
return;
99+
100+
d.detach();
101+
d->attributes = attrs;
102+
}
138103

139104
void QgsFeature::setGeometry( const QgsGeometry& geom )
140105
{
@@ -143,15 +108,31 @@ void QgsFeature::setGeometry( const QgsGeometry& geom )
143108

144109
void QgsFeature::setGeometry( QgsGeometry* geom )
145110
{
146-
// Destruct the attached geometry only if we still own it, before assigning new one.
147-
if ( mOwnsGeometry && mGeometry )
111+
// we do a little bit of trickery here to avoid an unnecessary deep copy
112+
// of the existing geometry by the detach function
113+
// (since we are replacing the geometry anyway)
114+
115+
//first, store the old ownsGeometry status
116+
QgsFeaturePrivate* old_d = d.data();
117+
bool ownedGeom = d->ownsGeometry;
118+
119+
//then set owns geometry to false before the detach, so that the deep copy
120+
//is not made
121+
d->ownsGeometry = false;
122+
d.detach();
123+
124+
//restore ownsGeometry setting if a detach was made
125+
if ( old_d != d.data() )
126+
{
127+
old_d->ownsGeometry = ownedGeom;
128+
}
129+
else if ( ownedGeom )
148130
{
149-
delete mGeometry;
150-
mGeometry = 0;
131+
delete d->geometry;
151132
}
152133

153-
mGeometry = geom;
154-
mOwnsGeometry = true;
134+
d->geometry = geom;
135+
d->ownsGeometry = true;
155136
}
156137

157138
/** Set the pointer to the feature geometry
@@ -165,42 +146,59 @@ void QgsFeature::setGeometryAndOwnership( unsigned char *geom, size_t length )
165146

166147
void QgsFeature::setFields( const QgsFields* fields, bool init )
167148
{
168-
mFields = *fields;
149+
setFields( *fields, init );
150+
}
151+
152+
void QgsFeature::setFields( const QgsFields &fields, bool init )
153+
{
154+
d.detach();
155+
d->fields = fields;
169156
if ( init )
170157
{
171-
initAttributes( fields->count() );
158+
initAttributes( d->fields.count() );
172159
}
173160
}
174161

162+
const QgsFields *QgsFeature::fields() const
163+
{
164+
return &( d->fields );
165+
}
166+
175167

176168
bool QgsFeature::isValid() const
177169
{
178-
return mValid;
170+
return d->valid;
179171
}
180172

181173
void QgsFeature::setValid( bool validity )
182174
{
183-
mValid = validity;
175+
if ( d->valid == validity )
176+
return;
177+
178+
d.detach();
179+
d->valid = validity;
184180
}
185181

186182
void QgsFeature::initAttributes( int fieldCount )
187183
{
188-
mAttributes.resize( fieldCount );
189-
QVariant* ptr = mAttributes.data();
184+
d.detach();
185+
d->attributes.resize( fieldCount );
186+
QVariant* ptr = d->attributes.data();
190187
for ( int i = 0; i < fieldCount; ++i, ++ptr )
191188
ptr->clear();
192189
}
193190

194191

195192
bool QgsFeature::setAttribute( int idx, const QVariant &value )
196193
{
197-
if ( idx < 0 || idx >= mAttributes.size() )
194+
if ( idx < 0 || idx >= d->attributes.size() )
198195
{
199-
QgsMessageLog::logMessage( QObject::tr( "Attribute index %1 out of bounds [0;%2]" ).arg( idx ).arg( mAttributes.size() ), QString::null, QgsMessageLog::WARNING );
196+
QgsMessageLog::logMessage( QObject::tr( "Attribute index %1 out of bounds [0;%2]" ).arg( idx ).arg( d->attributes.size() ), QString::null, QgsMessageLog::WARNING );
200197
return false;
201198
}
202199

203-
mAttributes[idx] = value;
200+
d.detach();
201+
d->attributes[idx] = value;
204202
return true;
205203
}
206204

@@ -210,7 +208,8 @@ bool QgsFeature::setAttribute( const QString& name, QVariant value )
210208
if ( fieldIdx == -1 )
211209
return false;
212210

213-
mAttributes[fieldIdx] = value;
211+
d.detach();
212+
d->attributes[fieldIdx] = value;
214213
return true;
215214
}
216215

@@ -220,15 +219,17 @@ bool QgsFeature::deleteAttribute( const QString& name )
220219
if ( fieldIdx == -1 )
221220
return false;
222221

223-
mAttributes[fieldIdx].clear();
222+
d.detach();
223+
d->attributes[fieldIdx].clear();
224224
return true;
225225
}
226226

227227
QVariant QgsFeature::attribute( int fieldIdx ) const
228228
{
229-
if ( fieldIdx < 0 || fieldIdx >= mAttributes.count() )
229+
if ( fieldIdx < 0 || fieldIdx >= d->attributes.count() )
230230
return QVariant();
231-
return mAttributes[fieldIdx];
231+
232+
return d->attributes[fieldIdx];
232233
}
233234

234235

@@ -238,19 +239,12 @@ QVariant QgsFeature::attribute( const QString& name ) const
238239
if ( fieldIdx == -1 )
239240
return QVariant();
240241

241-
return mAttributes[fieldIdx];
242+
return d->attributes[fieldIdx];
242243
}
243244

244245
int QgsFeature::fieldNameIndex( const QString& fieldName ) const
245246
{
246-
for ( int i = 0; i < mFields.count(); ++i )
247-
{
248-
if ( QString::compare( mFields.at( i ).name(), fieldName, Qt::CaseInsensitive ) == 0 )
249-
{
250-
return i;
251-
}
252-
}
253-
return -1;
247+
return d->fields.fieldNameIndex( fieldName );
254248
}
255249

256250
QDataStream& operator<<( QDataStream& out, const QgsFeature& feature )

‎src/core/qgsfeature.h

Lines changed: 127 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class QgsGeometry;
2828
class QgsRectangle;
2929
class QgsFeature;
3030
class QgsFields;
31+
class QgsFeaturePrivate;
3132

3233
// feature id class (currently 64 bit)
3334
#if 0
@@ -112,220 +113,241 @@ class QgsField;
112113
/** \ingroup core
113114
* The feature class encapsulates a single feature including its id,
114115
* geometry and a list of field/values attributes.
115-
*
116+
* \note QgsFeature objects are implicitly shared.
116117
* @author Gary E.Sherman
117118
*/
118119
class CORE_EXPORT QgsFeature
119120
{
120121
public:
121-
//! Constructor
122+
123+
/** Constructor for QgsFeature
124+
* @param id feature id
125+
*/
122126
QgsFeature( QgsFeatureId id = QgsFeatureId() );
123127

128+
/** Constructor for QgsFeature
129+
* @param fields feature's fields
130+
* @param id feature id
131+
*/
124132
QgsFeature( const QgsFields& fields, QgsFeatureId id = QgsFeatureId() );
125133

126-
/** copy ctor needed due to internal pointer */
134+
/** Copy constructor
135+
*/
127136
QgsFeature( const QgsFeature & rhs );
128137

129-
/** assignment operator needed due to internal pointer */
138+
/** Assignment operator
139+
*/
130140
QgsFeature & operator=( QgsFeature const & rhs );
131141

132142
//! Destructor
133-
~QgsFeature();
143+
virtual ~QgsFeature();
134144

135-
/**
136-
* Get the feature id for this feature
137-
* @return Feature id
145+
/** Get the feature ID for this feature.
146+
* @returns feature ID
147+
* @see setFeatureId
138148
*/
139149
QgsFeatureId id() const;
140150

141-
/**
142-
* Set the feature id for this feature
143-
* @param id Feature id
151+
/** Sets the feature ID for this feature.
152+
* @param id feature id
153+
* @see id
144154
*/
145155
void setFeatureId( QgsFeatureId id );
146156

147-
QgsAttributes attributes() const { return mAttributes; }
148-
void setAttributes( const QgsAttributes& attrs ) { mAttributes = attrs; }
157+
/** Returns the feature's attributes.
158+
* @link attributes @endlink method.
159+
* @returns list of feature's attributes
160+
* @see setAttributes
161+
* @note added in QGIS 2.9
162+
*/
163+
QgsAttributes attributes() const;
164+
165+
/** Sets the feature's attributes.
166+
* @param attrs attribute list
167+
* @see setAttribute
168+
* @see attributes
169+
*/
170+
void setAttributes( const QgsAttributes& attrs );
149171

150-
/**
151-
* Set an attribute by id
152-
*
153-
* @param field The index of the field to set
154-
* @param attr The value of the attribute
155-
*
156-
* @return false, if the field id does not exist
157-
*
172+
/** Set an attribute's value by field index.
173+
* @param field the index of the field to set
174+
* @param attr the value of the attribute
175+
* @return false, if the field index does not exist
158176
* @note For Python: raises a KeyError exception instead of returning false
177+
* @see setAttributes
159178
*/
160179
bool setAttribute( int field, const QVariant& attr );
161180

162-
/**
163-
* Initialize this feature with the given number of fields. Discard any previously set attribute data.
181+
/** Initialize this feature with the given number of fields. Discard any previously set attribute data.
164182
* @param fieldCount Number of fields to initialize
165183
*/
166184
void initAttributes( int fieldCount );
167185

168-
/**
169-
* Deletes an attribute and its value
170-
*
171-
* @param field The index of the field
172-
*
186+
/** Deletes an attribute and its value.
187+
* @param field the index of the field
188+
* @see setAttribute
173189
* @note For Python: raises a KeyError exception if the field is not found
174190
*/
175191
void deleteAttribute( int field );
176192

177-
/**
178-
* Return the validity of this feature. This is normally set by
193+
/** Returns the validity of this feature. This is normally set by
179194
* the provider to indicate some problem that makes the feature
180195
* invalid or to indicate a null feature.
196+
* @see setValid
181197
*/
182198
bool isValid() const;
183199

184-
/**
185-
* Set the validity of the feature.
200+
/** Sets the validity of the feature.
201+
* @param validity set to true if feature is valid
202+
* @see isValid
186203
*/
187204
void setValid( bool validity );
188205

189-
/**
190-
* Get the geometry object associated with this feature
206+
/** Get the geometry object associated with this feature. If the geometry
207+
* is not going to be modified than calling the const @link constGeometry @endlink
208+
* method is preferable as it avoids a potentially expensive detach operation.
191209
*
192210
* It is possible to modify the geometry in place but this will
193211
* be removed in 3.0 and therefore @link setGeometry @endlink should be called explicitly.
194212
*
195213
* @note will be modified to return by value in QGIS 3.0: `QgsGeometry geometry() const;`
214+
*
215+
* @returns pointer to feature's geometry
216+
* @see constGeometry
217+
* @see geometryAndOwnership
218+
* @see setGeometry
196219
*/
197220
QgsGeometry* geometry();
198221

199-
/** Gets a const pointer to the geometry object associated with this feature.
222+
/** Gets a const pointer to the geometry object associated with this feature. If the geometry
223+
* is not going to be modified than this method is preferable to the non-const
224+
* @link geometry @endlink method.
200225
* @note this is a temporary method for 2.x release cycle. Will be removed in QGIS 3.0.
226+
* @returns const pointer to feature's geometry
227+
* @see geometry
228+
* @see geometryAndOwnership
229+
* @see setGeometry
201230
* @note added in QGIS 2.9
202231
* @note will be removed in QGIS 3.0
203232
*/
204233
const QgsGeometry* constGeometry() const;
205234

206-
/**
207-
* Get the geometry object associated with this feature
208-
* The caller assumes responsibility for the QgsGeometry*'s destruction.
209-
* @deprecated will be removed in QGIS 3.0
235+
/** Get the geometry object associated with this feature, and transfer ownership of the
236+
* geometry to the caller. The caller assumes responsibility for the QgsGeometry*'s destruction.
237+
* @returns pointer to feature's geometry
238+
* @see geometry
239+
* @see setGeometry
210240
*/
211241
Q_DECL_DEPRECATED QgsGeometry *geometryAndOwnership();
212242

213-
/** Set this feature's geometry from another QgsGeometry object (deep copy)
243+
/** Set this feature's geometry from another QgsGeometry object. This method performs a deep copy
244+
* of the geometry.
245+
* @param geom new feature geometry
246+
* @see geometry
247+
* @see constGeometry
248+
* @see geometryAndOwnership
249+
* @see setGeometryAndOwnership
214250
*/
215251
void setGeometry( const QgsGeometry& geom );
216252

217-
/** Set this feature's geometry (takes geometry ownership)
218-
*
253+
/** Set this feature's geometry from a QgsGeometry pointer. Ownership of the geometry is transferred
254+
* to the feature.
255+
* @param geom new feature geometry
219256
* @note not available in python bindings
257+
* @see geometry
258+
* @see constGeometry
259+
* @see geometryAndOwnership
260+
* @see setGeometryAndOwnership
220261
* @deprecated will be removed in QGIS 3.0
221262
*/
222263
void setGeometry( QgsGeometry* geom );
223264

224-
/**
225-
* Set this feature's geometry from WKB
226-
*
227-
* This feature assumes responsibility for destroying geom.
228-
*
265+
/** Set this feature's geometry from WKB. This feature assumes responsibility for destroying the
266+
* created geometry.
267+
* @param geom geometry as WKB
268+
* @param length size of WKB
269+
* @see setGeometry
270+
* @see geometry
271+
* @see constGeometry
272+
* @see geometryAndOwnership
229273
* @deprecated will be removed in QGIS 3.0
230274
*/
231275
void setGeometryAndOwnership( unsigned char * geom, size_t length );
232276

233-
/** Assign a field map with the feature to allow attribute access by attribute name
234-
*
235-
* @param fields The attribute fields which this feature holds. When used from python, make sure
236-
* a copy of the fields is held by python, as ownership stays there.
237-
* I.e. Do not call feature.setFields( myDataProvider.fields() ) but instead call
238-
* myFields = myDataProvider.fields()
239-
* feature.setFields( myFields )
277+
/** Assign a field map with the feature to allow attribute access by attribute name.
278+
* @param fields The attribute fields which this feature holds
240279
* @param initAttributes If true, attributes are initialized. Clears any data previously assigned.
241280
* C++: Defaults to false
242281
* Python: Defaults to true
243-
*
244-
* TODO: QGIS3 - take reference, not pointer
282+
* @deprecated use setFields( const QgsFields& fields, bool initAttributes = false ) instead
283+
* @note not available in Python bindings
245284
*/
246-
void setFields( const QgsFields* fields, bool initAttributes = false );
285+
Q_DECL_DEPRECATED void setFields( const QgsFields* fields, bool initAttributes = false );
247286

248-
/** Get associated field map.
249-
*
250-
* TODO: QGIS 3 - return reference or value, not pointer
287+
/** Assign a field map with the feature to allow attribute access by attribute name.
288+
* @param fields The attribute fields which this feature holds
289+
* @param initAttributes If true, attributes are initialized. Clears any data previously assigned.
290+
* C++: Defaults to false
291+
* Python: Defaults to true
292+
* @note added in QGIS 2.9
293+
* @see fields
294+
*/
295+
void setFields( const QgsFields& fields, bool initAttributes = false );
296+
297+
/** Returns the field map associated with the feature.
298+
* @see setFields
299+
* TODO: QGIS 3 - return value, not pointer
251300
*/
252-
const QgsFields* fields() const { return &mFields; }
301+
const QgsFields* fields() const;
253302

254303
/** Insert a value into attribute. Returns false if attribute name could not be converted to index.
255-
* Field map must be associated to make this work.
256-
*
304+
* Field map must be associated using @link setFields @endlink before this method can be used.
257305
* @param name The name of the field to set
258306
* @param value The value to set
259-
*
260307
* @return false if attribute name could not be converted to index (C++ only)
261-
*
262308
* @note For Python: raises a KeyError exception instead of returning false
309+
* @see setFields
263310
*/
264311
bool setAttribute( const QString& name, QVariant value );
265312

266-
/** Remove an attribute value.
267-
* Returns false if attribute name could not be converted to index.
268-
* Field map must be associated to make this work.
269-
*
313+
/** Removes an attribute value by field name. Field map must be associated using @link setFields @endlink
314+
* before this method can be used.
270315
* @param name The name of the field to delete
271-
*
272316
* @return false if attribute name could not be converted to index (C++ only)
273-
*
274317
* @note For Python: raises a KeyError exception instead of returning false
318+
* @see setFields
275319
*/
276320
bool deleteAttribute( const QString& name );
277321

278-
/** Lookup attribute value from attribute name.
279-
* Returns invalid variant if attribute name could not be converted to index (C++ only)
280-
* Field map must be associated to make this work.
281-
*
322+
/** Lookup attribute value from attribute name. Field map must be associated using @link setFields @endlink
323+
* before this method can be used.
282324
* @param name The name of the attribute to get
283-
*
284325
* @return The value of the attribute (C++: Invalid variant if no such name exists )
285-
*
286326
* @note For Python: raises a KeyError exception if field is not found
327+
* @see setFields
287328
*/
288329
QVariant attribute( const QString& name ) const;
289330

290-
/** Lookup attribute value from its index. Returns invalid variant if the index does not exist.
291-
*
331+
/** Lookup attribute value from its index. Field map must be associated using @link setFields @endlink
332+
* before this method can be used.
292333
* @param fieldIdx The index of the attribute to get
293-
*
294334
* @return The value of the attribute (C++: Invalid variant if no such index exists )
295-
*
296335
* @note For Python: raises a KeyError exception if field is not found
336+
* @see setFields
297337
*/
298338
QVariant attribute( int fieldIdx ) const;
299339

300-
/** Utility method to get attribute index from name. Returns -1 if field does not exist or field map is not associated.
301-
* Field map must be associated to make this work.
340+
/** Utility method to get attribute index from name. Field map must be associated using @link setFields @endlink
341+
* before this method can be used.
342+
* @param fieldName name of field to get attribute index of
343+
* @returns -1 if field does not exist or field map is not associated.
344+
* @see setFields
302345
*/
303346
int fieldNameIndex( const QString& fieldName ) const;
304347

305348
private:
306349

307-
//! feature id
308-
QgsFeatureId mFid;
309-
310-
/** attributes accessed by field index */
311-
QgsAttributes mAttributes;
312-
313-
/** pointer to geometry in binary WKB format
314-
315-
This is usually set by a call to OGRGeometry::exportToWkb()
316-
*/
317-
QgsGeometry *mGeometry;
318-
319-
/** Indicator if the mGeometry is owned by this QgsFeature.
320-
If so, this QgsFeature takes responsibility for the mGeometry's destruction.
321-
*/
322-
bool mOwnsGeometry;
323-
324-
//! Flag to indicate if this feature is valid
325-
bool mValid;
326-
327-
//! Optional field map for name-based attribute lookups
328-
QgsFields mFields;
350+
QExplicitlySharedDataPointer<QgsFeaturePrivate> d;
329351

330352
}; // class QgsFeature
331353

‎src/core/qgsfeature_p.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/***************************************************************************
2+
qgsfeature_p.h
3+
---------------
4+
Date : May-2015
5+
Copyright : (C) 2015 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSFEATURE_PRIVATE_H
17+
#define QGSFEATURE_PRIVATE_H
18+
19+
/// @cond
20+
21+
//
22+
// W A R N I N G
23+
// -------------
24+
//
25+
// This file is not part of the QGIS API. It exists purely as an
26+
// implementation detail. This header file may change from version to
27+
// version without notice, or even be removed.
28+
//
29+
30+
#include "qgsfield.h"
31+
32+
#include "qgsgeometry.h"
33+
34+
class CORE_EXPORT QgsFeaturePrivate : public QSharedData
35+
{
36+
public:
37+
38+
QgsFeaturePrivate( QgsFeatureId id )
39+
: fid( id )
40+
, geometry( 0 )
41+
, ownsGeometry( false )
42+
, valid( false )
43+
{
44+
}
45+
46+
QgsFeaturePrivate( const QgsFeaturePrivate& other )
47+
: QSharedData( other )
48+
, fid( other.fid )
49+
, attributes( other.attributes )
50+
, geometry( other.ownsGeometry ? new QgsGeometry( *other.geometry ) : other.geometry )
51+
, ownsGeometry( other.ownsGeometry )
52+
, valid( other.valid )
53+
, fields( other.fields )
54+
{
55+
}
56+
57+
~QgsFeaturePrivate()
58+
{
59+
if ( ownsGeometry )
60+
delete geometry;
61+
}
62+
63+
//! feature id
64+
QgsFeatureId fid;
65+
66+
/** attributes accessed by field index */
67+
QgsAttributes attributes;
68+
69+
/** pointer to geometry in binary WKB format
70+
71+
This is usually set by a call to OGRGeometry::exportToWkb()
72+
*/
73+
QgsGeometry *geometry;
74+
75+
/** Indicator if the mGeometry is owned by this QgsFeature.
76+
If so, this QgsFeature takes responsibility for the mGeometry's destruction.
77+
*/
78+
bool ownsGeometry;
79+
80+
//! Flag to indicate if this feature is valid
81+
bool valid;
82+
83+
//! Optional field map for name-based attribute lookups
84+
QgsFields fields;
85+
86+
};
87+
88+
/// @endcond
89+
90+
#endif //QGSFEATURE_PRIVATE_H

0 commit comments

Comments
 (0)
Please sign in to comment.