Coverage Report

Created: 2026-07-14 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalvectorpipelinestepalgorithm.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  gdal "vector pipeline" subcommand
5
 * Author:   Even Rouault <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#ifndef GDALVECTORRPIPELINESTEPALGORITHM_INCLUDED
14
#define GDALVECTORRPIPELINESTEPALGORITHM_INCLUDED
15
16
#include "gdalalgorithm.h"
17
#include "gdalpipelinestepalgorithm.h"
18
19
#include "ogrsf_frmts.h"
20
#include "ogrlayerwithtranslatefeature.h"
21
22
#include <map>
23
#include <tuple>
24
#include <vector>
25
26
//! @cond Doxygen_Suppress
27
28
/************************************************************************/
29
/*                   GDALVectorPipelineStepAlgorithm                    */
30
/************************************************************************/
31
32
class GDALVectorPipelineStepAlgorithm /* non final */
33
    : public GDALPipelineStepAlgorithm
34
{
35
  public:
36
    ~GDALVectorPipelineStepAlgorithm() override;
37
38
  protected:
39
    GDALVectorPipelineStepAlgorithm(const std::string &name,
40
                                    const std::string &description,
41
                                    const std::string &helpURL,
42
                                    bool standaloneStep);
43
44
    GDALVectorPipelineStepAlgorithm(const std::string &name,
45
                                    const std::string &description,
46
                                    const std::string &helpURL,
47
                                    const ConstructorOptions &options);
48
49
    friend class GDALVectorPipelineAlgorithm;
50
    friend class GDALVectorConcatAlgorithm;
51
52
    int GetInputType() const override
53
0
    {
54
0
        return GDAL_OF_VECTOR;
55
0
    }
56
57
    int GetOutputType() const override
58
0
    {
59
0
        return GDAL_OF_VECTOR;
60
0
    }
61
};
62
63
/************************************************************************/
64
/*                      GDALVectorDecoratedDataset                      */
65
/************************************************************************/
66
67
/** Base class for GDALVectorOutputDataset, GDALVectorNonStreamingAlgorithmDataset
68
 * and GDALVectorPipelineOutputDataset
69
 */
70
class GDALVectorDecoratedDataset /* non final */
71
    : public GDALDataset
72
{
73
  public:
74
    ~GDALVectorDecoratedDataset() override;
75
76
    CSLConstList GetMetadata(const char *pszDomain) override
77
0
    {
78
0
        return m_srcDS.GetMetadata(pszDomain);
79
0
    }
80
81
    const char *GetMetadataItem(const char *pszName,
82
                                const char *pszDomain) override
83
0
    {
84
0
        return m_srcDS.GetMetadataItem(pszName, pszDomain);
85
0
    }
86
87
    std::vector<std::string>
88
    GetFieldDomainNames(CSLConstList papszOptions) const override
89
0
    {
90
0
        return m_srcDS.GetFieldDomainNames(papszOptions);
91
0
    }
92
93
    const OGRFieldDomain *GetFieldDomain(const std::string &name) const override
94
0
    {
95
0
        return m_srcDS.GetFieldDomain(name);
96
0
    }
97
98
    std::vector<std::string>
99
    GetRelationshipNames(CSLConstList papszOptions) const override
100
0
    {
101
0
        return m_srcDS.GetRelationshipNames(papszOptions);
102
0
    }
103
104
    const GDALRelationship *
105
    GetRelationship(const std::string &name) const override
106
0
    {
107
0
        return m_srcDS.GetRelationship(name);
108
0
    }
109
110
  private:
111
    std::unique_ptr<GDALDataset> m_dummySrcDS{};
112
113
  protected:
114
    explicit GDALVectorDecoratedDataset(GDALDataset *poSrcDS);
115
116
    GDALDataset &m_srcDS;
117
};
118
119
/************************************************************************/
120
/*                       GDALVectorOutputDataset                        */
121
/************************************************************************/
122
123
class GDALVectorOutputDataset : public GDALVectorDecoratedDataset
124
{
125
126
  public:
127
    explicit GDALVectorOutputDataset(GDALDataset *poSrcDS);
128
129
    int GetLayerCount() const override
130
0
    {
131
0
        return static_cast<int>(m_layers.size());
132
0
    }
133
134
    const OGRLayer *GetLayer(int idx) const override
135
0
    {
136
0
        return idx >= 0 && idx < GetLayerCount() ? m_layers[idx].get()
137
0
                                                 : nullptr;
138
0
    }
139
140
    int TestCapability(const char *) const override;
141
142
    void AddLayer(std::unique_ptr<OGRLayer> layer)
143
0
    {
144
0
        m_layers.emplace_back(std::move(layer));
145
0
    }
146
147
  private:
148
    std::vector<std::unique_ptr<OGRLayer>> m_layers{};
149
};
150
151
/************************************************************************/
152
/*                GDALVectorAlgorithmLayerProgressHelper                */
153
/************************************************************************/
154
155
/**
156
 * This class helps doing progress report for algorithm iterating over layers
157
 * of the source dataset.
158
 */
