LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_pipeline.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 283 292 96.9 %
Date: 2025-02-20 10:14:44 Functions: 17 18 94.4 %

          Line data    Source code
       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             : #include "gdalalg_vector_pipeline.h"
      14             : #include "gdalalg_vector_read.h"
      15             : #include "gdalalg_vector_clip.h"
      16             : #include "gdalalg_vector_filter.h"
      17             : #include "gdalalg_vector_reproject.h"
      18             : #include "gdalalg_vector_select.h"
      19             : #include "gdalalg_vector_sql.h"
      20             : #include "gdalalg_vector_write.h"
      21             : 
      22             : #include "cpl_conv.h"
      23             : #include "cpl_string.h"
      24             : 
      25             : #include <algorithm>
      26             : #include <cassert>
      27             : 
      28             : //! @cond Doxygen_Suppress
      29             : 
      30             : #ifndef _
      31             : #define _(x) (x)
      32             : #endif
      33             : 
      34             : /************************************************************************/
      35             : /*  GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm()  */
      36             : /************************************************************************/
      37             : 
      38         356 : GDALVectorPipelineStepAlgorithm::GDALVectorPipelineStepAlgorithm(
      39             :     const std::string &name, const std::string &description,
      40         356 :     const std::string &helpURL, bool standaloneStep)
      41             :     : GDALAlgorithm(name, description, helpURL),
      42         356 :       m_standaloneStep(standaloneStep)
      43             : {
      44         356 :     if (m_standaloneStep)
      45             :     {
      46          59 :         AddInputArgs(false);
      47          59 :         AddProgressArg();
      48          59 :         AddOutputArgs(false, false);
      49             :     }
      50         356 : }
      51             : 
      52             : /************************************************************************/
      53             : /*             GDALVectorPipelineStepAlgorithm::AddInputArgs()          */
      54             : /************************************************************************/
      55             : 
      56         220 : void GDALVectorPipelineStepAlgorithm::AddInputArgs(bool hiddenForCLI)
      57             : {
      58         220 :     AddInputFormatsArg(&m_inputFormats)
      59         660 :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR})
      60         220 :         .SetHiddenForCLI(hiddenForCLI);
      61         220 :     AddOpenOptionsArg(&m_openOptions).SetHiddenForCLI(hiddenForCLI);
      62             :     AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR,
      63         220 :                        /* positionalAndRequired = */ !hiddenForCLI)
      64         220 :         .SetHiddenForCLI(hiddenForCLI);
      65         220 :     if (GetName() != "sql")
      66             :     {
      67         422 :         AddArg("input-layer", 'l', _("Input layer name(s)"), &m_inputLayerNames)
      68         422 :             .AddAlias("layer")
      69         211 :             .SetHiddenForCLI(hiddenForCLI);
      70             :     }
      71         220 : }
      72             : 
      73             : /************************************************************************/
      74             : /*             GDALVectorPipelineStepAlgorithm::AddOutputArgs()         */
      75             : /************************************************************************/
      76             : 
      77         218 : void GDALVectorPipelineStepAlgorithm::AddOutputArgs(
      78             :     bool hiddenForCLI, bool shortNameOutputLayerAllowed)
      79             : {
      80         218 :     AddOutputFormatArg(&m_format, true)
      81             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      82         872 :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE})
      83         218 :         .SetHiddenForCLI(hiddenForCLI);
      84             :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
      85         218 :                         /* positionalAndRequired = */ !hiddenForCLI)
      86         218 :         .SetHiddenForCLI(hiddenForCLI);
      87         218 :     m_outputDataset.SetInputFlags(GADV_NAME | GADV_OBJECT);
      88         218 :     AddCreationOptionsArg(&m_creationOptions).SetHiddenForCLI(hiddenForCLI);
      89         218 :     AddLayerCreationOptionsArg(&m_layerCreationOptions)
      90         218 :         .SetHiddenForCLI(hiddenForCLI);
      91         218 :     AddOverwriteArg(&m_overwrite).SetHiddenForCLI(hiddenForCLI);
      92         218 :     AddUpdateArg(&m_update).SetHiddenForCLI(hiddenForCLI);
      93             :     AddArg("overwrite-layer", 0,
      94             :            _("Whether overwriting existing layer is allowed"),
      95         436 :            &m_overwriteLayer)
      96         436 :         .SetDefault(false)
      97         218 :         .SetHiddenForCLI(hiddenForCLI);
      98             :     AddArg("append", 0, _("Whether appending to existing layer is allowed"),
      99         436 :            &m_appendLayer)
     100         436 :         .SetDefault(false)
     101         218 :         .SetHiddenForCLI(hiddenForCLI);
     102         218 :     if (GetName() != "sql")
     103             :     {
     104             :         AddArg("output-layer", shortNameOutputLayerAllowed ? 'l' : 0,
     105         418 :                _("Output layer name"), &m_outputLayerName)
     106         418 :             .AddHiddenAlias("nln")  // For ogr2ogr nostalgic people
     107         209 :             .SetHiddenForCLI(hiddenForCLI);
     108             :     }
     109         218 : }
     110             : 
     111             : /************************************************************************/
     112             : /*            GDALVectorPipelineStepAlgorithm::RunImpl()                */
     113             : /************************************************************************/
     114             : 
     115         237 : bool GDALVectorPipelineStepAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
     116             :                                               void *pProgressData)
     117             : {
     118         237 :     if (m_standaloneStep)
     119             :     {
     120         108 :         GDALVectorReadAlgorithm readAlg;
     121         540 :         for (auto &arg : readAlg.GetArgs())
     122             :         {
     123         486 :             auto stepArg = GetArg(arg->GetName());
     124         486 :             if (stepArg && stepArg->IsExplicitlySet())
     125             :             {
     126          54 :                 arg->SetSkipIfAlreadySet(true);
     127          54 :                 arg->SetFrom(*stepArg);
     128             :             }
     129             :         }
     130             : 
     131          54 :         GDALVectorWriteAlgorithm writeAlg;
     132         810 :         for (auto &arg : writeAlg.GetArgs())
     133             :         {
     134         756 :             auto stepArg = GetArg(arg->GetName());
     135         756 :             if (stepArg && stepArg->IsExplicitlySet())
     136             :             {
     137          92 :                 arg->SetSkipIfAlreadySet(true);
     138          92 :                 arg->SetFrom(*stepArg);
     139             :             }
     140             :         }
     141             : 
     142          54 :         bool ret = false;
     143          54 :         if (readAlg.Run())
     144             :         {
     145          54 :             m_inputDataset.Set(readAlg.m_outputDataset.GetDatasetRef());
     146          54 :             m_outputDataset.Set(nullptr);
     147          54 :             if (RunStep(nullptr, nullptr))
     148             :             {
     149          41 :                 if (m_format == "stream")
     150             :                 {
     151           3 :                     ret = true;
     152             :                 }
     153             :                 else
     154             :                 {
     155          38 :                     writeAlg.m_inputDataset.Set(
     156             :                         m_outputDataset.GetDatasetRef());
     157          38 :                     if (writeAlg.Run(pfnProgress, pProgressData))
     158             :                     {
     159          37 :                         m_outputDataset.Set(
     160             :                             writeAlg.m_outputDataset.GetDatasetRef());
     161          37 :                         ret = true;
     162             :                     }
     163             :                 }
     164             :             }
     165             :         }
     166             : 
     167          54 :         return ret;
     168             :     }
     169             :     else
     170             :     {
     171         183 :         return RunStep(pfnProgress, pProgressData);
     172             :     }
     173             : }
     174             : 
     175             : /************************************************************************/
     176             : /*        GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm()    */
     177             : /************************************************************************/
     178             : 
     179          59 : GDALVectorPipelineAlgorithm::GDALVectorPipelineAlgorithm()
     180             :     : GDALAbstractPipelineAlgorithm<GDALVectorPipelineStepAlgorithm>(
     181             :           NAME, DESCRIPTION, HELP_URL,
     182          59 :           /*standaloneStep=*/false)
     183             : {
     184          59 :     AddInputArgs(/* hiddenForCLI = */ true);
     185          59 :     AddProgressArg();
     186         118 :     AddArg("pipeline", 0, _("Pipeline string"), &m_pipeline)
     187          59 :         .SetHiddenForCLI()
     188          59 :         .SetPositional();
     189          59 :     AddOutputArgs(/* hiddenForCLI = */ true,
     190             :                   /* shortNameOutputLayerAllowed=*/false);
     191             : 
     192          59 :     m_stepRegistry.Register<GDALVectorReadAlgorithm>();
     193          59 :     m_stepRegistry.Register<GDALVectorWriteAlgorithm>();
     194          59 :     m_stepRegistry.Register<GDALVectorClipAlgorithm>();
     195          59 :     m_stepRegistry.Register<GDALVectorReprojectAlgorithm>();
     196          59 :     m_stepRegistry.Register<GDALVectorFilterAlgorithm>();
     197          59 :     m_stepRegistry.Register<GDALVectorSelectAlgorithm>();
     198          59 :     m_stepRegistry.Register<GDALVectorSQLAlgorithm>();
     199          59 : }
     200             : 
     201             : /************************************************************************/
     202             : /*       GDALVectorPipelineAlgorithm::ParseCommandLineArguments()       */
     203             : /************************************************************************/
     204             : 
     205          46 : bool GDALVectorPipelineAlgorithm::ParseCommandLineArguments(
     206             :     const std::vector<std::string> &args)
     207             : {
     208          52 :     if (args.size() == 1 && (args[0] == "-h" || args[0] == "--help" ||
     209           6 :                              args[0] == "help" || args[0] == "--json-usage"))
     210           1 :         return GDALAlgorithm::ParseCommandLineArguments(args);
     211             : 
     212         314 :     for (const auto &arg : args)
     213             :     {
     214         271 :         if (arg.find("--pipeline") == 0)
     215           2 :             return GDALAlgorithm::ParseCommandLineArguments(args);
     216             : 
     217             :         // gdal vector pipeline [--progress] "read poly.gpkg ..."
     218         270 :         if (arg.find("read ") == 0)
     219           1 :             return GDALAlgorithm::ParseCommandLineArguments(args);
     220             :     }
     221             : 
     222          43 :     if (!m_steps.empty())
     223             :     {
     224           1 :         ReportError(CE_Failure, CPLE_AppDefined,
     225             :                     "ParseCommandLineArguments() can only be called once per "
     226             :                     "instance.");
     227           1 :         return false;
     228             :     }
     229             : 
     230             :     struct Step
     231             :     {
     232             :         std::unique_ptr<GDALVectorPipelineStepAlgorithm> alg{};
     233             :         std::vector<std::string> args{};
     234             :     };
     235             : 
     236          84 :     std::vector<Step> steps;
     237          42 :     steps.resize(1);
     238             : 
     239         302 :     for (const auto &arg : args)
     240             :     {
     241         261 :         if (arg == "--progress")
     242             :         {
     243           1 :             m_progressBarRequested = true;
     244           1 :             continue;
     245             :         }
     246             : 
     247         260 :         auto &curStep = steps.back();
     248             : 
     249         260 :         if (arg == "!" || arg == "|")
     250             :         {
     251          55 :             if (curStep.alg)
     252             :             {
     253          53 :                 steps.resize(steps.size() + 1);
     254             :             }
     255             :         }
     256             : #ifdef GDAL_PIPELINE_PROJ_NOSTALGIA
     257         205 :         else if (arg == "+step")
     258             :         {
     259           2 :             if (curStep.alg)
     260             :             {
     261           1 :                 steps.resize(steps.size() + 1);
     262             :             }
     263             :         }
     264         203 :         else if (arg.find("+gdal=") == 0)
     265             :         {
     266           1 :             const std::string stepName = arg.substr(strlen("+gdal="));
     267           1 :             curStep.alg = GetStepAlg(stepName);
     268           1 :             if (!curStep.alg)
     269             :             {
     270           0 :                 ReportError(CE_Failure, CPLE_AppDefined,
     271             :                             "unknown step name: %s", stepName.c_str());
     272           0 :                 return false;
     273             :             }
     274             :         }
     275             : #endif
     276         202 :         else if (!curStep.alg)
     277             :         {
     278          93 :             std::string algName = arg;
     279             : #ifdef GDAL_PIPELINE_PROJ_NOSTALGIA
     280          93 :             if (!algName.empty() && algName[0] == '+')
     281           1 :                 algName = algName.substr(1);
     282             : #endif
     283          93 :             curStep.alg = GetStepAlg(algName);
     284          93 :             if (!curStep.alg)
     285             :             {
     286           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
     287             :                             "unknown step name: %s", algName.c_str());
     288           1 :                 return false;
     289             :             }
     290             :         }
     291             :         else
     292             :         {
     293             : #ifdef GDAL_PIPELINE_PROJ_NOSTALGIA
     294         109 :             if (!arg.empty() && arg[0] == '+')
     295             :             {
     296           2 :                 curStep.args.push_back("--" + arg.substr(1));
     297           2 :                 continue;
     298             :             }
     299             : #endif
     300         214 :             std::string value = arg;
     301             : 
     302             : // #define GDAL_PIPELINE_NATURAL_LANGUAGE
     303             : #ifdef GDAL_PIPELINE_NATURAL_LANGUAGE
     304             :             // gdal vector pipeline "read [from] poly.gpkg, reproject [from EPSG:4326] to EPSG:32632 and write to out.gpkg with overwriting"
     305             :             if (value == "and")
     306             :             {
     307             :                 steps.resize(steps.size() + 1);
     308             :             }
     309             :             else if (value == "from" && curStep.alg->GetName() == "read")
     310             :             {
     311             :                 // do nothing
     312             :             }
     313             :             else if (value == "from" && curStep.alg->GetName() == "reproject")
     314             :             {
     315             :                 curStep.args.push_back("--src-crs");
     316             :             }
     317             :             else if (value == "to" && curStep.alg->GetName() == "reproject")
     318             :             {
     319             :                 curStep.args.push_back("--dst-crs");
     320             :             }
     321             :             else if (value == "to" && curStep.alg->GetName() == "write")
     322             :             {
     323             :                 // do nothing
     324             :             }
     325             :             else if (value == "with" && curStep.alg->GetName() == "write")
     326             :             {
     327             :                 // do nothing
     328             :             }
     329             :             else if (value == "overwriting" &&
     330             :                      curStep.alg->GetName() == "write")
     331             :             {
     332             :                 curStep.args.push_back("--overwrite");
     333             :             }
     334             :             else if (!value.empty() && value.back() == ',')
     335             :             {
     336             :                 curStep.args.push_back(value.substr(0, value.size() - 1));
     337             :                 steps.resize(steps.size() + 1);
     338             :             }
     339             :             else
     340             : #endif
     341             : 
     342             :             {
     343         107 :                 curStep.args.push_back(value);
     344             :             }
     345             :         }
     346             :     }
     347             : 
     348             :     // As we initially added a step without alg to bootstrap things, make
     349             :     // sure to remove it if it hasn't been filled, or the user has terminated
     350             :     // the pipeline with a '!' separator.
     351          41 :     if (!steps.back().alg)
     352           2 :         steps.pop_back();
     353             : 
     354          41 :     if (steps.size() < 2)
     355             :     {
     356           2 :         ReportError(CE_Failure, CPLE_AppDefined,
     357             :                     "At least 2 steps must be provided");
     358           2 :         return false;
     359             :     }
     360             : 
     361          39 :     if (steps.front().alg->GetName() != GDALVectorReadAlgorithm::NAME)
     362             :     {
     363           1 :         ReportError(CE_Failure, CPLE_AppDefined, "First step should be '%s'",
     364             :                     GDALVectorReadAlgorithm::NAME);
     365           1 :         return false;
     366             :     }
     367          50 :     for (size_t i = 1; i < steps.size() - 1; ++i)
     368             :     {
     369          13 :         if (steps[i].alg->GetName() == GDALVectorReadAlgorithm::NAME)
     370             :         {
     371           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     372             :                         "Only first step can be '%s'",
     373             :                         GDALVectorReadAlgorithm::NAME);
     374           1 :             return false;
     375             :         }
     376             :     }
     377          37 :     if (steps.back().alg->GetName() != GDALVectorWriteAlgorithm::NAME)
     378             :     {
     379           1 :         ReportError(CE_Failure, CPLE_AppDefined, "Last step should be '%s'",
     380             :                     GDALVectorWriteAlgorithm::NAME);
     381           1 :         return false;
     382             :     }
     383          83 :     for (size_t i = 0; i < steps.size() - 1; ++i)
     384             :     {
     385          48 :         if (steps[i].alg->GetName() == GDALVectorWriteAlgorithm::NAME)
     386             :         {
     387           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     388             :                         "Only last step can be '%s'",
     389             :                         GDALVectorWriteAlgorithm::NAME);
     390           1 :             return false;
     391             :         }
     392             :     }
     393             : 
     394          35 :     if (!m_pipeline.empty())
     395             :     {
     396             :         // Propagate input parameters set at the pipeline level to the
     397             :         // "read" step
     398             :         {
     399           7 :             auto &step = steps.front();
     400          70 :             for (auto &arg : step.alg->GetArgs())
     401             :             {
     402          63 :                 auto pipelineArg = GetArg(arg->GetName());
     403          63 :                 if (pipelineArg && pipelineArg->IsExplicitlySet())
     404             :                 {
     405           3 :                     arg->SetSkipIfAlreadySet(true);
     406           3 :                     arg->SetFrom(*pipelineArg);
     407             :                 }
     408             :             }
     409             :         }
     410             : 
     411             :         // Same with "write" step
     412             :         {
     413           7 :             auto &step = steps.back();
     414         105 :             for (auto &arg : step.alg->GetArgs())
     415             :             {
     416          98 :                 auto pipelineArg = GetArg(arg->GetName());
     417          98 :                 if (pipelineArg && pipelineArg->IsExplicitlySet())
     418             :                 {
     419           1 :                     arg->SetSkipIfAlreadySet(true);
     420           1 :                     arg->SetFrom(*pipelineArg);
     421             :                 }
     422             :             }
     423             :         }
     424             :     }
     425             : 
     426             :     // Parse each step, but without running the validation
     427         105 :     for (const auto &step : steps)
     428             :     {
     429          76 :         step.alg->m_skipValidationInParseCommandLine = true;
     430          76 :         if (!step.alg->ParseCommandLineArguments(step.args))
     431           6 :             return false;
     432             :     }
     433             : 
     434             :     // Evaluate "input" argument of "read" step, together with the "output"
     435             :     // argument of the "write" step, in case they point to the same dataset.
     436          29 :     auto inputArg = steps.front().alg->GetArg(GDAL_ARG_NAME_INPUT);
     437          58 :     if (inputArg && inputArg->IsExplicitlySet() &&
     438          29 :         inputArg->GetType() == GAAT_DATASET)
     439             :     {
     440          29 :         steps.front().alg->ProcessDatasetArg(inputArg, steps.back().alg.get());
     441             :     }
     442             : 
     443          92 :     for (const auto &step : steps)
     444             :     {
     445          64 :         if (!step.alg->ValidateArguments())
     446           1 :             return false;
     447             :     }
     448             : 
     449          90 :     for (auto &step : steps)
     450          62 :         m_steps.push_back(std::move(step.alg));
     451             : 
     452          28 :     return true;
     453             : }
     454             : 
     455             : /************************************************************************/
     456             : /*            GDALVectorPipelineAlgorithm::GetUsageForCLI()             */
     457             : /************************************************************************/
     458             : 
     459           2 : std::string GDALVectorPipelineAlgorithm::GetUsageForCLI(
     460             :     bool shortUsage, const UsageOptions &usageOptions) const
     461             : {
     462           2 :     std::string ret = GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptions);
     463           2 :     if (shortUsage)
     464           1 :         return ret;
     465             : 
     466             :     ret += "\n<PIPELINE> is of the form: read [READ-OPTIONS] "
     467           1 :            "( ! <STEP-NAME> [STEP-OPTIONS] )* ! write [WRITE-OPTIONS]\n";
     468           1 :     ret += '\n';
     469           1 :     ret += "Example: 'gdal vector pipeline --progress ! read in.gpkg ! \\\n";
     470           1 :     ret += "               reproject --dst-crs=EPSG:32632 ! ";
     471           1 :     ret += "write out.gpkg --overwrite'\n";
     472           1 :     ret += '\n';
     473           1 :     ret += "Potential steps are:\n";
     474             : 
     475           1 :     UsageOptions stepUsageOptions;
     476           1 :     stepUsageOptions.isPipelineStep = true;
     477             : 
     478           8 :     for (const std::string &name : m_stepRegistry.GetNames())
     479             :     {
     480          14 :         auto alg = GetStepAlg(name);
     481           7 :         assert(alg);
     482           7 :         auto [options, maxOptLen] = alg->GetArgNamesForCLI();
     483           7 :         stepUsageOptions.maxOptLen =
     484           7 :             std::max(stepUsageOptions.maxOptLen, maxOptLen);
     485             :     }
     486             : 
     487             :     {
     488           1 :         const auto name = GDALVectorReadAlgorithm::NAME;
     489           1 :         ret += '\n';
     490           2 :         auto alg = GetStepAlg(name);
     491           1 :         assert(alg);
     492           2 :         alg->SetCallPath({name});
     493           1 :         ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
     494             :     }
     495           8 :     for (const std::string &name : m_stepRegistry.GetNames())
     496             :     {
     497          13 :         if (name != GDALVectorReadAlgorithm::NAME &&
     498           6 :             name != GDALVectorWriteAlgorithm::NAME)
     499             :         {
     500           5 :             ret += '\n';
     501           5 :             auto alg = GetStepAlg(name);
     502           5 :             assert(alg);
     503          10 :             alg->SetCallPath({name});
     504           5 :             ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
     505             :         }
     506             :     }
     507             :     {
     508           1 :         const auto name = GDALVectorWriteAlgorithm::NAME;
     509           1 :         ret += '\n';
     510           2 :         auto alg = GetStepAlg(name);
     511           1 :         assert(alg);
     512           2 :         alg->SetCallPath({name});
     513           1 :         ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
     514             :     }
     515             : 
     516           1 :     return ret;
     517             : }
     518             : 
     519             : /************************************************************************/
     520             : /*                  GDALVectorPipelineOutputLayer                       */
     521             : /************************************************************************/
     522             : 
     523             : /************************************************************************/
     524             : /*                  GDALVectorPipelineOutputLayer()                     */
     525             : /************************************************************************/
     526             : 
     527          28 : GDALVectorPipelineOutputLayer::GDALVectorPipelineOutputLayer(OGRLayer &srcLayer)
     528          28 :     : m_srcLayer(srcLayer)
     529             : {
     530          28 : }
     531             : 
     532             : /************************************************************************/
     533             : /*             GDALVectorPipelineOutputLayer::ResetReading()            */
     534             : /************************************************************************/
     535             : 
     536          22 : void GDALVectorPipelineOutputLayer::ResetReading()
     537             : {
     538          22 :     m_srcLayer.ResetReading();
     539          22 :     m_pendingFeatures.clear();
     540          22 :     m_idxInPendingFeatures = 0;
     541          22 : }
     542             : 
     543             : /************************************************************************/
     544             : /*           GDALVectorPipelineOutputLayer::GetNextRawFeature()         */
     545             : /************************************************************************/
     546             : 
     547          90 : OGRFeature *GDALVectorPipelineOutputLayer::GetNextRawFeature()
     548             : {
     549          90 :     if (m_idxInPendingFeatures < m_pendingFeatures.size())
     550             :     {
     551             :         OGRFeature *poFeature =
     552           1 :             m_pendingFeatures[m_idxInPendingFeatures].release();
     553           1 :         ++m_idxInPendingFeatures;
     554           1 :         return poFeature;
     555             :     }
     556          89 :     m_pendingFeatures.clear();
     557          89 :     m_idxInPendingFeatures = 0;
     558             :     while (true)
     559             :     {
     560             :         auto poSrcFeature =
     561          90 :             std::unique_ptr<OGRFeature>(m_srcLayer.GetNextFeature());
     562          90 :         if (!poSrcFeature)
     563          22 :             return nullptr;
     564          68 :         TranslateFeature(std::move(poSrcFeature), m_pendingFeatures);
     565          68 :         if (!m_pendingFeatures.empty())
     566          67 :             break;
     567           1 :     }
     568          67 :     OGRFeature *poFeature = m_pendingFeatures[0].release();
     569          67 :     m_idxInPendingFeatures = 1;
     570          67 :     return poFeature;
     571             : }
     572             : 
     573             : /************************************************************************/
     574             : /*                 GDALVectorPipelineOutputDataset                      */
     575             : /************************************************************************/
     576             : 
     577             : /************************************************************************/
     578             : /*                 GDALVectorPipelineOutputDataset()                    */
     579             : /************************************************************************/
     580             : 
     581          36 : GDALVectorPipelineOutputDataset::GDALVectorPipelineOutputDataset(
     582          36 :     GDALDataset &srcDS)
     583          36 :     : m_srcDS(srcDS)
     584             : {
     585          36 :     SetDescription(m_srcDS.GetDescription());
     586          36 : }
     587             : 
     588             : /************************************************************************/
     589             : /*            GDALVectorPipelineOutputDataset::AddLayer()               */
     590             : /************************************************************************/
     591             : 
     592          42 : void GDALVectorPipelineOutputDataset::AddLayer(
     593             :     OGRLayer &oSrcLayer,
     594             :     std::unique_ptr<OGRLayerWithTranslateFeature> poNewLayer)
     595             : {
     596          42 :     m_layersToDestroy.push_back(std::move(poNewLayer));
     597             :     OGRLayerWithTranslateFeature *poNewLayerRaw =
     598          42 :         m_layersToDestroy.back().get();
     599          42 :     m_layers.push_back(poNewLayerRaw);
     600          42 :     m_mapSrcLayerToNewLayer[&oSrcLayer] = poNewLayerRaw;
     601          42 : }
     602             : 
     603             : /************************************************************************/
     604             : /*          GDALVectorPipelineOutputDataset::GetLayerCount()            */
     605             : /************************************************************************/
     606             : 
     607          68 : int GDALVectorPipelineOutputDataset::GetLayerCount()
     608             : {
     609          68 :     return static_cast<int>(m_layers.size());
     610             : }
     611             : 
     612             : /************************************************************************/
     613             : /*             GDALVectorPipelineOutputDataset::GetLayer()              */
     614             : /************************************************************************/
     615             : 
     616          31 : OGRLayer *GDALVectorPipelineOutputDataset::GetLayer(int idx)
     617             : {
     618          31 :     return idx >= 0 && idx < GetLayerCount() ? m_layers[idx] : nullptr;
     619             : }
     620             : 
     621             : /************************************************************************/
     622             : /*           GDALVectorPipelineOutputDataset::TestCapability()          */
     623             : /************************************************************************/
     624             : 
     625          32 : int GDALVectorPipelineOutputDataset::TestCapability(const char *pszCap)
     626             : {
     627          32 :     if (EQUAL(pszCap, ODsCRandomLayerRead))
     628             :     {
     629          32 :         return m_srcDS.TestCapability(pszCap);
     630             :     }
     631           0 :     return false;
     632             : }
     633             : 
     634             : /************************************************************************/
     635             : /*             GDALVectorPipelineOutputDataset::ResetReading()          */
     636             : /************************************************************************/
     637             : 
     638           2 : void GDALVectorPipelineOutputDataset::ResetReading()
     639             : {
     640           2 :     m_srcDS.ResetReading();
     641           2 :     m_pendingFeatures.clear();
     642           2 :     m_idxInPendingFeatures = 0;
     643           2 : }
     644             : 
     645             : /************************************************************************/
     646             : /*            GDALVectorPipelineOutputDataset::GetNextFeature()         */
     647             : /************************************************************************/
     648             : 
     649          18 : OGRFeature *GDALVectorPipelineOutputDataset::GetNextFeature(
     650             :     OGRLayer **ppoBelongingLayer, double *pdfProgressPct,
     651             :     GDALProgressFunc pfnProgress, void *pProgressData)
     652             : {
     653          18 :     if (m_idxInPendingFeatures < m_pendingFeatures.size())
     654             :     {
     655             :         OGRFeature *poFeature =
     656           0 :             m_pendingFeatures[m_idxInPendingFeatures].release();
     657           0 :         if (ppoBelongingLayer)
     658           0 :             *ppoBelongingLayer = m_belongingLayer;
     659           0 :         ++m_idxInPendingFeatures;
     660           0 :         return poFeature;
     661             :     }
     662             : 
     663          18 :     m_pendingFeatures.clear();
     664          18 :     m_idxInPendingFeatures = 0;
     665             : 
     666             :     while (true)
     667             :     {
     668          18 :         OGRLayer *poSrcBelongingLayer = nullptr;
     669          18 :         auto poSrcFeature = std::unique_ptr<OGRFeature>(m_srcDS.GetNextFeature(
     670          18 :             &poSrcBelongingLayer, pdfProgressPct, pfnProgress, pProgressData));
     671          18 :         if (!poSrcFeature)
     672           2 :             return nullptr;
     673          16 :         auto iterToDstLayer = m_mapSrcLayerToNewLayer.find(poSrcBelongingLayer);
     674          16 :         if (iterToDstLayer != m_mapSrcLayerToNewLayer.end())
     675             :         {
     676          16 :             m_belongingLayer = iterToDstLayer->second;
     677          16 :             m_belongingLayer->TranslateFeature(std::move(poSrcFeature),
     678          16 :                                                m_pendingFeatures);
     679          16 :             if (!m_pendingFeatures.empty())
     680          16 :                 break;
     681             :         }
     682           0 :     }
     683          16 :     OGRFeature *poFeature = m_pendingFeatures[0].release();
     684          16 :     if (ppoBelongingLayer)
     685          16 :         *ppoBelongingLayer = m_belongingLayer;
     686          16 :     m_idxInPendingFeatures = 1;
     687          16 :     return poFeature;
     688             : }
     689             : 
     690             : //! @endcond

Generated by: LCOV version 1.14