QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
qgsvectorlayercache.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsvectorlayercache.cpp
3 Cache features of a vector layer
4 -------------------
5 begin : January 2013
6 copyright : (C) Matthias Kuhn
7 email : matthias at opengis dot ch
8
9 ***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgsvectorlayercache.h"
19
21#include "qgscacheindex.h"
22#include "qgsvectorlayer.h"
25
26#include <QElapsedTimer>
27
28#include "moc_qgsvectorlayercache.cpp"
29
31 : QObject( parent )
32 , mLayer( layer )
33{
34 mCache.setMaxCost( cacheSize );
35
36 connect( mLayer, &QgsVectorLayer::featureDeleted, this, &QgsVectorLayerCache::featureDeleted );
37 connect( mLayer, &QgsVectorLayer::featureAdded, this, &QgsVectorLayerCache::onFeatureAdded );
38 connect( mLayer, &QgsVectorLayer::destroyed, this, &QgsVectorLayerCache::layerDeleted );
39
40 setCacheGeometry( true );
41 setCacheSubsetOfAttributes( mLayer->attributeList() );
43
44 connect( mLayer, &QgsVectorLayer::attributeDeleted, this, &QgsVectorLayerCache::attributeDeleted );
45 connect( mLayer, &QgsVectorLayer::updatedFields, this, &QgsVectorLayerCache::invalidate );
46 connect( mLayer, &QgsVectorLayer::dataChanged, this, &QgsVectorLayerCache::invalidate );
47 connect( mLayer, &QgsVectorLayer::attributeValueChanged, this, &QgsVectorLayerCache::onAttributeValueChanged );
48
49 connectJoinedLayers();
50}
51
53{
54 qDeleteAll( mCacheIndices );
55 mCacheIndices.clear();
56}
57
59{
60 mCache.setMaxCost( cacheSize );
61}
62
64{
65 return mCache.maxCost();
66}
67
69{
70 bool shouldCacheGeometry = cacheGeometry && mLayer->isSpatial();
71 bool mustInvalidate = shouldCacheGeometry && !mCacheGeometry; // going from no geometry -> geometry, so have to clear existing cache entries
72 mCacheGeometry = shouldCacheGeometry;
73 if ( cacheGeometry )
74 {
75 connect( mLayer, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayerCache::geometryChanged, Qt::UniqueConnection );
76 }
77 else
78 {
79 disconnect( mLayer, &QgsVectorLayer::geometryChanged, this, &QgsVectorLayerCache::geometryChanged );
80 }
81 if ( mustInvalidate )
82 {
83 invalidate();
84 }
85}
86
88{
89 if ( ! mCache.isEmpty() && ! QSet<int>( mCachedAttributes.cbegin(), mCachedAttributes.cend() )
90 .contains( QSet<int>( attributes.cbegin(), attributes.cend( ) ) ) )
91 invalidate();
92 mCachedAttributes = attributes;
93}
94
96{
97 return mCachedAttributes;
98}
99
101{
102 mFullCache = fullCache;
103
104 if ( mFullCache )
105 {
106 // Add a little more than necessary...
107 setCacheSize( mLayer->featureCount() + 100 );
108
109 // Initialize the cache...
111 .setSubsetOfAttributes( mCachedAttributes )
113
114 int i = 0;
115
116 QElapsedTimer t;
117 t.start();
118
119 QgsFeature f;
120 while ( it.nextFeature( f ) )
121 {
122 ++i;
123
124 if ( t.elapsed() > 1000 )
125 {
126 bool cancel = false;
127 emit progress( i, cancel );
128 if ( cancel )
129 break;
130
131 t.restart();
132 }
133 }
134
135 it.close();
136
137 emit finished();
138 }
139}
140
142{
143 mCacheIndices.append( cacheIndex );
144}
145
146void QgsVectorLayerCache::setCacheAddedAttributes( bool cacheAddedAttributes )
147{
148 if ( cacheAddedAttributes )
149 {
150 connect( mLayer, &QgsVectorLayer::attributeAdded, this, &QgsVectorLayerCache::attributeAdded );
151 }
152 else
153 {
154 disconnect( mLayer, &QgsVectorLayer::attributeAdded, this, &QgsVectorLayerCache::attributeAdded );
155 }
156}
157
158bool QgsVectorLayerCache::featureAtId( QgsFeatureId featureId, QgsFeature &feature, bool skipCache )
159{
160 bool featureFound = false;
161
162 QgsCachedFeature *cachedFeature = nullptr;
163
164 if ( !skipCache )
165 {
166 cachedFeature = mCache[ featureId ];
167 }
168
169 if ( cachedFeature )
170 {
171 feature = QgsFeature( *cachedFeature->feature() );
172 featureFound = true;
173 }
174 else
175 {
176 QgsFeatureRequest request { featureId };
177 const bool allAttrsFetched { mCachedAttributes.count( ) == mLayer->fields().count() };
178 if ( ! allAttrsFetched )
179 {
180 request.setSubsetOfAttributes( mCachedAttributes );
181 }
182 if ( !mCacheGeometry )
183 {
184 request.setFlags( request.flags().setFlag( Qgis::FeatureRequestFlag::NoGeometry ) );
185 }
186 if ( mLayer->getFeatures( request ).nextFeature( feature ) )
187 {
188 cacheFeature( feature, allAttrsFetched );
189 featureFound = true;
190 }
191 }
192
193 return featureFound;
194}
195
197{
198
199 bool featureFound = false;
200
201 QgsCachedFeature *cachedFeature = nullptr;
202
203 if ( !skipCache )
204 {
205 cachedFeature = mCache[ featureId ];
206 }
207
208 if ( cachedFeature && cachedFeature->allAttributesFetched() )
209 {
210 feature = QgsFeature( *cachedFeature->feature() );
211 featureFound = true;
212 }
213 else if ( mLayer->getFeatures( QgsFeatureRequest()
214 .setFilterFid( featureId )
215 .setFlags( !mCacheGeometry ? Qgis::FeatureRequestFlag::NoGeometry : Qgis::FeatureRequestFlags() ) )
216 .nextFeature( feature ) )
217 {
218 cacheFeature( feature, true );
219 featureFound = true;
220 }
221
222 return featureFound;
223}
224
225bool QgsVectorLayerCache::completeFeatureAtId( QgsFeatureId featureId, QgsFeature &feature, bool skipCache )
226{
227 bool featureFound = false;
228
229 QgsCachedFeature *cachedFeature = nullptr;
230
231 if ( !skipCache )
232 {
233 cachedFeature = mCache[ featureId ];
234 }
235
236 if ( cachedFeature && cachedFeature->allAttributesFetched() && cachedFeature->geometryFetched() )
237 {
238 feature = QgsFeature( *cachedFeature->feature() );
239 featureFound = true;
240 }
241 else if ( mLayer->getFeatures( QgsFeatureRequest()
242 .setFilterFid( featureId ) )
243 .nextFeature( feature ) )
244 {
245 cacheFeature( feature, true, true );
246 featureFound = true;
247 }
248
249 return featureFound;
250}
251
253{
254 bool removed = mCache.remove( fid );
255 if ( removed )
256 {
257 if ( auto unorderedIt = std::find( mCacheUnorderedKeys.begin(), mCacheUnorderedKeys.end(), fid ); unorderedIt != mCacheUnorderedKeys.end() )
258 {
259 mCacheUnorderedKeys.erase( unorderedIt );
260
261 if ( auto orderedIt = std::find( mCacheOrderedKeys.begin(), mCacheOrderedKeys.end(), fid ); orderedIt != mCacheOrderedKeys.end() )
262 mCacheOrderedKeys.erase( orderedIt );
263 }
264 }
265 return removed;
266}
267
269{
270 return mLayer;
271}
272
274{
275 return mLayer->crs();
276}
277
279{
280 return mLayer->wkbType();
281}
282
284{
285 return mLayer->fields();
286}
287
289{
290 return mLayer->featureCount();
291}
292
294{
295 // If a request is too large for the cache don't notify to prevent from indexing incomplete requests
296 if ( fids.count() <= mCache.size() )
297 {
298 for ( const auto &idx : std::as_const( mCacheIndices ) )
299 {
300 idx->requestCompleted( featureRequest, fids );
301 }
302 if ( featureRequest.filterType() == Qgis::FeatureRequestFilterType::NoFilter &&
303 ( featureRequest.spatialFilterType() == Qgis::SpatialFilterType::NoFilter || featureRequest.filterRect().contains( mLayer->extent() ) ) )
304 {
305 mFullCache = true;
306 }
307 }
308}
309
311{
312 const auto constMCacheIndices = mCacheIndices;
313 for ( QgsAbstractCacheIndex *idx : constMCacheIndices )
314 {
315 idx->flushFeature( fid );
316 }
317}
318
319void QgsVectorLayerCache::onAttributeValueChanged( QgsFeatureId fid, int field, const QVariant &value )
320{
321 QgsCachedFeature *cachedFeat = mCache[ fid ];
322
323 if ( cachedFeat )
324 {
325 cachedFeat->mFeature->setAttribute( field, value );
326 }
327
328 emit attributeValueChanged( fid, field, value );
329}
330
331void QgsVectorLayerCache::onJoinAttributeValueChanged( QgsFeatureId fid, int field, const QVariant &value )
332{
333 const QgsVectorLayer *joinLayer = qobject_cast<const QgsVectorLayer *>( sender() );
334
335 const auto constVectorJoins = mLayer->vectorJoins();
336 for ( const QgsVectorLayerJoinInfo &info : constVectorJoins )
337 {
338 if ( joinLayer == info.joinLayer() )
339 {
340 const QgsFeature feature = mLayer->joinBuffer()->targetedFeatureOf( &info, joinLayer->getFeature( fid ) );
341
342 const QString fieldName = info.prefixedFieldName( joinLayer->fields().field( field ) );
343 const int fieldIndex = mLayer->fields().indexFromName( fieldName );
344
345 if ( feature.isValid() && fieldIndex != -1 )
346 {
347 onAttributeValueChanged( feature.id(), fieldIndex, value );
348 return;
349 }
350 }
351 }
352}
353
354void QgsVectorLayerCache::featureDeleted( QgsFeatureId fid )
355{
356 mCache.remove( fid );
357
358 if ( auto it = mCacheUnorderedKeys.find( fid ); it != mCacheUnorderedKeys.end() )
359 {
360 mCacheUnorderedKeys.erase( it );
361 if ( auto orderedIt = std::find( mCacheOrderedKeys.begin(), mCacheOrderedKeys.end(), fid ); orderedIt != mCacheOrderedKeys.end() )
362 mCacheOrderedKeys.erase( orderedIt );
363 }
364}
365
366void QgsVectorLayerCache::onFeatureAdded( QgsFeatureId fid )
367{
368 if ( mFullCache )
369 {
370 if ( cacheSize() <= mLayer->featureCount() )
371 {
372 setCacheSize( mLayer->featureCount() + 100 );
373 }
374
375 QgsFeature feat;
376 featureAtId( fid, feat );
377 }
378 emit featureAdded( fid );
379}
380
381void QgsVectorLayerCache::attributeAdded( int field )
382{
383 Q_UNUSED( field )
384 mCachedAttributes.append( field );
385 invalidate();
386}
387
388void QgsVectorLayerCache::attributeDeleted( int field )
389{
390 const QgsAttributeList attrs = mCachedAttributes;
391 mCachedAttributes.clear();
392
393 for ( int attr : attrs )
394 {
395 if ( attr < field )
396 mCachedAttributes << attr;
397 else if ( attr > field )
398 mCachedAttributes << attr - 1;
399 }
400}
401
402void QgsVectorLayerCache::geometryChanged( QgsFeatureId fid, const QgsGeometry &geom )
403{
404 QgsCachedFeature *cachedFeat = mCache[ fid ];
405
406 if ( cachedFeat )
407 {
408 cachedFeat->mFeature->setGeometry( geom );
409 }
410}
411
412void QgsVectorLayerCache::layerDeleted()
413{
414 emit cachedLayerDeleted();
415 mLayer = nullptr;
416}
417
418void QgsVectorLayerCache::invalidate()
419{
420 if ( ! mCache.isEmpty() )
421 {
422 mCache.clear();
423 mCacheOrderedKeys.clear();
424 mCacheUnorderedKeys.clear();
425 mFullCache = false;
426 emit invalidated();
427 }
428}
429
430bool QgsVectorLayerCache::canUseCacheForRequest( const QgsFeatureRequest &featureRequest, QgsFeatureIterator &it )
431{
432 // check first for available indices
433 const auto constMCacheIndices = mCacheIndices;
434 for ( QgsAbstractCacheIndex *idx : constMCacheIndices )
435 {
436 if ( idx->getCacheIterator( it, featureRequest ) )
437 {
438 return true;
439 }
440 }
441
442 // no indexes available, but maybe we have already cached all required features anyway?
443 switch ( featureRequest.filterType() )
444 {
446 {
447 if ( mCache.contains( featureRequest.filterFid() ) )
448 {
449 it = QgsFeatureIterator( new QgsCachedFeatureIterator( this, featureRequest ) );
450 return true;
451 }
452 break;
453 }
455 {
456 if ( cachedFeatureIds().contains( featureRequest.filterFids() ) )
457 {
458 it = QgsFeatureIterator( new QgsCachedFeatureIterator( this, featureRequest ) );
459 return true;
460 }
461 break;
462 }
465 {
466 if ( mFullCache )
467 {
468 it = QgsFeatureIterator( new QgsCachedFeatureIterator( this, featureRequest ) );
469 return true;
470 }
471 break;
472 }
473
474 }
475 return false;
476}
477
479{
481 bool requiresWriterIt = true; // If a not yet cached, but cacheable request is made, this stays true.
482
483 if ( checkInformationCovered( featureRequest ) )
484 {
485 // If we have a full cache available, run on this
486 if ( mFullCache )
487 {
488 it = QgsFeatureIterator( new QgsCachedFeatureIterator( this, featureRequest ) );
489 requiresWriterIt = false;
490 }
491 else
492 {
493 // may still be able to satisfy request using cache
494 requiresWriterIt = !canUseCacheForRequest( featureRequest, it );
495 }
496 }
497 else
498 {
499 // Let the layer answer the request, so no caching of requests
500 // we don't want to cache is done
501 requiresWriterIt = false;
502 it = mLayer->getFeatures( featureRequest );
503 }
504
505 if ( requiresWriterIt && mLayer->dataProvider() )
506 {
507 // No index was able to satisfy the request
508 QgsFeatureRequest myRequest = QgsFeatureRequest( featureRequest );
509
510 // Make sure if we cache the geometry, it gets fetched
511 if ( mCacheGeometry && mLayer->isSpatial() )
512 myRequest.setFlags( featureRequest.flags() & ~( static_cast< int >( Qgis::FeatureRequestFlag::NoGeometry ) ) );
513
514 // Make sure all the cached attributes are requested as well if requesting a subset
515 if ( myRequest.flags().testFlag( Qgis::FeatureRequestFlag::SubsetOfAttributes ) )
516 {
517 if ( mCachedAttributes.count( ) != mLayer->fields().count() )
518 {
519 const QgsAttributeList requestSubset = featureRequest.subsetOfAttributes();
520 QSet<int> attrs( requestSubset.begin(), requestSubset.end() );
521 for ( int attr : std::as_const( mCachedAttributes ) )
522 attrs.insert( attr );
523 myRequest.setSubsetOfAttributes( attrs.values() );
524 }
525 else // we are already caching all attributes
526 {
528 myRequest.setFlags( myRequest.flags().setFlag( Qgis::FeatureRequestFlag::SubsetOfAttributes, false ) );
529 }
530 }
531
532 it = QgsFeatureIterator( new QgsCachedFeatureWriterIterator( this, myRequest ) );
533 }
534
535 return it;
536}
537
539{
540 return mCache.contains( fid );
541}
542
544{
545 const QList< QgsFeatureId > keys = mCache.keys();
546 return QgsFeatureIds( keys.begin(), keys.end() );
547}
548
550{
551 QgsAttributeList requestedAttributes;
552
553 if ( !featureRequest.flags().testFlag( Qgis::FeatureRequestFlag::SubsetOfAttributes ) )
554 {
555 requestedAttributes = mLayer->attributeList();
556 }
557 else
558 {
559 requestedAttributes = featureRequest.subsetOfAttributes();
560 }
561
562 // Check if we even cache the information requested
563 const auto constRequestedAttributes = requestedAttributes;
564 for ( int attr : constRequestedAttributes )
565 {
566 if ( !mCachedAttributes.contains( attr ) )
567 {
568 return false;
569 }
570 }
571
572 // If the request needs geometry but we don't cache this...
573 return !( !featureRequest.flags().testFlag( Qgis::FeatureRequestFlag::NoGeometry )
574 && !mCacheGeometry );
575}
576
577void QgsVectorLayerCache::connectJoinedLayers() const
578{
579 const auto constVectorJoins = mLayer->vectorJoins();
580 for ( const QgsVectorLayerJoinInfo &info : constVectorJoins )
581 {
582 const QgsVectorLayer *vl = info.joinLayer();
583 if ( vl )
584 connect( vl, &QgsVectorLayer::attributeValueChanged, this, &QgsVectorLayerCache::onJoinAttributeValueChanged );
585 }
586}
587
588bool QgsVectorLayerCache::QgsCachedFeature::allAttributesFetched() const
589{
590 return mAllAttributesFetched;
591}
592
593bool QgsVectorLayerCache::QgsCachedFeature::geometryFetched() const
594{
595 return mGeometryFetched;
596}
@ Fid
Filter using feature ID.
Definition qgis.h:2224
@ Fids
Filter using feature IDs.
Definition qgis.h:2226
@ Expression
Filter using expression.
Definition qgis.h:2225
@ NoFilter
No filter is applied.
Definition qgis.h:2223
@ SubsetOfAttributes
Fetch only a subset of attributes (setSubsetOfAttributes sets this flag).
Definition qgis.h:2197
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2196
@ NoFlags
No flags are set.
Definition qgis.h:2195
@ NoFilter
No spatial filtering of features.
Definition qgis.h:2252
QFlags< FeatureRequestFlag > FeatureRequestFlags
Flags for controlling feature requests.
Definition qgis.h:2211
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:277
Abstract base class for cache indices.
Represents a coordinate reference system (CRS).
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
bool close()
Call to end the iteration.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsRectangle filterRect() const
Returns the rectangle from which features will be taken.
Qgis::FeatureRequestFilterType filterType() const
Returns the attribute/ID filter type which is currently set on this request.
Qgis::FeatureRequestFlags flags() const
Returns the flags which affect how features are fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Qgis::SpatialFilterType spatialFilterType() const
Returns the spatial filter type which is currently set on this request.
QgsAttributeList subsetOfAttributes() const
Returns the subset of attributes which at least need to be fetched.
const QgsFeatureIds & filterFids() const
Returns the feature IDs that should be fetched.
QgsFeatureId filterFid() const
Returns the feature ID that should be fetched.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsFeatureId id
Definition qgsfeature.h:66
bool isValid() const
Returns the validity of this feature.
Container of fields for a vector layer.
Definition qgsfields.h:46
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
A geometry is the spatial representation of a feature.
void dataChanged()
Data of layer changed.
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
bool isFidCached(QgsFeatureId fid) const
Check if a certain feature id is cached.
void setFullCache(bool fullCache)
This enables or disables full caching.
void finished()
When filling the cache, this signal gets emitted once the cache is fully initialized.
void featureRemoved(QgsFeatureId fid)
Gets called, whenever a feature has been removed.
void setCacheAddedAttributes(bool cacheAddedAttributes)
If this is enabled, the subset of cached attributes will automatically be extended to also include ne...
void invalidated()
The cache has been invalidated and cleared.
void setCacheSize(int cacheSize)
Sets the maximum number of features to keep in the cache.
void setCacheSubsetOfAttributes(const QgsAttributeList &attributes)
Set the list (possibly a subset) of attributes to be cached.
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer and this cache.
QgsFields fields() const
Returns the fields associated with features in the cache.
void cachedLayerDeleted()
Is emitted when the cached layer is deleted.
friend class QgsCachedFeatureWriterIterator
void requestCompleted(const QgsFeatureRequest &featureRequest, const QgsFeatureIds &fids)
Gets called, whenever the full list of feature ids for a certain request is known.
void attributeValueChanged(QgsFeatureId fid, int field, const QVariant &value)
Emitted when an attribute is changed.
bool removeCachedFeature(QgsFeatureId fid)
Removes the feature identified by fid from the cache if present.
void progress(int i, bool &cancel)
When filling the cache, this signal gets emitted periodically to notify about the progress and to be ...
QgsVectorLayer * layer()
Returns the layer to which this cache belongs.
long long featureCount() const
Returns the number of features contained in the source, or -1 if the feature count is unknown.
QgsCoordinateReferenceSystem sourceCrs() const
Returns the coordinate reference system for features in the cache.
bool checkInformationCovered(const QgsFeatureRequest &featureRequest)
Checks if the information required to complete the request is cached.
QgsFeatureIds cachedFeatureIds() const
Returns the set of feature IDs for features which are cached.
bool featureAtIdWithAllAttributes(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id with all attributes, if the cached feature already contains ...
bool cacheGeometry() const
Returns true if the cache will fetch and cache feature geometries.
Qgis::WkbType wkbType() const
Returns the geometry type for features in the cache.
int cacheSize()
Returns the maximum number of features this cache will hold.
friend class QgsCachedFeatureIterator
QgsAttributeList cacheSubsetOfAttributes() const
Returns the list (possibly a subset) of cached attributes.
void addCacheIndex(QgsAbstractCacheIndex *cacheIndex)
Adds a QgsAbstractCacheIndex to this cache.
QgsVectorLayerCache(QgsVectorLayer *layer, int cacheSize, QObject *parent=nullptr)
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest=QgsFeatureRequest())
Query this VectorLayerCache for features.
bool completeFeatureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id with all attributes and geometry, if the cached feature alre...
bool featureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id.
Defines left outer join from our vector layer to some other vector layer.
Represents a vector layer which manages a vector based dataset.
void attributeAdded(int idx)
Will be emitted, when a new attribute has been added to this vector layer.
void attributeDeleted(int idx)
Will be emitted, when an attribute has been deleted from this vector layer.
void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Emitted whenever an attribute value change is done in the edit buffer.
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer.
void featureDeleted(QgsFeatureId fid)
Emitted when a feature has been deleted.
const QList< QgsVectorLayerJoinInfo > vectorJoins() const
void geometryChanged(QgsFeatureId fid, const QgsGeometry &geometry)
Emitted whenever a geometry change is done in the edit buffer.
Q_INVOKABLE QgsFeature getFeature(QgsFeatureId fid) const
Queries the layer for the feature with the given id.
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
Definition qgsfield.h:28