159
class GDALVectorAlgorithmLayerProgressHelper
160
{
161
  public:
162
    /** Constructor */
163
    GDALVectorAlgorithmLayerProgressHelper(GDALProgressFunc pfnProgress,
164
                                           void *pProgressData);
165
    /** Constructor */
166
    explicit GDALVectorAlgorithmLayerProgressHelper(
167
        const GDALPipelineStepRunContext &ctxt);
168
169
    /** Register the passed layer as a layer that will be processed. */
170
    void AddProcessedLayer(OGRLayer &srcLayer);
171
172
    /** Register the passed layer as a layer that will be forwarded without
173
     * processing. */
174
    void AddPassThroughLayer(OGRLayer &srcLayer);
175
176
    //! @cond Doxygen_Suppress
177
    class iterator
178
    {
179
      public:
180
        explicit iterator(const GDALVectorAlgorithmLayerProgressHelper &helper,
181
                          bool start)
182
0
            : m_helper(helper),
183
0
              m_nLayerIdx(start ? 0 : m_helper.m_apoSrcLayers.size())
184
0
        {
185
0
        }
186
187
        inline bool operator==(const iterator &other) const
188
0
        {
189
0
            return m_nLayerIdx == other.m_nLayerIdx;
190
0
        }
191
192
        inline bool operator!=(const iterator &other) const
193
0
        {
194
0
            return m_nLayerIdx != other.m_nLayerIdx;
195
0
        }
196
197
        inline iterator &operator++()
198
0
        {
199
0
            if (!m_helper.m_anFeatures.empty())
200
0
                m_nFeatureIdx += m_helper.m_anFeatures[m_nProcessedLayerIdx];
201
0
            if (m_helper.m_apoSrcLayers[m_nLayerIdx].second)
202
0
                ++m_nProcessedLayerIdx;
203
0
            ++m_nLayerIdx;
204
0
            return *this;
205
0
        }
206
207
        using progress_data_unique_ptr =
208
            std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>;
209
        using value_type = std::tuple<OGRLayer *, bool, GDALProgressFunc,
210
                                      progress_data_unique_ptr>;
211
212
        value_type operator*() const;
213
214
      private:
215
        const GDALVectorAlgorithmLayerProgressHelper &m_helper;
216
        size_t m_nLayerIdx = 0;
217
        size_t m_nProcessedLayerIdx = 0;
218
        GIntBig m_nFeatureIdx = 0;
219
    };
220
221
    //! @endcond
222
223
    /** Start of an iterator over layers registered with AddProcessedLayer()
224
     * and AddUnprocessedLayer() */
225
    iterator begin() const
226
0
    {
227
0
        return iterator(*this, true);
228
0
    }
229
230
    /** End of an iterator over layers registered with AddProcessedLayer()
231
     * and AddUnprocessedLayer() */
232
    iterator end() const
233
0
    {
234
0
        return iterator(*this, false);
235
0
    }
236
237
    /** Return if AddProcessedLayer() has been called at least once. */
238
    bool HasProcessedLayers() const
239
0
    {
240
0
        return !m_anFeatures.empty();
241
0
    }
242
243
  private:
244
    GDALProgressFunc m_pfnProgress = nullptr;
245
    void *m_pProgressData = nullptr;
246
    int64_t m_nTotalFeatures = 0;
247
    std::vector<std::pair<OGRLayer *, bool>> m_apoSrcLayers{};
248
    std::vector<int64_t> m_anFeatures{};
249
250
    CPL_DISALLOW_COPY_ASSIGN(GDALVectorAlgorithmLayerProgressHelper)
251
};
252
253
/************************************************************************/
254
/*                    GDALVectorPipelineOutputLayer                     */
255
/************************************************************************/
256
257
/** Class that implements GetNextFeature() by forwarding to
258
 * OGRLayerWithTranslateFeature::TranslateFeature() implementation, which
259
 * might return several features, and must apply layer filters.
260
 */
