LCOV - code coverage report
Current view: top level - apps - gdalalg_tee.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 84 85 98.8 %
Date: 2025-09-10 17:48:50 Functions: 25 27 92.6 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "tee" pipeline step
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #ifndef GDALALG_TEE_INCLUDED
      14             : #define GDALALG_TEE_INCLUDED
      15             : 
      16             : #include "gdalalg_abstract_pipeline.h"
      17             : #include "gdalalg_raster_pipeline.h"
      18             : #include "gdalalg_vector_pipeline.h"
      19             : #include "ogrsf_frmts.h"
      20             : 
      21             : #include <utility>
      22             : 
      23             : //! @cond Doxygen_Suppress
      24             : 
      25             : #ifndef _
      26             : #define _(x) (x)
      27             : #endif
      28             : 
      29             : /************************************************************************/
      30             : /*                        GDALTeeStepAlgorithmAbstract                  */
      31             : /************************************************************************/
      32             : 
      33         115 : class GDALTeeStepAlgorithmAbstract /* non final */
      34             : {
      35             :   public:
      36             :     static constexpr const char *NAME = "tee";
      37             :     static constexpr const char *DESCRIPTION =
      38             :         "Pipes the input into the output stream and side nested pipelines.";
      39             :     static constexpr const char *HELP_URL = "/programs/gdal_pipeline.html";
      40             : 
      41             :     virtual ~GDALTeeStepAlgorithmAbstract();
      42             : 
      43          14 :     void CopyFilenameBindingsFrom(const GDALTeeStepAlgorithmAbstract *other)
      44             :     {
      45          14 :         m_oMapNameToAlg = other->m_oMapNameToAlg;
      46          14 :     }
      47             : 
      48          17 :     bool BindFilename(const std::string &filename,
      49             :                       GDALPipelineStepAlgorithm *alg,
      50             :                       const std::vector<std::string> &args)
      51             :     {
      52          17 :         if (cpl::contains(m_oMapNameToAlg, filename))
      53           1 :             return false;
      54          16 :         m_oMapNameToAlg[filename] = std::make_pair(alg, args);
      55          16 :         return true;
      56             :     }
      57             : 
      58             :   protected:
      59         115 :     GDALTeeStepAlgorithmAbstract() = default;
      60             : 
      61             :     std::vector<GDALArgDatasetValue> m_pipelines{};
      62             :     std::map<std::string,
      63             :              std::pair<GDALPipelineStepAlgorithm *, std::vector<std::string>>>
      64             :         m_oMapNameToAlg{};
      65             : };
      66             : 
      67             : /************************************************************************/
      68             : /*                        GDALTeeStepAlgorithmBase                      */
      69             : /************************************************************************/
      70             : 
      71             : template <class BaseStepAlgorithm, int nDatasetType>
      72             : class GDALTeeStepAlgorithmBase /* non final */
      73             :     : public BaseStepAlgorithm,
      74             :       public GDALTeeStepAlgorithmAbstract
      75             : {
      76             :   public:
      77          25 :     bool IsNativelyStreamingCompatible() const override
      78             :     {
      79          25 :         return false;
      80             :     }
      81             : 
      82          28 :     bool CanBeMiddleStep() const override
      83             :     {
      84          28 :         return true;
      85             :     }
      86             : 
      87          49 :     bool CanBeLastStep() const override
      88             :     {
      89          49 :         return true;
      90             :     }
      91             : 
      92           1 :     bool GeneratesFilesFromUserInput() const override
      93             :     {
      94           1 :         return true;
      95             :     }
      96             : 
      97             :   protected:
      98             :     explicit GDALTeeStepAlgorithmBase();
      99             : 
     100           4 :     int GetInputType() const override
     101             :     {
     102           4 :         return nDatasetType;
     103             :     }
     104             : 
     105          14 :     int GetOutputType() const override
     106             :     {
     107          14 :         return nDatasetType;
     108             :     }
     109             : 
     110             :   private:
     111             :     bool RunStep(GDALPipelineStepRunContext &ctxt) override;
     112             : };
     113             : 
     114             : /************************************************************************/
     115             : /*             GDALTeeStepAlgorithmBase::GDALTeeStepAlgorithmBase()     */
     116             : /************************************************************************/
     117             : 
     118             : template <class BaseStepAlgorithm, int nDatasetType>
     119         115 : GDALTeeStepAlgorithmBase<BaseStepAlgorithm,
     120             :                          nDatasetType>::GDALTeeStepAlgorithmBase()
     121             :     : BaseStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
     122             :                         GDALPipelineStepAlgorithm::ConstructorOptions()
     123         115 :                             .SetAddDefaultArguments(false))
     124             : {
     125         115 :     this->AddArg("tee-pipeline", 0, _("Nested pipeline"), &m_pipelines,
     126             :                  nDatasetType)
     127         230 :         .SetPositional()
     128         115 :         .SetMinCount(1)
     129         115 :         .SetMaxCount(INT_MAX)
     130         115 :         .SetMetaVar("PIPELINE")
     131         230 :         .SetPackedValuesAllowed(false)
     132         115 :         .SetDatasetInputFlags(GADV_NAME)
     133         115 :         .SetDatasetOutputFlags(GADV_NAME)
     134         115 :         .SetAutoOpenDataset(false);
     135         115 : }
     136             : 
     137             : /************************************************************************/
     138             : /*                  GDALTeeStepAlgorithmBase::RunStep()                 */
     139             : /************************************************************************/
     140             : 
     141             : template <class BaseStepAlgorithm, int nDatasetType>
     142          12 : bool GDALTeeStepAlgorithmBase<BaseStepAlgorithm, nDatasetType>::RunStep(
     143             :     GDALPipelineStepRunContext &ctxt)
     144             : {
     145          12 :     auto pfnProgress = ctxt.m_pfnProgress;
     146          12 :     auto pProgressData = ctxt.m_pProgressData;
     147             : 
     148          12 :     auto poSrcDS = this->m_inputDataset[0].GetDatasetRef();
     149          12 :     CPLAssert(poSrcDS);
     150          12 :     CPLAssert(this->m_outputDataset.GetName().empty());
     151          12 :     CPLAssert(!this->m_outputDataset.GetDatasetRef());
     152             : 
     153             :     // Backup filters
     154          24 :     std::vector<std::string> aosAttributeFilters;
     155          24 :     std::vector<std::unique_ptr<OGRGeometry>> apoSpatialFilters;
     156          16 :     for (auto *poLayer : poSrcDS->GetLayers())
     157             :     {
     158           4 :         const char *pszQueryString = poLayer->GetAttrQueryString();
     159           4 :         aosAttributeFilters.push_back(pszQueryString ? pszQueryString : "");
     160           4 :         const auto poSpatFilter = poLayer->GetSpatialFilter();
     161           4 :         apoSpatialFilters.push_back(std::unique_ptr<OGRGeometry>(
     162           0 :             poSpatFilter ? poSpatFilter->clone() : nullptr));
     163             :     }
     164             : 
     165          12 :     int iTeeDS = 0;
     166          20 :     for (const auto &dataset : m_pipelines)
     167             :     {
     168          14 :         const auto oIter = m_oMapNameToAlg.find(dataset.GetName());
     169          14 :         if (oIter == m_oMapNameToAlg.end())
     170             :         {
     171           1 :             this->ReportError(CE_Failure, CPLE_AppDefined,
     172             :                               "'%s' is not a valid nested pipeline",
     173           1 :                               dataset.GetName().c_str());
     174           6 :             return false;
     175             :         }
     176          13 :         auto subAlg = oIter->second.first;
     177          13 :         const auto &subAlgArgs = oIter->second.second;
     178             : 
     179          13 :         auto &subAlgInputDatasets = subAlg->GetInputDatasets();
     180          13 :         CPLAssert(subAlgInputDatasets.empty());
     181          13 :         subAlgInputDatasets.resize(1);
     182          13 :         subAlgInputDatasets[0].Set(poSrcDS);
     183             : 
     184             :         std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
     185          13 :             pScaledProgress(
     186             :                 GDALCreateScaledProgress(
     187          13 :                     double(iTeeDS) / static_cast<int>(m_pipelines.size()),
     188          13 :                     double(iTeeDS + 1) / static_cast<int>(m_pipelines.size()),
     189             :                     pfnProgress, pProgressData),
     190          13 :                 GDALDestroyScaledProgress);
     191             : 
     192          13 :         bool ret = (subAlg->ParseCommandLineArguments(subAlgArgs) &&
     193           8 :                     subAlg->Run(pScaledProgress ? GDALScaledProgress : nullptr,
     194          21 :                                 pScaledProgress.get()) &&
     195           8 :                     subAlg->Finalize());
     196             : 
     197             :         // Restore filters
     198          18 :         for (int i = 0; i < static_cast<int>(aosAttributeFilters.size()); ++i)
     199             :         {
     200           5 :             auto poLayer = poSrcDS->GetLayer(i);
     201          10 :             poLayer->SetAttributeFilter(aosAttributeFilters[i].empty()
     202           5 :                                             ? aosAttributeFilters[i].c_str()
     203             :                                             : nullptr);
     204           5 :             poLayer->SetSpatialFilter(apoSpatialFilters[i].get());
     205           5 :             poLayer->ResetReading();
     206             :         }
     207             : 
     208          13 :         if (!ret)
     209           5 :             return false;
     210             : 
     211           8 :         ++iTeeDS;
     212             :     }
     213             : 
     214           6 :     this->m_outputDataset.Set(poSrcDS);
     215           6 :     return true;
     216             : }
     217             : 
     218             : /************************************************************************/
     219             : /*                         GDALTeeRasterAlgorithm                       */
     220             : /************************************************************************/
     221             : 
     222         132 : class GDALTeeRasterAlgorithm final
     223             :     : public GDALTeeStepAlgorithmBase<GDALRasterPipelineStepAlgorithm,
     224             :                                       GDAL_OF_RASTER>
     225             : {
     226             :   public:
     227          66 :     GDALTeeRasterAlgorithm() = default;
     228             : 
     229             :     ~GDALTeeRasterAlgorithm() override;
     230             : };
     231             : 
     232             : /************************************************************************/
     233             : /*                         GDALTeeVectorAlgorithm                       */
     234             : /************************************************************************/
     235             : 
     236          98 : class GDALTeeVectorAlgorithm final
     237             :     : public GDALTeeStepAlgorithmBase<GDALVectorPipelineStepAlgorithm,
     238             :                                       GDAL_OF_VECTOR>
     239             : {
     240             :   public:
     241          49 :     GDALTeeVectorAlgorithm() = default;
     242             : 
     243             :     ~GDALTeeVectorAlgorithm() override;
     244             : };
     245             : 
     246             : //! @endcond
     247             : 
     248             : #endif

Generated by: LCOV version 1.14