LCOV - code coverage report
Current view: top level - apps - gdalalg_tee.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 81 82 98.8 %
Date: 2025-11-11 01:53:33 Functions: 24 27 88.9 %

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

Generated by: LCOV version 1.14