261
class GDALVectorPipelineOutputLayer /* non final */
262
    : public OGRLayerWithTranslateFeature
263
{
264
  protected:
265
    explicit GDALVectorPipelineOutputLayer(OGRLayer &oSrcLayer);
266
    ~GDALVectorPipelineOutputLayer() override;
267
268
    OGRLayer &m_srcLayer;
269
270
    void FailTranslation()
271
0
    {
272
0
        m_translateError = true;
273
0
    }
274
275
    bool PassesFilters(const OGRFeature *poFeature);
276
277
  public:
278
    void ResetReading() override;
279
280
    OGRFeature *GetNextFeature() override final;
281
282
  private:
283
    std::vector<std::unique_ptr<OGRFeature>> m_pendingFeatures{};
284
    size_t m_idxInPendingFeatures = 0;
285
    bool m_translateError = false;
286
};
287
288
/************************************************************************/
289
/*                  GDALVectorPipelinePassthroughLayer                  */
290
/************************************************************************/
291
292
/** Class that forwards GetNextFeature() calls to the source layer and
293
 * can be added to GDALVectorPipelineOutputDataset::AddLayer()
294
 */
295
class GDALVectorPipelinePassthroughLayer /* non final */
296
    : public GDALVectorPipelineOutputLayer
297
{
298
  public:
299
    explicit GDALVectorPipelinePassthroughLayer(OGRLayer &oSrcLayer)
300
0
        : GDALVectorPipelineOutputLayer(oSrcLayer)
301
0
    {
302
0
        GDALVectorPipelinePassthroughLayer::SetDescription(
303
0
            oSrcLayer.GetDescription());
304
0
    }
Unexecuted instantiation: GDALVectorPipelinePassthroughLayer::GDALVectorPipelinePassthroughLayer(OGRLayer&)
Unexecuted instantiation: GDALVectorPipelinePassthroughLayer::GDALVectorPipelinePassthroughLayer(OGRLayer&)
305
306
    const OGRFeatureDefn *GetLayerDefn() const override;
307
308
    int TestCapability(const char *pszCap) const override
309
0
    {
310
0
        if (EQUAL(pszCap, OLCFastFeatureCount))
311
0
            return false;
312
0
        return m_srcLayer.TestCapability(pszCap);
313
0
    }
314
315
    OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
316
                      bool bForce) override
317
0
    {
318
0
        return m_srcLayer.GetExtent(iGeomField, psExtent, bForce);
319
0
    }
320
321
    OGRErr IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent,
322
                        bool bForce) override
323
0
    {
324
0
        return m_srcLayer.GetExtent3D(iGeomField, psExtent, bForce);
325
0
    }
326
327
    bool TranslateFeature(
328
        std::unique_ptr<OGRFeature> poSrcFeature,
329
        std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override;
330
};
331
332
/************************************************************************/
333
/*                 GDALVectorNonStreamingAlgorithmLayer                 */
334
/************************************************************************/
335
336
/**
337
 * This class represents a layer for algorithms that process vector data
338
 * in a non-streaming manner.
339
 *
340
 * Implementations must override the following methods:
341
 * - Process(), which is called when the first feature is read
342
 * - GetNextProcessedFeature() method which provides features in sequential order
343
 */
344
class GDALVectorNonStreamingAlgorithmLayer
345
    : public OGRLayer,
346
      public OGRGetNextFeatureThroughRaw<GDALVectorNonStreamingAlgorithmLayer>
