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