347
{
348
  public:
349
    GDALVectorNonStreamingAlgorithmLayer(OGRLayer &srcLayer,
350
                                         int geomFieldIndex);
351
352
    ~GDALVectorNonStreamingAlgorithmLayer() override;
353
354
    const char *GetDescription() const override
355
0
    {
356
0
        return GetName();
357
0
    }
358
359
    virtual bool Process(GDALProgressFunc pfnProgress, void *pProgressData) = 0;
360
361
    virtual std::unique_ptr<OGRFeature> GetNextProcessedFeature() = 0;
362
363
    OGRFeature *GetNextRawFeature();
364
365
    DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(GDALVectorNonStreamingAlgorithmLayer)
366
367
  protected:
368
    OGRLayer &m_srcLayer;
369
    int m_geomFieldIndex{0};
370
371
  private:
372
    CPL_DISALLOW_COPY_ASSIGN(GDALVectorNonStreamingAlgorithmLayer)
373
};
374
375
/************************************************************************/
376
/*                GDALVectorNonStreamingAlgorithmDataset                */
377
/************************************************************************/
378
379
/**
380
 * Dataset used to read all input features into memory and perform some
381
 * processing.
382
 */
383
class GDALVectorNonStreamingAlgorithmDataset /* non final */
384
    : public GDALVectorDecoratedDataset
385
{
386
  public:
387
    explicit GDALVectorNonStreamingAlgorithmDataset(GDALDataset &oSrcDS);
388
    ~GDALVectorNonStreamingAlgorithmDataset() override;
389
390
    /** Add a layer to the dataset and perform the associated processing. */
391
    bool AddProcessedLayer(
392
        std::unique_ptr<GDALVectorNonStreamingAlgorithmLayer> srcLayer,
393
        GDALProgressFunc progressFunc, void *progressData);
394
395
    void AddPassThroughLayer(OGRLayer &oLayer);
396
397
    int GetLayerCount() const final override;
398
    OGRLayer *GetLayer(int idx) const final override;
399
    int TestCapability(const char *pszCap) const override;
400
401
  private:
402
    std::vector<std::unique_ptr<OGRLayer>> m_owned_layers{};
403
    std::vector<OGRLayer *> m_layers{};
404
};
405
406
/************************************************************************/
407
/*                   GDALVectorPipelineOutputDataset                    */
408
/************************************************************************/
409
410
/** Class used by vector pipeline steps to create an output on-the-fly
411
 * dataset where they can store on-the-fly layers.
412
 */
413
class GDALVectorPipelineOutputDataset /* non final */
414
    : public GDALVectorDecoratedDataset
415
{
416
    std::map<OGRLayer *, OGRLayerWithTranslateFeature *>
417
        m_mapSrcLayerToNewLayer{};
418
    std::vector<std::unique_ptr<OGRLayerWithTranslateFeature>>
419
        m_layersToDestroy{};
420
    std::vector<OGRLayerWithTranslateFeature *> m_layers{};
421
422
    OGRLayerWithTranslateFeature *m_belongingLayer = nullptr;
423
    std::vector<std::unique_ptr<OGRFeature>> m_pendingFeatures{};
424
    size_t m_idxInPendingFeatures = 0;
425
426
    CPL_DISALLOW_COPY_ASSIGN(GDALVectorPipelineOutputDataset)
427
428
  public:
429
    explicit GDALVectorPipelineOutputDataset(GDALDataset &oSrcDS);
430
431
    void AddLayer(OGRLayer &oSrcLayer,
432
                  std::unique_ptr<OGRLayerWithTranslateFeature> poNewLayer);
433
434
    int GetLayerCount() const override;
435
436
    OGRLayer *GetLayer(int idx) const override;
437
438
    int TestCapability(const char *pszCap) const override;
439
440
    void ResetReading() override;
441
442
    OGRFeature *GetNextFeature(OGRLayer **ppoBelongingLayer,
443
                               double *pdfProgressPct,
444
                               GDALProgressFunc pfnProgress,
445
                               void *pProgressData) override;
446
};
447
448
//! @endcond
449
450
#endif