Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: GDALAlgorithm class
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 GDAL_ALGORITHM_INCLUDED
14 : #define GDAL_ALGORITHM_INCLUDED
15 :
16 : #include "cpl_port.h"
17 : #include "cpl_progress.h"
18 :
19 : #include "gdal.h"
20 :
21 : /************************************************************************/
22 : /************************************************************************/
23 : /* GDAL Algorithm C API */
24 : /************************************************************************/
25 : /************************************************************************/
26 :
27 : CPL_C_START
28 :
29 : /** Type of an argument */
30 : typedef enum GDALAlgorithmArgType
31 : {
32 : /** Boolean type. Value is a bool. */
33 : GAAT_BOOLEAN,
34 : /** Single-value string type. Value is a std::string */
35 : GAAT_STRING,
36 : /** Single-value integer type. Value is a int */
37 : GAAT_INTEGER,
38 : /** Single-value real type. Value is a double */
39 : GAAT_REAL,
40 : /** Dataset type. Value is a GDALArgDatasetValue */
41 : GAAT_DATASET,
42 : /** Multi-value string type. Value is a std::vector<std::string> */
43 : GAAT_STRING_LIST,
44 : /** Multi-value integer type. Value is a std::vector<int> */
45 : GAAT_INTEGER_LIST,
46 : /** Multi-value real type. Value is a std::vector<double> */
47 : GAAT_REAL_LIST,
48 : /** Multi-value dataset type. Value is a std::vector<GDALArgDatasetValue> */
49 : GAAT_DATASET_LIST,
50 : } GDALAlgorithmArgType;
51 :
52 : /** Return whether the argument type is a list / multi-valued one. */
53 : bool CPL_DLL GDALAlgorithmArgTypeIsList(GDALAlgorithmArgType type);
54 :
55 : /** Return the string representation of the argument type */
56 : const char CPL_DLL *GDALAlgorithmArgTypeName(GDALAlgorithmArgType type);
57 :
58 : /** Opaque C type for GDALArgDatasetValue */
59 : typedef struct GDALArgDatasetValueHS *GDALArgDatasetValueH;
60 :
61 : /** Opaque C type for GDALAlgorithmArg */
62 : typedef struct GDALAlgorithmArgHS *GDALAlgorithmArgH;
63 :
64 : /** Opaque C type for GDALAlgorithm */
65 : typedef struct GDALAlgorithmHS *GDALAlgorithmH;
66 :
67 : /** Opaque C type for GDALAlgorithmRegistry */
68 : typedef struct GDALAlgorithmRegistryHS *GDALAlgorithmRegistryH;
69 :
70 : /************************************************************************/
71 : /* GDALAlgorithmRegistryH API */
72 : /************************************************************************/
73 :
74 : GDALAlgorithmRegistryH CPL_DLL GDALGetGlobalAlgorithmRegistry(void);
75 :
76 : void CPL_DLL GDALAlgorithmRegistryRelease(GDALAlgorithmRegistryH);
77 :
78 : char CPL_DLL **GDALAlgorithmRegistryGetAlgNames(GDALAlgorithmRegistryH);
79 :
80 : GDALAlgorithmH CPL_DLL GDALAlgorithmRegistryInstantiateAlg(
81 : GDALAlgorithmRegistryH, const char *pszAlgName);
82 :
83 : /************************************************************************/
84 : /* GDALAlgorithmH API */
85 : /************************************************************************/
86 :
87 : void CPL_DLL GDALAlgorithmRelease(GDALAlgorithmH);
88 :
89 : const char CPL_DLL *GDALAlgorithmGetName(GDALAlgorithmH);
90 :
91 : const char CPL_DLL *GDALAlgorithmGetDescription(GDALAlgorithmH);
92 :
93 : const char CPL_DLL *GDALAlgorithmGetLongDescription(GDALAlgorithmH);
94 :
95 : const char CPL_DLL *GDALAlgorithmGetHelpFullURL(GDALAlgorithmH);
96 :
97 : bool CPL_DLL GDALAlgorithmHasSubAlgorithms(GDALAlgorithmH);
98 :
99 : char CPL_DLL **GDALAlgorithmGetSubAlgorithmNames(GDALAlgorithmH);
100 :
101 : GDALAlgorithmH CPL_DLL
102 : GDALAlgorithmInstantiateSubAlgorithm(GDALAlgorithmH, const char *pszSubAlgName);
103 :
104 : bool CPL_DLL GDALAlgorithmParseCommandLineArguments(GDALAlgorithmH,
105 : CSLConstList papszArgs);
106 :
107 : GDALAlgorithmH CPL_DLL GDALAlgorithmGetActualAlgorithm(GDALAlgorithmH);
108 :
109 : bool CPL_DLL GDALAlgorithmRun(GDALAlgorithmH, GDALProgressFunc pfnProgress,
110 : void *pProgressData);
111 :
112 : bool CPL_DLL GDALAlgorithmFinalize(GDALAlgorithmH);
113 :
114 : char CPL_DLL *GDALAlgorithmGetUsageAsJSON(GDALAlgorithmH);
115 :
116 : char CPL_DLL **GDALAlgorithmGetArgNames(GDALAlgorithmH);
117 :
118 : GDALAlgorithmArgH CPL_DLL GDALAlgorithmGetArg(GDALAlgorithmH,
119 : const char *pszArgName);
120 :
121 : /************************************************************************/
122 : /* GDALAlgorithmArgH API */
123 : /************************************************************************/
124 :
125 : void CPL_DLL GDALAlgorithmArgRelease(GDALAlgorithmArgH);
126 :
127 : const char CPL_DLL *GDALAlgorithmArgGetName(GDALAlgorithmArgH);
128 :
129 : GDALAlgorithmArgType CPL_DLL GDALAlgorithmArgGetType(GDALAlgorithmArgH);
130 :
131 : const char CPL_DLL *GDALAlgorithmArgGetDescription(GDALAlgorithmArgH);
132 :
133 : const char CPL_DLL *GDALAlgorithmArgGetShortName(GDALAlgorithmArgH);
134 :
135 : char CPL_DLL **GDALAlgorithmArgGetAliases(GDALAlgorithmArgH);
136 :
137 : const char CPL_DLL *GDALAlgorithmArgGetMetaVar(GDALAlgorithmArgH);
138 :
139 : const char CPL_DLL *GDALAlgorithmArgGetCategory(GDALAlgorithmArgH);
140 :
141 : bool CPL_DLL GDALAlgorithmArgIsPositional(GDALAlgorithmArgH);
142 :
143 : bool CPL_DLL GDALAlgorithmArgIsRequired(GDALAlgorithmArgH);
144 :
145 : int CPL_DLL GDALAlgorithmArgGetMinCount(GDALAlgorithmArgH);
146 :
147 : int CPL_DLL GDALAlgorithmArgGetMaxCount(GDALAlgorithmArgH);
148 :
149 : bool CPL_DLL GDALAlgorithmArgGetPackedValuesAllowed(GDALAlgorithmArgH);
150 :
151 : bool CPL_DLL GDALAlgorithmArgGetRepeatedArgAllowed(GDALAlgorithmArgH);
152 :
153 : char CPL_DLL **GDALAlgorithmArgGetChoices(GDALAlgorithmArgH);
154 :
155 : bool CPL_DLL GDALAlgorithmArgIsExplicitlySet(GDALAlgorithmArgH);
156 :
157 : bool CPL_DLL GDALAlgorithmArgHasDefaultValue(GDALAlgorithmArgH);
158 :
159 : bool CPL_DLL GDALAlgorithmArgIsHiddenForCLI(GDALAlgorithmArgH);
160 :
161 : bool CPL_DLL GDALAlgorithmArgIsOnlyForCLI(GDALAlgorithmArgH);
162 :
163 : bool CPL_DLL GDALAlgorithmArgIsInput(GDALAlgorithmArgH);
164 :
165 : bool CPL_DLL GDALAlgorithmArgIsOutput(GDALAlgorithmArgH);
166 :
167 : const char CPL_DLL *GDALAlgorithmArgGetMutualExclusionGroup(GDALAlgorithmArgH);
168 :
169 : bool CPL_DLL GDALAlgorithmArgGetAsBoolean(GDALAlgorithmArgH);
170 :
171 : const char CPL_DLL *GDALAlgorithmArgGetAsString(GDALAlgorithmArgH);
172 :
173 : GDALArgDatasetValueH
174 : CPL_DLL GDALAlgorithmArgGetAsDatasetValue(GDALAlgorithmArgH);
175 :
176 : int CPL_DLL GDALAlgorithmArgGetAsInteger(GDALAlgorithmArgH);
177 :
178 : double CPL_DLL GDALAlgorithmArgGetAsDouble(GDALAlgorithmArgH);
179 :
180 : char CPL_DLL **GDALAlgorithmArgGetAsStringList(GDALAlgorithmArgH);
181 :
182 : const int CPL_DLL *GDALAlgorithmArgGetAsIntegerList(GDALAlgorithmArgH,
183 : size_t *pnCount);
184 :
185 : const double CPL_DLL *GDALAlgorithmArgGetAsDoubleList(GDALAlgorithmArgH,
186 : size_t *pnCount);
187 :
188 : bool CPL_DLL GDALAlgorithmArgSetAsBoolean(GDALAlgorithmArgH, bool);
189 :
190 : bool CPL_DLL GDALAlgorithmArgSetAsString(GDALAlgorithmArgH, const char *);
191 :
192 : bool CPL_DLL GDALAlgorithmArgSetAsDatasetValue(GDALAlgorithmArgH hArg,
193 : GDALArgDatasetValueH value);
194 :
195 : bool CPL_DLL GDALAlgorithmArgSetDataset(GDALAlgorithmArgH hArg, GDALDatasetH);
196 :
197 : bool CPL_DLL GDALAlgorithmArgSetDatasets(GDALAlgorithmArgH hArg, size_t nCount,
198 : GDALDatasetH *);
199 :
200 : bool CPL_DLL GDALAlgorithmArgSetDatasetNames(GDALAlgorithmArgH hArg,
201 : CSLConstList);
202 :
203 : bool CPL_DLL GDALAlgorithmArgSetAsInteger(GDALAlgorithmArgH, int);
204 :
205 : bool CPL_DLL GDALAlgorithmArgSetAsDouble(GDALAlgorithmArgH, double);
206 :
207 : bool CPL_DLL GDALAlgorithmArgSetAsStringList(GDALAlgorithmArgH, CSLConstList);
208 :
209 : bool CPL_DLL GDALAlgorithmArgSetAsIntegerList(GDALAlgorithmArgH, size_t nCount,
210 : const int *pnValues);
211 :
212 : bool CPL_DLL GDALAlgorithmArgSetAsDoubleList(GDALAlgorithmArgH, size_t nCount,
213 : const double *pnValues);
214 :
215 : /************************************************************************/
216 : /* GDALArgDatasetValueH API */
217 : /************************************************************************/
218 :
219 : GDALArgDatasetValueH CPL_DLL GDALArgDatasetValueCreate(void);
220 :
221 : void CPL_DLL GDALArgDatasetValueRelease(GDALArgDatasetValueH);
222 :
223 : const char CPL_DLL *GDALArgDatasetValueGetName(GDALArgDatasetValueH);
224 :
225 : GDALDatasetH CPL_DLL GDALArgDatasetValueGetDatasetRef(GDALArgDatasetValueH);
226 :
227 : GDALDatasetH
228 : CPL_DLL GDALArgDatasetValueGetDatasetIncreaseRefCount(GDALArgDatasetValueH);
229 :
230 : /** Bit indicating that the name component of GDALArgDatasetValue is accepted. */
231 : #define GADV_NAME (1 << 0)
232 : /** Bit indicating that the dataset component of GDALArgDatasetValue is accepted. */
233 : #define GADV_OBJECT (1 << 1)
234 :
235 : /** Binary-or combination of GDAL_OF_RASTER, GDAL_OF_VECTOR and
236 : * GDAL_OF_MULTIDIM_RASTER.
237 : */
238 : typedef int GDALArgDatasetValueType;
239 :
240 : GDALArgDatasetValueType
241 : CPL_DLL GDALArgDatasetValueGetType(GDALArgDatasetValueH);
242 :
243 : int CPL_DLL GDALArgDatasetValueGetInputFlags(GDALArgDatasetValueH);
244 :
245 : int CPL_DLL GDALArgDatasetValueGetOutputFlags(GDALArgDatasetValueH);
246 :
247 : void CPL_DLL GDALArgDatasetValueSetName(GDALArgDatasetValueH, const char *);
248 :
249 : void CPL_DLL GDALArgDatasetValueSetDataset(GDALArgDatasetValueH, GDALDatasetH);
250 :
251 : CPL_C_END
252 :
253 : /************************************************************************/
254 : /************************************************************************/
255 : /* GDAL Algorithm C++ API */
256 : /************************************************************************/
257 : /************************************************************************/
258 :
259 : // The rest of this header requires C++17
260 : // _MSC_VER >= 1920 : Visual Studio >= 2019
261 : #if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS) && \
262 : (defined(DOXYGEN_SKIP) || __cplusplus >= 201703L || _MSC_VER >= 1920)
263 :
264 : #include "cpl_error.h"
265 :
266 : #include <limits>
267 : #include <functional>
268 : #include <map>
269 : #include <memory>
270 : #include <string>
271 : #include <type_traits>
272 : #include <utility>
273 : #include <variant>
274 : #include <vector>
275 :
276 : class GDALDataset;
277 :
278 : /** Common argument category */
279 : constexpr const char *GAAC_COMMON = "Common";
280 :
281 : /** Base argument category */
282 : constexpr const char *GAAC_BASE = "Base";
283 :
284 : /** Advanced argument category */
285 : constexpr const char *GAAC_ADVANCED = "Advanced";
286 :
287 : /** Esoteric argument category */
288 : constexpr const char *GAAC_ESOTERIC = "Esoteric";
289 :
290 : /** Argument metadata item that applies to the "input-format" and
291 : * "output-format" argument */
292 : constexpr const char *GAAMDI_REQUIRED_CAPABILITIES = "required_capabilities";
293 :
294 : /** Name of the argument for an input dataset. */
295 : constexpr const char *GDAL_ARG_NAME_INPUT = "input";
296 :
297 : /** Name of the argument for an output dataset. */
298 : constexpr const char *GDAL_ARG_NAME_OUTPUT = "output";
299 :
300 : /** Name of the argument for an output format. */
301 : constexpr const char *GDAL_ARG_NAME_OUTPUT_FORMAT = "output-format";
302 :
303 : /** Name of the argument for update. */
304 : constexpr const char *GDAL_ARG_NAME_UPDATE = "update";
305 :
306 : /** Name of the argument for overwrite. */
307 : constexpr const char *GDAL_ARG_NAME_OVERWRITE = "overwrite";
308 :
309 : /** Name of the argument for read-only. */
310 : constexpr const char *GDAL_ARG_NAME_READ_ONLY = "read-only";
311 :
312 : /************************************************************************/
313 : /* GDALArgDatasetValue */
314 : /************************************************************************/
315 :
316 : /** Return the string representation of GDALArgDatasetValueType */
317 : std::string CPL_DLL GDALArgDatasetValueTypeName(GDALArgDatasetValueType);
318 :
319 : class GDALAlgorithmArg;
320 :
321 : /** Value for an argument that points to a GDALDataset.
322 : *
323 : * This is the value of arguments of type GAAT_DATASET or GAAT_DATASET_LIST.
324 : */
325 : class CPL_DLL GDALArgDatasetValue final
326 : {
327 : public:
328 : /** Default (empty) constructor */
329 2534 : GDALArgDatasetValue() = default;
330 :
331 : /** Constructor by dataset name. */
332 27 : explicit GDALArgDatasetValue(const std::string &name) : m_name(name)
333 : {
334 27 : }
335 :
336 : /** Constructor by dataset instance, increasing its reference counter */
337 : explicit GDALArgDatasetValue(GDALDataset *poDS);
338 :
339 : /** Move constructor */
340 : GDALArgDatasetValue(GDALArgDatasetValue &&other);
341 :
342 : /** Destructor. Decrease m_poDS reference count, and destroy it if no
343 : * longer referenced. */
344 : ~GDALArgDatasetValue();
345 :
346 : /** Dereference the dataset object and close it if no longer referenced.
347 : * Return an error if an error occurred during dataset closing. */
348 : bool Close();
349 :
350 : /** Move-assignment operator */
351 : GDALArgDatasetValue &operator=(GDALArgDatasetValue &&other);
352 :
353 : /** Get the GDALDataset* instance (may be null), and increase its reference
354 : * count if not null. Once done with the dataset, the caller should call
355 : * GDALDataset::Release().
356 : */
357 : GDALDataset *GetDatasetIncreaseRefCount();
358 :
359 : /** Get a GDALDataset* instance (may be null). This does not modify the
360 : * reference counter, hence the lifetime of the returned object is not
361 : * guaranteed to exceed the one of this instance.
362 : */
363 5268 : GDALDataset *GetDatasetRef()
364 : {
365 5268 : return m_poDS;
366 : }
367 :
368 : /** Borrow the GDALDataset* instance (may be null), leaving its reference
369 : * counter unchanged.
370 : */
371 1 : GDALDataset *BorrowDataset()
372 : {
373 1 : GDALDataset *ret = m_poDS;
374 1 : m_poDS = nullptr;
375 1 : return ret;
376 : }
377 :
378 : /** Borrow the GDALDataset* instance from another GDALArgDatasetValue,
379 : * leaving its reference counter unchange.
380 : */
381 : void BorrowDatasetFrom(GDALArgDatasetValue &other)
382 : {
383 : Close();
384 : m_poDS = other.BorrowDataset();
385 : m_name = other.m_name;
386 : }
387 :
388 : /** Get dataset name */
389 1569 : const std::string &GetName() const
390 : {
391 1569 : return m_name;
392 : }
393 :
394 : /** Return whether a dataset name has been set */
395 830 : bool IsNameSet() const
396 : {
397 830 : return m_nameSet;
398 : }
399 :
400 : /** Indicates which components among name and dataset are accepted as
401 : * input, when this argument serves as an input.
402 : *
403 : * If the GADV_NAME bit is set, it indicates a dataset name is accepted as
404 : * input.
405 : * If the GADV_OBJECT bit is set, it indicates a dataset object is
406 : * accepted as input.
407 : * If both bits are set, the algorithm can accept either a name or a dataset
408 : * object.
409 : */
410 154 : int GetInputFlags() const
411 : {
412 154 : return m_inputFlags;
413 : }
414 :
415 : /** Indicates which components among name and dataset are modified,
416 : * when this argument serves as an output.
417 : *
418 : * If the GADV_NAME bit is set, it indicates a dataset name is generated as
419 : * output (that is the algorithm will generate the name. Rarely used).
420 : * If the GADV_OBJECT bit is set, it indicates a dataset object is
421 : * generated as output, and available for use after the algorithm has
422 : * completed.
423 : */
424 51 : int GetOutputFlags() const
425 : {
426 51 : return m_outputFlags;
427 : }
428 :
429 : /** Set dataset name */
430 : void Set(const std::string &name);
431 :
432 : /** Transfer dataset to this instance (does not affect its reference
433 : * counter). */
434 : void Set(std::unique_ptr<GDALDataset> poDS);
435 :
436 : /** Set dataset object, increasing its reference counter. */
437 : void Set(GDALDataset *poDS);
438 :
439 : /** Set from other value, increasing the reference counter of the
440 : * GDALDataset object.
441 : */
442 : void SetFrom(const GDALArgDatasetValue &other);
443 :
444 : /** Set which components among name and dataset are accepted as
445 : * input, when this argument serves as an input.
446 : * Should only be used by GDALAlgorithm sub-classes.
447 : */
448 1220 : void SetInputFlags(int flags)
449 : {
450 1220 : m_inputFlags = flags;
451 1220 : }
452 :
453 : /** Set which components among name and dataset are modified when this
454 : * argument serves as an output.
455 : * Should only be used by GDALAlgorithm sub-classes.
456 : */
457 679 : void SetOutputFlags(int flags)
458 : {
459 679 : m_outputFlags = flags;
460 679 : }
461 :
462 : /** Get which type of dataset is allowed / generated.
463 : * Binary-or combination of GDAL_OF_RASTER, GDAL_OF_VECTOR and
464 : * GDAL_OF_MULTIDIM_RASTER, possibly combined with GDAL_OF_UPDATE.
465 : */
466 596 : GDALArgDatasetValueType GetType() const
467 : {
468 596 : return m_type;
469 : }
470 :
471 : /** Set which type of dataset is allowed / generated.
472 : * Binary-or combination of GDAL_OF_RASTER, GDAL_OF_VECTOR and
473 : * GDAL_OF_MULTIDIM_RASTER.
474 : */
475 1488 : void SetType(GDALArgDatasetValueType type)
476 : {
477 1488 : m_type = type;
478 1488 : }
479 :
480 : protected:
481 : friend class GDALAlgorithm;
482 :
483 : /** Set the argument that owns us. */
484 1488 : void SetOwnerArgument(GDALAlgorithmArg *arg)
485 : {
486 1488 : CPLAssert(!m_ownerArg);
487 1488 : m_ownerArg = arg;
488 1488 : }
489 :
490 : private:
491 : /** The owner argument (may be nullptr for freestanding objects) */
492 : GDALAlgorithmArg *m_ownerArg = nullptr;
493 :
494 : /** Dataset object. */
495 : GDALDataset *m_poDS = nullptr;
496 :
497 : /** Dataset name */
498 : std::string m_name{};
499 :
500 : /** Whether a dataset name (possibly empty for a MEM dataset...) has been set */
501 : bool m_nameSet = false;
502 :
503 : /** Dataset type */
504 : GDALArgDatasetValueType m_type =
505 : GDAL_OF_RASTER | GDAL_OF_VECTOR | GDAL_OF_MULTIDIM_RASTER;
506 :
507 : /** Which components among name and dataset are accepted as
508 : * input, when this argument serves as an input.
509 : */
510 : int m_inputFlags = GADV_NAME | GADV_OBJECT;
511 :
512 : /** Which components among name and dataset are generated as
513 : * output, when this argument serves as an output.
514 : */
515 : int m_outputFlags = GADV_OBJECT;
516 :
517 : GDALArgDatasetValue(const GDALArgDatasetValue &) = delete;
518 : GDALArgDatasetValue &operator=(const GDALArgDatasetValue &) = delete;
519 : };
520 :
521 : /************************************************************************/
522 : /* GDALAlgorithmArgDecl */
523 : /************************************************************************/
524 :
525 : /** Argument declaration.
526 : *
527 : * It does not hold its value.
528 : */
529 : class CPL_DLL GDALAlgorithmArgDecl final
530 : {
531 : public:
532 : /** Special value for the SetMaxCount() / GetMaxCount() to indicate
533 : * unlimited number of values. */
534 : static constexpr int UNBOUNDED = std::numeric_limits<int>::max();
535 :
536 : /** Constructor.
537 : *
538 : * @param longName Long name. Must be 2 characters at least. Must not start
539 : * with dash.
540 : * @param chShortName 1-letter short name, or NUL character
541 : * @param description Description.
542 : * @param type Type of the argument.
543 : */
544 : GDALAlgorithmArgDecl(const std::string &longName, char chShortName,
545 : const std::string &description,
546 : GDALAlgorithmArgType type);
547 :
548 : /** Declare an alias. Must be 2 characters at least. */
549 4596 : GDALAlgorithmArgDecl &AddAlias(const std::string &alias)
550 : {
551 4596 : m_aliases.push_back(alias);
552 4596 : return *this;
553 : }
554 :
555 : /** Declare an hidden alias (i.e. not exposed in usage).
556 : * Must be 2 characters at least. */
557 766 : GDALAlgorithmArgDecl &AddHiddenAlias(const std::string &alias)
558 : {
559 766 : m_hiddenAliases.push_back(alias);
560 766 : return *this;
561 : }
562 :
563 : /** Declare that the argument is positional. Typically input / output files
564 : */
565 1438 : GDALAlgorithmArgDecl &SetPositional()
566 : {
567 1438 : m_positional = true;
568 1438 : return *this;
569 : }
570 :
571 : /** Declare that the argument is required. Default is no
572 : */
573 1262 : GDALAlgorithmArgDecl &SetRequired()
574 : {
575 1262 : m_required = true;
576 1262 : return *this;
577 : }
578 :
579 : /** Declare the "meta-var" hint.
580 : * By default, the meta-var value is the long name of the argument in
581 : * upper case.
582 : */
583 4307 : GDALAlgorithmArgDecl &SetMetaVar(const std::string &metaVar)
584 : {
585 4307 : m_metaVar = metaVar;
586 4307 : return *this;
587 : }
588 :
589 : /** Declare the argument category: GAAC_COMMON, GAAC_BASE, GAAC_ADVANCED,
590 : * GAAC_ESOTERIC or a custom category.
591 : */
592 12032 : GDALAlgorithmArgDecl &SetCategory(const std::string &category)
593 : {
594 12032 : m_category = category;
595 12032 : return *this;
596 : }
597 :
598 : /** Declare a default value for the argument.
599 : */
600 1871 : template <class T> GDALAlgorithmArgDecl &SetDefault(const T &value)
601 : {
602 1871 : m_hasDefaultValue = true;
603 : if constexpr (std::is_same_v<T, int>)
604 : {
605 20 : if (m_type == GAAT_REAL)
606 : {
607 1 : m_defaultValue = static_cast<double>(value);
608 1 : return *this;
609 : }
610 : }
611 1870 : m_defaultValue = value;
612 1870 : return *this;
613 : }
614 :
615 : /** Declare the minimum number of values for the argument. Defaults to 0.
616 : * Only applies to list type of arguments.
617 : * Setting it to non-zero does *not* make the argument required. It just
618 : * sets the minimum number of values when it is specified. To also make
619 : * it required, use SetRequired().
620 : */
621 : GDALAlgorithmArgDecl &SetMinCount(int count);
622 :
623 : /** Declare the maximum number of values for the argument.
624 : * Defaults to 1 for scalar types, and UNBOUNDED for list types.
625 : * Only applies to list type of arguments.
626 : */
627 : GDALAlgorithmArgDecl &SetMaxCount(int count);
628 :
629 : /** Declare whether in \--help message one should display hints about the
630 : * minimum/maximum number of values. Defaults to true.
631 : */
632 268 : GDALAlgorithmArgDecl &SetDisplayHintAboutRepetition(bool displayHint)
633 : {
634 268 : m_displayHintAboutRepetition = displayHint;
635 268 : return *this;
636 : }
637 :
638 : /** Declares whether, for list type of arguments, several values, space
639 : * separated, may be specified. That is "--foo=bar,baz".
640 : * The default is true.
641 : */
642 17 : GDALAlgorithmArgDecl &SetPackedValuesAllowed(bool allowed)
643 : {
644 17 : m_packedValuesAllowed = allowed;
645 17 : return *this;
646 : }
647 :
648 : /** Declares whether, for list type of arguments, the argument may be
649 : * repeated. That is "--foo=bar --foo=baz".
650 : * The default is true.
651 : */
652 513 : GDALAlgorithmArgDecl &SetRepeatedArgAllowed(bool allowed)
653 : {
654 513 : m_repeatedArgAllowed = allowed;
655 513 : return *this;
656 : }
657 :
658 : //! @cond Doxygen_Suppress
659 294 : GDALAlgorithmArgDecl &SetChoices()
660 : {
661 294 : return *this;
662 : }
663 :
664 : //! @endcond
665 :
666 : /** Declares the allowed values (as strings) for the argument.
667 : * Only honored for GAAT_STRING and GAAT_STRING_LIST types.
668 : */
669 : template <typename T, typename... U>
670 2255 : GDALAlgorithmArgDecl &SetChoices(T &&first, U &&...rest)
671 : {
672 2255 : m_choices.push_back(std::forward<T>(first));
673 2255 : SetChoices(std::forward<U>(rest)...);
674 2255 : return *this;
675 : }
676 :
677 : //! @cond Doxygen_Suppress
678 64 : GDALAlgorithmArgDecl &SetHiddenChoices()
679 : {
680 64 : return *this;
681 : }
682 :
683 : //! @endcond
684 :
685 : /** Declares the, hidden, allowed values (as strings) for the argument.
686 : * Only honored for GAAT_STRING and GAAT_STRING_LIST types.
687 : */
688 : template <typename T, typename... U>
689 64 : GDALAlgorithmArgDecl &SetHiddenChoices(T &&first, U &&...rest)
690 : {
691 64 : m_hiddenChoices.push_back(std::forward<T>(first));
692 64 : SetHiddenChoices(std::forward<U>(rest)...);
693 64 : return *this;
694 : }
695 :
696 : /** Declare that the argument must not be mentioned in CLI usage.
697 : * For example, "output-value" for "gdal raster info", which is only
698 : * meant when the algorithm is used from a non-CLI context.
699 : */
700 5205 : GDALAlgorithmArgDecl &SetHiddenForCLI(bool hiddenForCLI = true)
701 : {
702 5205 : m_hiddenForCLI = hiddenForCLI;
703 5205 : return *this;
704 : }
705 :
706 : /** Declare that the argument is only for CLI usage.
707 : * For example "--help" */
708 9920 : GDALAlgorithmArgDecl &SetOnlyForCLI(bool onlyForCLI = true)
709 : {
710 9920 : m_onlyForCLI = onlyForCLI;
711 9920 : return *this;
712 : }
713 :
714 : /** Declare that the argument is hidden. Default is no
715 : */
716 1883 : GDALAlgorithmArgDecl &SetHidden()
717 : {
718 1883 : m_hidden = true;
719 1883 : return *this;
720 : }
721 :
722 : /** Indicate whether the value of the argument is read-only during the
723 : * execution of the algorithm. Default is true.
724 : */
725 757 : GDALAlgorithmArgDecl &SetIsInput(bool isInput = true)
726 : {
727 757 : m_isInput = isInput;
728 757 : return *this;
729 : }
730 :
731 : /** Indicate whether (at least part of) the value of the argument is set
732 : * during the execution of the algorithm.
733 : * For example, "output-value" for "gdal raster info"
734 : * Default is false.
735 : * An argument may return both IsInput() and IsOutput() as true.
736 : * For example the "gdal raster convert" algorithm consumes the dataset
737 : * name of its "output" argument, and sets the dataset object during its
738 : * execution.
739 : */
740 757 : GDALAlgorithmArgDecl &SetIsOutput(bool isOutput = true)
741 : {
742 757 : m_isOutput = isOutput;
743 757 : return *this;
744 : }
745 :
746 : /** Set the name of the mutual exclusion group to which this argument
747 : * belongs to. At most one argument in a group can be specified.
748 : */
749 807 : GDALAlgorithmArgDecl &SetMutualExclusionGroup(const std::string &group)
750 : {
751 807 : m_mutualExclusionGroup = group;
752 807 : return *this;
753 : }
754 :
755 : /** Set user-defined metadata item.
756 : */
757 : GDALAlgorithmArgDecl &
758 1280 : AddMetadataItem(const std::string &name,
759 : const std::vector<std::string> &values)
760 : {
761 1280 : m_metadata[name] = values;
762 1280 : return *this;
763 : }
764 :
765 : /** Set that this (string) argument accepts the \@filename syntax to
766 : * mean that the content of the specified file should be used as the
767 : * value of the argument.
768 : */
769 104 : GDALAlgorithmArgDecl &SetReadFromFileAtSyntaxAllowed()
770 : {
771 104 : m_readFromFileAtSyntaxAllowed = true;
772 104 : return *this;
773 : }
774 :
775 : /** Sets that SQL comments must be removed from a (string) argument.
776 : */
777 103 : GDALAlgorithmArgDecl &SetRemoveSQLCommentsEnabled()
778 : {
779 103 : m_removeSQLComments = true;
780 103 : return *this;
781 : }
782 :
783 : /** Sets whether the dataset should be opened automatically by
784 : * GDALAlgorithm. Only applies to GAAT_DATASET and GAAT_DATASET_LIST.
785 : */
786 71 : GDALAlgorithmArgDecl &SetAutoOpenDataset(bool autoOpen)
787 : {
788 71 : m_autoOpenDataset = autoOpen;
789 71 : return *this;
790 : }
791 :
792 : /** Return the (long) name */
793 29575 : inline const std::string &GetName() const
794 : {
795 29575 : return m_longName;
796 : }
797 :
798 : /** Return the short name, or empty string if there is none */
799 23704 : inline const std::string &GetShortName() const
800 : {
801 23704 : return m_shortName;
802 : }
803 :
804 : /** Return the aliases (potentially none) */
805 694 : inline const std::vector<std::string> &GetAliases() const
806 : {
807 694 : return m_aliases;
808 : }
809 :
810 : /** Return the description */
811 1280 : inline const std::string &GetDescription() const
812 : {
813 1280 : return m_description;
814 : }
815 :
816 : /** Return the "meta-var" hint.
817 : * By default, the meta-var value is the long name of the argument in
818 : * upper case.
819 : */
820 702 : inline const std::string &GetMetaVar() const
821 : {
822 702 : return m_metaVar;
823 : }
824 :
825 : /** Return the argument category: GAAC_COMMON, GAAC_BASE, GAAC_ADVANCED,
826 : * GAAC_ESOTERIC or a custom category.
827 : */
828 1994 : inline const std::string &GetCategory() const
829 : {
830 1994 : return m_category;
831 : }
832 :
833 : /** Return the type */
834 32601 : inline GDALAlgorithmArgType GetType() const
835 : {
836 32601 : return m_type;
837 : }
838 :
839 : /** Return the allowed values (as strings) for the argument.
840 : * Only honored for GAAT_STRING and GAAT_STRING_LIST types.
841 : */
842 1890 : inline const std::vector<std::string> &GetChoices() const
843 : {
844 1890 : return m_choices;
845 : }
846 :
847 : /** Return the allowed hidden values (as strings) for the argument.
848 : * Only honored for GAAT_STRING and GAAT_STRING_LIST types.
849 : */
850 342 : inline const std::vector<std::string> &GetHiddenChoices() const
851 : {
852 342 : return m_hiddenChoices;
853 : }
854 :
855 : /** Return whether the argument is required. Defaults to false.
856 : */
857 20807 : inline bool IsRequired() const
858 : {
859 20807 : return m_required;
860 : }
861 :
862 : /** Return the minimum number of values for the argument. Defaults to 0.
863 : * Only applies to list type of arguments.
864 : */
865 2582 : inline int GetMinCount() const
866 : {
867 2582 : return m_minCount;
868 : }
869 :
870 : /** Return the maximum number of values for the argument.
871 : * Defaults to 1 for scalar types, and UNBOUNDED for list types.
872 : * Only applies to list type of arguments.
873 : */
874 2293 : inline int GetMaxCount() const
875 : {
876 2293 : return m_maxCount;
877 : }
878 :
879 : /** Returns whether in \--help message one should display hints about the
880 : * minimum/maximum number of values. Defaults to true.
881 : */
882 372 : inline bool GetDisplayHintAboutRepetition() const
883 : {
884 372 : return m_displayHintAboutRepetition;
885 : }
886 :
887 : /** Return whether, for list type of arguments, several values, space
888 : * separated, may be specified. That is "--foo=bar,baz".
889 : * The default is true.
890 : */
891 535 : inline bool GetPackedValuesAllowed() const
892 : {
893 535 : return m_packedValuesAllowed;
894 : }
895 :
896 : /** Return whether, for list type of arguments, the argument may be
897 : * repeated. That is "--foo=bar --foo=baz".
898 : * The default is true.
899 : */
900 1448 : inline bool GetRepeatedArgAllowed() const
901 : {
902 1448 : return m_repeatedArgAllowed;
903 : }
904 :
905 : /** Return if the argument is a positional one. */
906 1846 : inline bool IsPositional() const
907 : {
908 1846 : return m_positional;
909 : }
910 :
911 : /** Return if the argument has a declared default value. */
912 24400 : inline bool HasDefaultValue() const
913 : {
914 24400 : return m_hasDefaultValue;
915 : }
916 :
917 : /** Return whether the argument is hidden.
918 : */
919 6813 : inline bool IsHidden() const
920 : {
921 6813 : return m_hidden;
922 : }
923 :
924 : /** Return whether the argument must not be mentioned in CLI usage.
925 : * For example, "output-value" for "gdal raster info", which is only
926 : * meant when the algorithm is used from a non-CLI context.
927 : */
928 1536 : inline bool IsHiddenForCLI() const
929 : {
930 1536 : return m_hiddenForCLI;
931 : }
932 :
933 : /** Return whether the argument is only for CLI usage.
934 : * For example "--help" */
935 4732 : inline bool IsOnlyForCLI() const
936 : {
937 4732 : return m_onlyForCLI;
938 : }
939 :
940 : /** Indicate whether the value of the argument is read-only during the
941 : * execution of the algorithm. Default is true.
942 : */
943 2828 : inline bool IsInput() const
944 : {
945 2828 : return m_isInput;
946 : }
947 :
948 : /** Return whether (at least part of) the value of the argument is set
949 : * during the execution of the algorithm.
950 : * For example, "output-value" for "gdal raster info"
951 : * Default is false.
952 : * An argument may return both IsInput() and IsOutput() as true.
953 : * For example the "gdal raster convert" algorithm consumes the dataset
954 : * name of its "output" argument, and sets the dataset object during its
955 : * execution.
956 : */
957 4411 : inline bool IsOutput() const
958 : {
959 4411 : return m_isOutput;
960 : }
961 :
962 : /** Return the name of the mutual exclusion group to which this argument
963 : * belongs to, or empty string if it does not belong to any exclusion
964 : * group.
965 : */
966 4163 : inline const std::string &GetMutualExclusionGroup() const
967 : {
968 4163 : return m_mutualExclusionGroup;
969 : }
970 :
971 : /** Return if this (string) argument accepts the \@filename syntax to
972 : * mean that the content of the specified file should be used as the
973 : * value of the argument.
974 : */
975 514 : inline bool IsReadFromFileAtSyntaxAllowed() const
976 : {
977 514 : return m_readFromFileAtSyntaxAllowed;
978 : }
979 :
980 : /** Returns whether SQL comments must be removed from a (string) argument.
981 : */
982 505 : bool IsRemoveSQLCommentsEnabled() const
983 : {
984 505 : return m_removeSQLComments;
985 : }
986 :
987 : /** Returns whether the dataset should be opened automatically by
988 : * GDALAlgorithm. Only applies to GAAT_DATASET and GAAT_DATASET_LIST.
989 : */
990 875 : bool AutoOpenDataset() const
991 : {
992 875 : return m_autoOpenDataset;
993 : }
994 :
995 : /** Get user-defined metadata. */
996 : inline const std::map<std::string, std::vector<std::string>>
997 906 : GetMetadata() const
998 : {
999 906 : return m_metadata;
1000 : }
1001 :
1002 : /** Get user-defined metadata by item name. */
1003 : inline const std::vector<std::string> *
1004 385 : GetMetadataItem(const std::string &name) const
1005 : {
1006 385 : const auto iter = m_metadata.find(name);
1007 385 : return iter == m_metadata.end() ? nullptr : &(iter->second);
1008 : }
1009 :
1010 : /** Return the default value of the argument.
1011 : * Must be called with T consistent of the type of the algorithm, and only
1012 : * if HasDefaultValue() is true.
1013 : * Valid T types are:
1014 : * - bool for GAAT_BOOLEAN
1015 : * - int for GAAT_INTEGER
1016 : * - double for GAAT_REAL
1017 : * - std::string for GAAT_STRING
1018 : * - GDALArgDatasetValue for GAAT_DATASET
1019 : * - std::vector<int> for GAAT_INTEGER_LIST
1020 : * - std::vector<double for GAAT_REAL_LIST
1021 : * - std::vector<std::string> for GAAT_STRING_LIST
1022 : * - std::vector<GDALArgDatasetValue> for GAAT_DATASET_LIST
1023 : */
1024 132 : template <class T> inline const T &GetDefault() const
1025 : {
1026 132 : return std::get<T>(m_defaultValue);
1027 : }
1028 :
1029 : private:
1030 : const std::string m_longName;
1031 : const std::string m_shortName;
1032 : const std::string m_description;
1033 : const GDALAlgorithmArgType m_type;
1034 : std::string m_category = GAAC_BASE;
1035 : std::string m_metaVar{};
1036 : std::string m_mutualExclusionGroup{};
1037 : int m_minCount = 0;
1038 : int m_maxCount = 0;
1039 : bool m_required = false;
1040 : bool m_positional = false;
1041 : bool m_hasDefaultValue = false;
1042 : bool m_hidden = false;
1043 : bool m_hiddenForCLI = false;
1044 : bool m_onlyForCLI = false;
1045 : bool m_isInput = true;
1046 : bool m_isOutput = false;
1047 : bool m_packedValuesAllowed = true;
1048 : bool m_repeatedArgAllowed = true;
1049 : bool m_displayHintAboutRepetition = true;
1050 : bool m_readFromFileAtSyntaxAllowed = false;
1051 : bool m_removeSQLComments = false;
1052 : bool m_autoOpenDataset = true;
1053 : std::map<std::string, std::vector<std::string>> m_metadata{};
1054 : std::vector<std::string> m_aliases{};
1055 : std::vector<std::string> m_hiddenAliases{};
1056 : std::vector<std::string> m_choices{};
1057 : std::vector<std::string> m_hiddenChoices{};
1058 : std::variant<bool, std::string, int, double, std::vector<std::string>,
1059 : std::vector<int>, std::vector<double>>
1060 : m_defaultValue{};
1061 : };
1062 :
1063 : /************************************************************************/
1064 : /* GDALAlgorithmArg */
1065 : /************************************************************************/
1066 :
1067 : class GDALAlgorithm;
1068 :
1069 : /** Argument of an algorithm.
1070 : */
1071 : class CPL_DLL GDALAlgorithmArg /* non-final */
1072 : {
1073 : public:
1074 : /** Constructor */
1075 : template <class T>
1076 22881 : GDALAlgorithmArg(const GDALAlgorithmArgDecl &decl, T *pValue)
1077 22881 : : m_decl(decl), m_value(pValue)
1078 : {
1079 : if constexpr (!std::is_same_v<T, GDALArgDatasetValue> &&
1080 : !std::is_same_v<T, std::vector<GDALArgDatasetValue>>)
1081 : {
1082 21348 : if (decl.HasDefaultValue())
1083 : {
1084 : try
1085 : {
1086 2 : *std::get<T *>(m_value) = decl.GetDefault<T>();
1087 : }
1088 0 : catch (const std::bad_variant_access &e)
1089 : {
1090 : // I don't think that can happen, but Coverity Scan thinks
1091 : // so
1092 0 : CPLError(CE_Failure, CPLE_AppDefined,
1093 : "*std::get<T *>(m_value) = decl.GetDefault<T>() "
1094 : "failed: %s",
1095 0 : e.what());
1096 : }
1097 : }
1098 : }
1099 22881 : }
1100 :
1101 : /** Return the argument declaration. */
1102 : const GDALAlgorithmArgDecl &GetDeclaration() const
1103 : {
1104 : return m_decl;
1105 : }
1106 :
1107 : /** Alias for GDALAlgorithmArgDecl::GetName() */
1108 29573 : inline const std::string &GetName() const
1109 : {
1110 29573 : return m_decl.GetName();
1111 : }
1112 :
1113 : /** Alias for GDALAlgorithmArgDecl::GetShortName() */
1114 23704 : inline const std::string &GetShortName() const
1115 : {
1116 23704 : return m_decl.GetShortName();
1117 : }
1118 :
1119 : /** Alias for GDALAlgorithmArgDecl::GetAliases() */
1120 694 : inline const std::vector<std::string> &GetAliases() const
1121 : {
1122 694 : return m_decl.GetAliases();
1123 : }
1124 :
1125 : /** Alias for GDALAlgorithmArgDecl::GetDescription() */
1126 1280 : inline const std::string &GetDescription() const
1127 : {
1128 1280 : return m_decl.GetDescription();
1129 : }
1130 :
1131 : /** Alias for GDALAlgorithmArgDecl::GetMetaVar() */
1132 702 : inline const std::string &GetMetaVar() const
1133 : {
1134 702 : return m_decl.GetMetaVar();
1135 : }
1136 :
1137 : /** Alias for GDALAlgorithmArgDecl::GetType() */
1138 30296 : inline GDALAlgorithmArgType GetType() const
1139 : {
1140 30296 : return m_decl.GetType();
1141 : }
1142 :
1143 : /** Alias for GDALAlgorithmArgDecl::GetCategory() */
1144 1994 : inline const std::string &GetCategory() const
1145 : {
1146 1994 : return m_decl.GetCategory();
1147 : }
1148 :
1149 : /** Alias for GDALAlgorithmArgDecl::IsRequired() */
1150 20807 : inline bool IsRequired() const
1151 : {
1152 20807 : return m_decl.IsRequired();
1153 : }
1154 :
1155 : /** Alias for GDALAlgorithmArgDecl::GetMinCount() */
1156 2580 : inline int GetMinCount() const
1157 : {
1158 2580 : return m_decl.GetMinCount();
1159 : }
1160 :
1161 : /** Alias for GDALAlgorithmArgDecl::GetMaxCount() */
1162 2291 : inline int GetMaxCount() const
1163 : {
1164 2291 : return m_decl.GetMaxCount();
1165 : }
1166 :
1167 : /** Alias for GDALAlgorithmArgDecl::GetDisplayHintAboutRepetition() */
1168 372 : inline bool GetDisplayHintAboutRepetition() const
1169 : {
1170 372 : return m_decl.GetDisplayHintAboutRepetition();
1171 : }
1172 :
1173 : /** Alias for GDALAlgorithmArgDecl::GetPackedValuesAllowed() */
1174 535 : inline bool GetPackedValuesAllowed() const
1175 : {
1176 535 : return m_decl.GetPackedValuesAllowed();
1177 : }
1178 :
1179 : /** Alias for GDALAlgorithmArgDecl::GetRepeatedArgAllowed() */
1180 1448 : inline bool GetRepeatedArgAllowed() const
1181 : {
1182 1448 : return m_decl.GetRepeatedArgAllowed();
1183 : }
1184 :
1185 : /** Alias for GDALAlgorithmArgDecl::IsPositional() */
1186 1846 : inline bool IsPositional() const
1187 : {
1188 1846 : return m_decl.IsPositional();
1189 : }
1190 :
1191 : /** Alias for GDALAlgorithmArgDecl::GetChoices() */
1192 1890 : inline const std::vector<std::string> &GetChoices() const
1193 : {
1194 1890 : return m_decl.GetChoices();
1195 : }
1196 :
1197 : /** Alias for GDALAlgorithmArgDecl::GetHiddenChoices() */
1198 342 : inline const std::vector<std::string> &GetHiddenChoices() const
1199 : {
1200 342 : return m_decl.GetHiddenChoices();
1201 : }
1202 :
1203 : /** Return auto completion choices, if a auto completion function has been
1204 : * registered.
1205 : */
1206 : inline std::vector<std::string>
1207 30 : GetAutoCompleteChoices(const std::string ¤tValue) const
1208 : {
1209 30 : if (m_autoCompleteFunction)
1210 29 : return m_autoCompleteFunction(currentValue);
1211 1 : return {};
1212 : }
1213 :
1214 : /** Return whether the argument value has been explicitly set with Set() */
1215 83220 : inline bool IsExplicitlySet() const
1216 : {
1217 83220 : return m_explicitlySet;
1218 : }
1219 :
1220 : /** Alias for GDALAlgorithmArgDecl::HasDefaultValue() */
1221 1183 : inline bool HasDefaultValue() const
1222 : {
1223 1183 : return m_decl.HasDefaultValue();
1224 : }
1225 :
1226 : /** Alias for GDALAlgorithmArgDecl::IsHidden() */
1227 6813 : inline bool IsHidden() const
1228 : {
1229 6813 : return m_decl.IsHidden();
1230 : }
1231 :
1232 : /** Alias for GDALAlgorithmArgDecl::IsHiddenForCLI() */
1233 1536 : inline bool IsHiddenForCLI() const
1234 : {
1235 1536 : return m_decl.IsHiddenForCLI();
1236 : }
1237 :
1238 : /** Alias for GDALAlgorithmArgDecl::IsOnlyForCLI() */
1239 4732 : inline bool IsOnlyForCLI() const
1240 : {
1241 4732 : return m_decl.IsOnlyForCLI();
1242 : }
1243 :
1244 : /** Alias for GDALAlgorithmArgDecl::IsInput() */
1245 2828 : inline bool IsInput() const
1246 : {
1247 2828 : return m_decl.IsInput();
1248 : }
1249 :
1250 : /** Alias for GDALAlgorithmArgDecl::IsOutput() */
1251 4411 : inline bool IsOutput() const
1252 : {
1253 4411 : return m_decl.IsOutput();
1254 : }
1255 :
1256 : /** Alias for GDALAlgorithmArgDecl::IsReadFromFileAtSyntaxAllowed() */
1257 : inline bool IsReadFromFileAtSyntaxAllowed() const
1258 : {
1259 : return m_decl.IsReadFromFileAtSyntaxAllowed();
1260 : }
1261 :
1262 : /** Alias for GDALAlgorithmArgDecl::IsRemoveSQLCommentsEnabled() */
1263 : inline bool IsRemoveSQLCommentsEnabled() const
1264 : {
1265 : return m_decl.IsRemoveSQLCommentsEnabled();
1266 : }
1267 :
1268 : /** Alias for GDALAlgorithmArgDecl::GetMutualExclusionGroup() */
1269 4163 : inline const std::string &GetMutualExclusionGroup() const
1270 : {
1271 4163 : return m_decl.GetMutualExclusionGroup();
1272 : }
1273 :
1274 : /** Alias for GDALAlgorithmArgDecl::GetMetadata() */
1275 : inline const std::map<std::string, std::vector<std::string>>
1276 906 : GetMetadata() const
1277 : {
1278 906 : return m_decl.GetMetadata();
1279 : }
1280 :
1281 : /** Alias for GDALAlgorithmArgDecl::GetMetadataItem() */
1282 : inline const std::vector<std::string> *
1283 385 : GetMetadataItem(const std::string &name) const
1284 : {
1285 385 : return m_decl.GetMetadataItem(name);
1286 : }
1287 :
1288 : /** Alias for GDALAlgorithmArgDecl::GetDefault() */
1289 130 : template <class T> inline const T &GetDefault() const
1290 : {
1291 130 : return m_decl.GetDefault<T>();
1292 : }
1293 :
1294 : /** Alias for GDALAlgorithmArgDecl::AutoOpenDataset() */
1295 875 : inline bool AutoOpenDataset() const
1296 : {
1297 875 : return m_decl.AutoOpenDataset();
1298 : }
1299 :
1300 : /** Return the value of the argument, which is by decreasing order of priority:
1301 : * - the value set through Set().
1302 : * - the default value set through SetDefault().
1303 : * - the initial value of the C++ variable to which this argument is bound to.
1304 : *
1305 : * Must be called with T consistent of the type of the algorithm:
1306 : * - bool for GAAT_BOOLEAN
1307 : * - int for GAAT_INTEGER
1308 : * - double for GAAT_REAL
1309 : * - std::string for GAAT_STRING
1310 : * - GDALArgDatasetValue for GAAT_DATASET
1311 : * - std::vector<int> for GAAT_INTEGER_LIST
1312 : * - std::vector<double for GAAT_REAL_LIST
1313 : * - std::vector<std::string> for GAAT_STRING_LIST
1314 : * - std::vector<GDALArgDatasetValue> for GAAT_DATASET_LIST
1315 : */
1316 4531 : template <class T> inline T &Get()
1317 : {
1318 4531 : return *(std::get<T *>(m_value));
1319 : }
1320 :
1321 : /** Return the value of the argument, which is by decreasing order of priority:
1322 : * - the value set through Set().
1323 : * - the default value set through SetDefault().
1324 : * - the initial value of the C++ variable to which this argument is bound to.
1325 : *
1326 : * Must be called with T consistent of the type of the algorithm:
1327 : * - bool for GAAT_BOOLEAN
1328 : * - int for GAAT_INTEGER
1329 : * - double for GAAT_REAL
1330 : * - std::string for GAAT_STRING
1331 : * - GDALArgDatasetValue for GAAT_DATASET
1332 : * - std::vector<int> for GAAT_INTEGER_LIST
1333 : * - std::vector<double for GAAT_REAL_LIST
1334 : * - std::vector<std::string> for GAAT_STRING_LIST
1335 : * - std::vector<GDALArgDatasetValue> for GAAT_DATASET_LIST
1336 : */
1337 809 : template <class T> inline const T &Get() const
1338 : {
1339 809 : return *(std::get<T *>(m_value));
1340 : }
1341 :
1342 : /** Set the value for a GAAT_BOOLEAN argument.
1343 : * It cannot be called several times for a given argument.
1344 : * Validation checks and other actions are run.
1345 : * Return true if success.
1346 : */
1347 : bool Set(bool value);
1348 :
1349 : /** Set the value for a GAAT_STRING argument.
1350 : * It cannot be called several times for a given argument.
1351 : * Validation checks and other actions are run.
1352 : * Return true if success.
1353 : */
1354 : bool Set(const std::string &value);
1355 :
1356 : /** Set the value for a GAAT_STRING argument.
1357 : * It cannot be called several times for a given argument.
1358 : * Validation checks and other actions are run.
1359 : * Return true if success.
1360 : */
1361 111 : bool Set(const char *value)
1362 : {
1363 111 : return Set(std::string(value ? value : ""));
1364 : }
1365 :
1366 : /** Set the value for a GAAT_INTEGER (or GAAT_REAL) argument.
1367 : * It cannot be called several times for a given argument.
1368 : * Validation checks and other actions are run.
1369 : * Return true if success.
1370 : */
1371 : bool Set(int value);
1372 :
1373 : /** Set the value for a GAAT_REAL argument */
1374 : bool Set(double value);
1375 :
1376 : /** Set the value for a GAAT_DATASET argument, increasing ds' reference
1377 : * counter if ds is not null.
1378 : * It cannot be called several times for a given argument.
1379 : * Validation checks and other actions are run.
1380 : * Return true if success.
1381 : */
1382 : bool Set(GDALDataset *ds);
1383 :
1384 : /** Set the value for a GAAT_DATASET argument.
1385 : * It cannot be called several times for a given argument.
1386 : * Validation checks and other actions are run.
1387 : * Return true if success.
1388 : */
1389 : bool Set(std::unique_ptr<GDALDataset> ds);
1390 :
1391 : /** Set the value for a GAAT_DATASET argument.
1392 : * It cannot be called several times for a given argument.
1393 : * Validation checks and other actions are run.
1394 : * Return true if success.
1395 : */
1396 : bool SetDatasetName(const std::string &name);
1397 :
1398 : /** Set the value for a GAAT_DATASET argument.
1399 : * It references the dataset pointed by other.m_poDS.
1400 : * It cannot be called several times for a given argument.
1401 : * Validation checks and other actions are run.
1402 : * Return true if success.
1403 : */
1404 : bool SetFrom(const GDALArgDatasetValue &other);
1405 :
1406 : /** Set the value for a GAAT_STRING_LIST argument.
1407 : * It cannot be called several times for a given argument.
1408 : * Validation checks and other actions are run.
1409 : * Return true if success.
1410 : */
1411 : bool Set(const std::vector<std::string> &value);
1412 :
1413 : /** Set the value for a GAAT_INTEGER_LIST argument.
1414 : * It cannot be called several times for a given argument.
1415 : * Validation checks and other actions are run.
1416 : * Return true if success.
1417 : */
1418 : bool Set(const std::vector<int> &value);
1419 :
1420 : /** Set the value for a GAAT_REAL_LIST argument.
1421 : * It cannot be called several times for a given argument.
1422 : * Validation checks and other actions are run.
1423 : * Return true if success.
1424 : */
1425 : bool Set(const std::vector<double> &value);
1426 :
1427 : /** Set the value for a GAAT_DATASET_LIST argument.
1428 : * It cannot be called several times for a given argument.
1429 : * Validation checks and other actions are run.
1430 : * Return true if success.
1431 : */
1432 : bool Set(std::vector<GDALArgDatasetValue> &&value);
1433 :
1434 : /** Set the value for another argument.
1435 : * For GAAT_DATASET, it will reference the dataset pointed by other.m_poDS.
1436 : * It cannot be called several times for a given argument.
1437 : * Validation checks and other actions are run.
1438 : * Return true if success.
1439 : */
1440 : bool SetFrom(const GDALAlgorithmArg &other);
1441 :
1442 : /** Advanced method used to make "gdal info" and "gdal raster|vector info"
1443 : * to avoid re-opening an already opened dataset */
1444 321 : void SetSkipIfAlreadySet(bool skip = true)
1445 : {
1446 321 : m_skipIfAlreadySet = skip;
1447 321 : }
1448 :
1449 : /** Advanced method used to make "gdal info" and "gdal raster|vector info"
1450 : * to avoid re-opening an already opened dataset */
1451 3 : bool SkipIfAlreadySet() const
1452 : {
1453 3 : return m_skipIfAlreadySet;
1454 : }
1455 :
1456 : /** Serialize this argument and its value.
1457 : * May return false if the argument is not explicitly set or if a dataset
1458 : * is passed by value.
1459 : */
1460 : bool Serialize(std::string &serializedArg) const;
1461 :
1462 : //! @cond Doxygen_Suppress
1463 1595 : void NotifyValueSet()
1464 : {
1465 1595 : m_explicitlySet = true;
1466 1595 : }
1467 :
1468 : //! @endcond
1469 :
1470 : protected:
1471 : friend class GDALAlgorithm;
1472 : /** Argument declaration */
1473 : GDALAlgorithmArgDecl m_decl;
1474 : /** Pointer to the value */
1475 : std::variant<bool *, std::string *, int *, double *, GDALArgDatasetValue *,
1476 : std::vector<std::string> *, std::vector<int> *,
1477 : std::vector<double> *, std::vector<GDALArgDatasetValue> *>
1478 : m_value{};
1479 : /** Actions */
1480 : std::vector<std::function<void()>> m_actions{};
1481 : /** Validation actions */
1482 : std::vector<std::function<bool()>> m_validationActions{};
1483 : /** Autocompletion function */
1484 : std::function<std::vector<std::string>(const std::string &)>
1485 : m_autoCompleteFunction{};
1486 :
1487 : private:
1488 : bool m_skipIfAlreadySet = false;
1489 : bool m_explicitlySet = false;
1490 :
1491 852 : template <class T> bool SetInternal(const T &value)
1492 : {
1493 852 : m_explicitlySet = true;
1494 852 : *std::get<T *>(m_value) = value;
1495 852 : return RunAllActions();
1496 : }
1497 :
1498 : bool ProcessString(std::string &value) const;
1499 :
1500 : bool RunAllActions();
1501 : void RunActions();
1502 : bool RunValidationActions();
1503 : };
1504 :
1505 : /************************************************************************/
1506 : /* GDALInConstructionAlgorithmArg */
1507 : /************************************************************************/
1508 :
1509 : //! @cond Doxygen_Suppress
1510 : namespace test_gdal_algorithm
1511 : {
1512 : struct test_gdal_algorithm;
1513 : }
1514 :
1515 : //! @endcond
1516 :
1517 : /** Technical class used by GDALAlgorithm when constructing argument
1518 : * declarations.
1519 : */
1520 : class CPL_DLL GDALInConstructionAlgorithmArg final : public GDALAlgorithmArg
1521 : {
1522 : friend struct test_gdal_algorithm::test_gdal_algorithm;
1523 :
1524 : public:
1525 : /** Constructor */
1526 : template <class T>
1527 22859 : GDALInConstructionAlgorithmArg(GDALAlgorithm *owner,
1528 : const GDALAlgorithmArgDecl &decl, T *pValue)
1529 22859 : : GDALAlgorithmArg(decl, pValue), m_owner(owner)
1530 : {
1531 22859 : }
1532 :
1533 : /** Add a documented alias for the argument */
1534 : GDALInConstructionAlgorithmArg &AddAlias(const std::string &alias);
1535 :
1536 : /** Add a non-documented alias for the argument */
1537 : GDALInConstructionAlgorithmArg &AddHiddenAlias(const std::string &alias);
1538 :
1539 : /** Alias for GDALAlgorithmArgDecl::SetPositional() */
1540 : GDALInConstructionAlgorithmArg &SetPositional();
1541 :
1542 : /** Alias for GDALAlgorithmArgDecl::SetRequired() */
1543 1262 : GDALInConstructionAlgorithmArg &SetRequired()
1544 : {
1545 1262 : m_decl.SetRequired();
1546 1262 : return *this;
1547 : }
1548 :
1549 : /** Alias for GDALAlgorithmArgDecl::SetMetaVar() */
1550 4307 : GDALInConstructionAlgorithmArg &SetMetaVar(const std::string &metaVar)
1551 : {
1552 4307 : m_decl.SetMetaVar(metaVar);
1553 4307 : return *this;
1554 : }
1555 :
1556 : /** Alias for GDALAlgorithmArgDecl::SetCategory() */
1557 12032 : GDALInConstructionAlgorithmArg &SetCategory(const std::string &category)
1558 : {
1559 12032 : m_decl.SetCategory(category);
1560 12032 : return *this;
1561 : }
1562 :
1563 : /** Alias for GDALAlgorithmArgDecl::SetDefault() */
1564 : template <class T>
1565 1869 : GDALInConstructionAlgorithmArg &SetDefault(const T &value)
1566 : {
1567 1869 : m_decl.SetDefault(value);
1568 : if constexpr (!std::is_same_v<T, GDALArgDatasetValue> &&
1569 : !std::is_same_v<T, std::vector<GDALArgDatasetValue>>)
1570 : {
1571 1869 : if (m_decl.HasDefaultValue())
1572 1869 : *std::get<T *>(m_value) = value;
1573 : }
1574 1869 : return *this;
1575 : }
1576 :
1577 : /** Alias for GDALAlgorithmArgDecl::SetDefault() */
1578 227 : GDALInConstructionAlgorithmArg &SetDefault(const char *value)
1579 : {
1580 227 : return SetDefault(std::string(value));
1581 : }
1582 :
1583 : /** Alias for GDALAlgorithmArgDecl::SetMinCount() */
1584 648 : GDALInConstructionAlgorithmArg &SetMinCount(int count)
1585 : {
1586 648 : m_decl.SetMinCount(count);
1587 648 : return *this;
1588 : }
1589 :
1590 : /** Alias for GDALAlgorithmArgDecl::SetMaxCount() */
1591 378 : GDALInConstructionAlgorithmArg &SetMaxCount(int count)
1592 : {
1593 378 : m_decl.SetMaxCount(count);
1594 378 : return *this;
1595 : }
1596 :
1597 : /** Alias for GDALAlgorithmArgDecl::SetDisplayHintAboutRepetition() */
1598 : GDALInConstructionAlgorithmArg &
1599 268 : SetDisplayHintAboutRepetition(bool displayHint)
1600 : {
1601 268 : m_decl.SetDisplayHintAboutRepetition(displayHint);
1602 268 : return *this;
1603 : }
1604 :
1605 : /** Alias for GDALAlgorithmArgDecl::SetPackedValuesAllowed() */
1606 17 : GDALInConstructionAlgorithmArg &SetPackedValuesAllowed(bool allowed)
1607 : {
1608 17 : m_decl.SetPackedValuesAllowed(allowed);
1609 17 : return *this;
1610 : }
1611 :
1612 : /** Alias for GDALAlgorithmArgDecl::SetRepeatedArgAllowed() */
1613 513 : GDALInConstructionAlgorithmArg &SetRepeatedArgAllowed(bool allowed)
1614 : {
1615 513 : m_decl.SetRepeatedArgAllowed(allowed);
1616 513 : return *this;
1617 : }
1618 :
1619 : /** Alias for GDALAlgorithmArgDecl::SetChoices() */
1620 : template <typename T, typename... U>
1621 294 : GDALInConstructionAlgorithmArg &SetChoices(T &&first, U &&...rest)
1622 : {
1623 294 : m_decl.SetChoices(std::forward<T>(first), std::forward<U>(rest)...);
1624 294 : return *this;
1625 : }
1626 :
1627 : /** Alias for GDALAlgorithmArgDecl::SetHiddenChoices() */
1628 : template <typename T, typename... U>
1629 64 : GDALInConstructionAlgorithmArg &SetHiddenChoices(T &&first, U &&...rest)
1630 : {
1631 64 : m_decl.SetHiddenChoices(std::forward<T>(first),
1632 : std::forward<U>(rest)...);
1633 64 : return *this;
1634 : }
1635 :
1636 : /** Alias for GDALAlgorithmArgDecl::SetHidden() */
1637 1883 : GDALInConstructionAlgorithmArg &SetHidden()
1638 : {
1639 1883 : m_decl.SetHidden();
1640 1883 : return *this;
1641 : }
1642 :
1643 : /** Alias for GDALAlgorithmArgDecl::SetHiddenForCLI() */
1644 5205 : GDALInConstructionAlgorithmArg &SetHiddenForCLI(bool hiddenForCLI = true)
1645 : {
1646 5205 : m_decl.SetHiddenForCLI(hiddenForCLI);
1647 5205 : return *this;
1648 : }
1649 :
1650 : /** Alias for GDALAlgorithmArgDecl::SetOnlyForCLI() */
1651 9920 : GDALInConstructionAlgorithmArg &SetOnlyForCLI(bool onlyForCLI = true)
1652 : {
1653 9920 : m_decl.SetOnlyForCLI(onlyForCLI);
1654 9920 : return *this;
1655 : }
1656 :
1657 : /** Alias for GDALAlgorithmArgDecl::SetIsInput() */
1658 757 : GDALInConstructionAlgorithmArg &SetIsInput(bool isInput = true)
1659 : {
1660 757 : m_decl.SetIsInput(isInput);
1661 757 : return *this;
1662 : }
1663 :
1664 : /** Alias for GDALAlgorithmArgDecl::SetIsOutput() */
1665 757 : GDALInConstructionAlgorithmArg &SetIsOutput(bool isOutput = true)
1666 : {
1667 757 : m_decl.SetIsOutput(isOutput);
1668 757 : return *this;
1669 : }
1670 :
1671 : /** Alias for GDALAlgorithmArgDecl::SetReadFromFileAtSyntaxAllowed() */
1672 101 : GDALInConstructionAlgorithmArg &SetReadFromFileAtSyntaxAllowed()
1673 : {
1674 101 : m_decl.SetReadFromFileAtSyntaxAllowed();
1675 101 : return *this;
1676 : }
1677 :
1678 : /** Alias for GDALAlgorithmArgDecl::SetRemoveSQLCommentsEnabled() */
1679 101 : GDALInConstructionAlgorithmArg &SetRemoveSQLCommentsEnabled()
1680 : {
1681 101 : m_decl.SetRemoveSQLCommentsEnabled();
1682 101 : return *this;
1683 : }
1684 :
1685 : /** Alias for GDALAlgorithmArgDecl::SetAutoOpenDataset() */
1686 71 : GDALInConstructionAlgorithmArg &SetAutoOpenDataset(bool autoOpen)
1687 : {
1688 71 : m_decl.SetAutoOpenDataset(autoOpen);
1689 71 : return *this;
1690 : }
1691 :
1692 : /** Alias for GDALAlgorithmArgDecl::SetMutualExclusionGroup() */
1693 : GDALInConstructionAlgorithmArg &
1694 807 : SetMutualExclusionGroup(const std::string &group)
1695 : {
1696 807 : m_decl.SetMutualExclusionGroup(group);
1697 807 : return *this;
1698 : }
1699 :
1700 : /** Alias for GDALAlgorithmArgDecl::AddMetadataItem() */
1701 : GDALInConstructionAlgorithmArg &
1702 1280 : AddMetadataItem(const std::string &name,
1703 : const std::vector<std::string> &values)
1704 : {
1705 1280 : m_decl.AddMetadataItem(name, values);
1706 1280 : return *this;
1707 : }
1708 :
1709 : /** Register an action that is executed, once and exactly once, if the
1710 : * argument is explicitly set, at the latest by the ValidateArguments()
1711 : * method. */
1712 5650 : GDALInConstructionAlgorithmArg &AddAction(std::function<void()> f)
1713 : {
1714 5650 : m_actions.push_back(f);
1715 5650 : return *this;
1716 : }
1717 :
1718 : /** Register an action that is executed, once and exactly once, if the
1719 : * argument is explicitly set, at the latest by the ValidateArguments()
1720 : * method. If the provided function returns false, validation fails. */
1721 3138 : GDALInConstructionAlgorithmArg &AddValidationAction(std::function<bool()> f)
1722 : {
1723 3138 : m_validationActions.push_back(f);
1724 3138 : return *this;
1725 : }
1726 :
1727 : /** Register a function that will return a list of valid choices for
1728 : * the value of the argument. This is typically used for autocompletion.
1729 : */
1730 4159 : GDALInConstructionAlgorithmArg &SetAutoCompleteFunction(
1731 : std::function<std::vector<std::string>(const std::string &)> f)
1732 : {
1733 4159 : m_autoCompleteFunction = std::move(f);
1734 4159 : return *this;
1735 : }
1736 :
1737 : /** Register an action to validate that the argument value is a valid
1738 : * CRS definition.
1739 : * @param noneAllowed Set to true to mean that "null" or "none" are allowed
1740 : * to mean to unset CRS.
1741 : */
1742 : GDALInConstructionAlgorithmArg &SetIsCRSArg(bool noneAllowed = false);
1743 :
1744 : private:
1745 : GDALAlgorithm *const m_owner;
1746 :
1747 : GDALInConstructionAlgorithmArg(const GDALInConstructionAlgorithmArg &) =
1748 : delete;
1749 : GDALInConstructionAlgorithmArg &
1750 : operator=(const GDALInConstructionAlgorithmArg &) = delete;
1751 : };
1752 :
1753 : /************************************************************************/
1754 : /* GDALAlgorithmRegistry */
1755 : /************************************************************************/
1756 :
1757 : /** Registry of GDAL algorithms.
1758 : */
1759 3415 : class CPL_DLL GDALAlgorithmRegistry
1760 : {
1761 : public:
1762 : /** Special value to put in m_aliases to separate public alias from
1763 : * hidden aliases */
1764 : static constexpr const char *HIDDEN_ALIAS_SEPARATOR = "==hide==";
1765 :
1766 : virtual ~GDALAlgorithmRegistry();
1767 :
1768 : /** Algorithm information */
1769 : class AlgInfo
1770 : {
1771 : public:
1772 : /** Algorithm (short) name */
1773 : std::string m_name{};
1774 : /** Aliases */
1775 : std::vector<std::string> m_aliases{};
1776 : /** Creation function */
1777 : std::function<std::unique_ptr<GDALAlgorithm>()> m_creationFunc{};
1778 : };
1779 :
1780 : /** Register the algorithm of type MyAlgorithm.
1781 : */
1782 14859 : template <class MyAlgorithm> bool Register()
1783 : {
1784 29718 : AlgInfo info;
1785 14859 : info.m_name = MyAlgorithm::NAME;
1786 14859 : info.m_aliases = MyAlgorithm::GetAliases();
1787 16178 : info.m_creationFunc = []() -> std::unique_ptr<GDALAlgorithm>
1788 1355 : { return std::make_unique<MyAlgorithm>(); };
1789 29718 : return Register(info);
1790 : }
1791 :
1792 : /** Register an algorithm by its AlgInfo structure.
1793 : */
1794 : bool Register(const AlgInfo &info);
1795 :
1796 : /** Get the names of registered algorithms.
1797 : *
1798 : * This only returns the main name of each algorithm, not its potential
1799 : * alternate names.
1800 : */
1801 : std::vector<std::string> GetNames() const;
1802 :
1803 : /** Instantiate an algorithm by its name or one of its alias. */
1804 : virtual std::unique_ptr<GDALAlgorithm>
1805 : Instantiate(const std::string &name) const;
1806 :
1807 : /** Get an algorithm by its name. */
1808 442 : const AlgInfo *GetInfo(const std::string &name) const
1809 : {
1810 442 : auto iter = m_mapNameToInfo.find(name);
1811 442 : return iter != m_mapNameToInfo.end() ? &(iter->second) : nullptr;
1812 : }
1813 :
1814 : /** Returns true if there are no algorithms registered. */
1815 1058 : bool empty() const
1816 : {
1817 1058 : return m_mapNameToInfo.empty();
1818 : }
1819 :
1820 : private:
1821 : std::map<std::string, AlgInfo> m_mapNameToInfo{};
1822 : std::map<std::string, AlgInfo> m_mapAliasToInfo{};
1823 : std::map<std::string, AlgInfo> m_mapHiddenAliasToInfo{};
1824 : };
1825 :
1826 : /************************************************************************/
1827 : /* GDALAlgorithm */
1828 : /************************************************************************/
1829 :
1830 : /** GDAL algorithm.
1831 : *
1832 : * An algorithm declares its name, description, help URL.
1833 : * It also defined arguments or (mutual exclusion) sub-algorithms.
1834 : *
1835 : * It can be used from the command line with the ParseCommandLineArguments()
1836 : * method, or users can iterate over the available arguments with the GetArgs()
1837 : * or GetArg() method and fill them programmatically with
1838 : * GDALAlgorithmArg::Set().
1839 : *
1840 : * Execution of the algorithm is done with the Run() method.
1841 : *
1842 : * This is an abstract class. Implementations must sub-class it and implement the
1843 : * RunImpl() method.
1844 : */
1845 :
1846 1883 : /* abstract */ class CPL_DLL GDALAlgorithm
1847 : {
1848 : friend struct test_gdal_algorithm::test_gdal_algorithm;
1849 :
1850 : public:
1851 : virtual ~GDALAlgorithm();
1852 :
1853 : /** Get the algorithm name */
1854 966 : const std::string &GetName() const
1855 : {
1856 966 : return m_name;
1857 : }
1858 :
1859 : /** Get the algorithm description (a few sentences at most) */
1860 18 : const std::string &GetDescription() const
1861 : {
1862 18 : return m_description;
1863 : }
1864 :
1865 : /** Get the long algorithm description. May be empty. */
1866 2 : const std::string &GetLongDescription() const
1867 : {
1868 2 : return m_longDescription;
1869 : }
1870 :
1871 : /** Get the algorithm help URL. If starting with '/', it is relative to
1872 : * "https://gdal.org".
1873 : */
1874 : const std::string &GetHelpURL() const
1875 : {
1876 : return m_helpURL;
1877 : }
1878 :
1879 : /** Get the algorithm full URL, resolving relative URLs. */
1880 191 : const std::string &GetHelpFullURL() const
1881 : {
1882 191 : return m_helpFullURL;
1883 : }
1884 :
1885 : /** Returns whether this algorithm has sub-algorithms */
1886 1058 : bool HasSubAlgorithms() const
1887 : {
1888 1058 : return !m_subAlgRegistry.empty();
1889 : }
1890 :
1891 : /** Get the names of registered algorithms.
1892 : *
1893 : * This only returns the main name of each algorithm, not its potential
1894 : * alternate names.
1895 : */
1896 137 : std::vector<std::string> GetSubAlgorithmNames() const
1897 : {
1898 137 : return m_subAlgRegistry.GetNames();
1899 : }
1900 :
1901 : /** Instantiate an algorithm by its name (or its alias). */
1902 : std::unique_ptr<GDALAlgorithm>
1903 663 : InstantiateSubAlgorithm(const std::string &name) const
1904 : {
1905 663 : auto ret = m_subAlgRegistry.Instantiate(name);
1906 663 : if (ret)
1907 : {
1908 1260 : auto childCallPath = m_callPath;
1909 630 : childCallPath.push_back(name);
1910 630 : ret->SetCallPath(childCallPath);
1911 : }
1912 663 : return ret;
1913 : }
1914 :
1915 : /** Return the potential arguments of the algorithm. */
1916 : const std::vector<std::unique_ptr<GDALAlgorithmArg>> &GetArgs() const
1917 : {
1918 : return m_args;
1919 : }
1920 :
1921 : /** Return the potential arguments of the algorithm. */
1922 259 : std::vector<std::unique_ptr<GDALAlgorithmArg>> &GetArgs()
1923 : {
1924 259 : return m_args;
1925 : }
1926 :
1927 : /** Return an argument from its long name, short name or an alias */
1928 8596 : GDALAlgorithmArg *GetArg(const std::string &osName)
1929 : {
1930 : return const_cast<GDALAlgorithmArg *>(
1931 8596 : const_cast<const GDALAlgorithm *>(this)->GetArg(osName));
1932 : }
1933 :
1934 : /** Return an argument from its long name, short name or an alias */
1935 : const GDALAlgorithmArg *GetArg(const std::string &osName) const;
1936 :
1937 : /** Set the calling path to this algorithm.
1938 : *
1939 : * For example the main "gdal" CLI will set the path to the name of its
1940 : * binary before calling ParseCommandLineArguments().
1941 : */
1942 1169 : void SetCallPath(const std::vector<std::string> &path)
1943 : {
1944 1169 : m_callPath = path;
1945 1169 : }
1946 :
1947 : /** Set hint before calling ParseCommandLineArguments() that it must
1948 : * try to be be graceful when possible, e.g. accepting
1949 : * "gdal raster convert in.tif out.tif --co"
1950 : */
1951 29 : void SetParseForAutoCompletion()
1952 : {
1953 29 : m_parseForAutoCompletion = true;
1954 29 : }
1955 :
1956 : /** Set the reference file paths used to interpret relative paths.
1957 : *
1958 : * This has only effect if called before calling ParseCommandLineArguments().
1959 : */
1960 256 : void SetReferencePathForRelativePaths(const std::string &referencePath)
1961 : {
1962 256 : m_referencePath = referencePath;
1963 256 : }
1964 :
1965 : /** Return the reference file paths used to interpret relative paths. */
1966 211 : const std::string &GetReferencePathForRelativePaths() const
1967 : {
1968 211 : return m_referencePath;
1969 : }
1970 :
1971 : /** Returns whether this algorithm supports a streamed output dataset. */
1972 321 : bool SupportsStreamedOutput() const
1973 : {
1974 321 : return m_supportsStreamedOutput;
1975 : }
1976 :
1977 : /** Indicates that the algorithm must be run to generate a streamed output
1978 : * dataset. In particular, this must be used as a hint by algorithms to
1979 : * avoid writing files on the filesystem. This is used by the GDALG driver
1980 : * when executing a serialized algorithm command line.
1981 : *
1982 : * This has only effect if called before calling Run().
1983 : */
1984 15 : void SetExecutionForStreamedOutput()
1985 : {
1986 15 : m_executionForStreamOutput = true;
1987 15 : }
1988 :
1989 : /** Parse a command line argument, which does not include the algorithm
1990 : * name, to set the value of corresponding arguments.
1991 : */
1992 : virtual bool
1993 : ParseCommandLineArguments(const std::vector<std::string> &args);
1994 :
1995 : /** Validate that all constraints are met. This method is automatically
1996 : * executed by ParseCommandLineArguments() and Run(), and thus does
1997 : * generally not need to be explicitly called.
1998 : */
1999 : virtual bool ValidateArguments();
2000 :
2001 : /** Execute the algorithm, starting with ValidateArguments() and then
2002 : * calling RunImpl().
2003 : */
2004 : bool Run(GDALProgressFunc pfnProgress = nullptr,
2005 : void *pProgressData = nullptr);
2006 :
2007 : /** Complete any pending actions, and return the final status.
2008 : * This is typically useful for algorithm that generate an output dataset.
2009 : */
2010 : virtual bool Finalize();
2011 :
2012 : /** Usage options */
2013 : struct UsageOptions
2014 : {
2015 : /** Whether this is a pipeline step */
2016 : bool isPipelineStep;
2017 : /** Maximum width of the names of the options */
2018 : size_t maxOptLen;
2019 :
2020 55 : UsageOptions() : isPipelineStep(false), maxOptLen(0)
2021 : {
2022 55 : }
2023 : };
2024 :
2025 : /** Return the usage as a string appropriate for command-line interface
2026 : * \--help output.
2027 : */
2028 : virtual std::string
2029 : GetUsageForCLI(bool shortUsage,
2030 : const UsageOptions &usageOptions = UsageOptions()) const;
2031 :
2032 : /** Return the usage of the algorithm as a JSON-serialized string.
2033 : *
2034 : * This can be used to dynamically generate interfaces to algorithms.
2035 : */
2036 : virtual std::string GetUsageAsJSON() const;
2037 :
2038 : /** Return the actual algorithm that is going to be invoked, when the
2039 : * current algorithm has sub-algorithms.
2040 : *
2041 : * Only valid after ParseCommandLineArguments() has been called.
2042 : */
2043 247 : GDALAlgorithm &GetActualAlgorithm()
2044 : {
2045 247 : if (m_selectedSubAlg)
2046 92 : return m_selectedSubAlg->GetActualAlgorithm();
2047 155 : return *this;
2048 : }
2049 :
2050 : /** Whether the \--help flag has been specified. */
2051 4 : bool IsHelpRequested() const
2052 : {
2053 4 : return m_helpRequested;
2054 : }
2055 :
2056 : /** Whether the \--json-usage flag has been specified. */
2057 1 : bool IsJSONUsageRequested() const
2058 : {
2059 1 : return m_JSONUsageRequested;
2060 : }
2061 :
2062 : /** Whether the \--progress flag has been specified. */
2063 34 : bool IsProgressBarRequested() const
2064 : {
2065 34 : if (m_selectedSubAlg)
2066 20 : return m_selectedSubAlg->IsProgressBarRequested();
2067 14 : return m_progressBarRequested;
2068 : }
2069 :
2070 : /** Return alias names (generally short) for the current algorithm. */
2071 1 : const std::vector<std::string> &GetAliases() const
2072 : {
2073 1 : return m_aliases;
2074 : }
2075 :
2076 : /** Used by the "gdal info" special algorithm when it first tries to
2077 : * run "gdal raster info", to inherit from the potential special flags,
2078 : * such as \--help or \--json-usage, that this later algorithm has received.
2079 : */
2080 73 : bool PropagateSpecialActionTo(GDALAlgorithm *target)
2081 : {
2082 73 : target->m_progressBarRequested = m_progressBarRequested;
2083 73 : if (m_specialActionRequested)
2084 : {
2085 5 : target->m_specialActionRequested = m_specialActionRequested;
2086 5 : target->m_helpRequested = m_helpRequested;
2087 5 : target->m_helpDocRequested = m_helpDocRequested;
2088 5 : target->m_JSONUsageRequested = m_JSONUsageRequested;
2089 5 : return true;
2090 : }
2091 68 : return false;
2092 : }
2093 :
2094 : /** Return auto completion suggestions */
2095 : virtual std::vector<std::string>
2096 : GetAutoComplete(std::vector<std::string> &args, bool showAllOptions);
2097 :
2098 : protected:
2099 : friend class GDALInConstructionAlgorithmArg;
2100 :
2101 : /** Selected sub-algorithm. Set by ParseCommandLineArguments() when
2102 : * handling over on a sub-algorithm. */
2103 : GDALAlgorithm *m_selectedSubAlg = nullptr;
2104 :
2105 : /** Call path to the current algorithm. For example, for "gdal convert raster",
2106 : * it is ["gdal", "convert"]
2107 : */
2108 : std::vector<std::string> m_callPath{};
2109 :
2110 : /** Long description of the algorithm */
2111 : std::string m_longDescription{};
2112 :
2113 : /** Whether a progress bar is requested (value of \--progress argument) */
2114 : bool m_progressBarRequested = false;
2115 :
2116 : friend class GDALVectorPipelineAlgorithm;
2117 : /** Whether ValidateArguments() should be skipped during ParseCommandLineArguments() */
2118 : bool m_skipValidationInParseCommandLine = false;
2119 :
2120 : friend class GDALAlgorithmRegistry; // to set m_aliases
2121 : /** Algorithm alias names */
2122 : std::vector<std::string> m_aliases{};
2123 :
2124 : /** Whether this algorithm supports a streamed output dataset. */
2125 : bool m_supportsStreamedOutput = false;
2126 :
2127 : /** Whether this algorithm is run to generated a streamed output dataset. */
2128 : bool m_executionForStreamOutput = false;
2129 :
2130 : /** Constructor */
2131 : GDALAlgorithm(const std::string &name, const std::string &description,
2132 : const std::string &helpURL);
2133 :
2134 : /** Special processing for an argument of type GAAT_DATASET */
2135 : bool ProcessDatasetArg(GDALAlgorithmArg *arg, GDALAlgorithm *algForOutput);
2136 :
2137 : /** Register the sub-algorithm of type MyAlgorithm.
2138 : */
2139 6658 : template <class MyAlgorithm> bool RegisterSubAlgorithm()
2140 : {
2141 6658 : return m_subAlgRegistry.Register<MyAlgorithm>();
2142 : }
2143 :
2144 : /** Register a sub-algoritm by its AlgInfo structure.
2145 : */
2146 445 : bool RegisterSubAlgorithm(const GDALAlgorithmRegistry::AlgInfo &info)
2147 : {
2148 445 : return m_subAlgRegistry.Register(info);
2149 : }
2150 :
2151 : /** Add boolean argument. */
2152 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2153 : char chShortName,
2154 : const std::string &helpMessage,
2155 : bool *pValue);
2156 :
2157 : /** Add string argument. */
2158 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2159 : char chShortName,
2160 : const std::string &helpMessage,
2161 : std::string *pValue);
2162 :
2163 : /** Add integer argument. */
2164 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2165 : char chShortName,
2166 : const std::string &helpMessage,
2167 : int *pValue);
2168 :
2169 : /** Add real argument. */
2170 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2171 : char chShortName,
2172 : const std::string &helpMessage,
2173 : double *pValue);
2174 :
2175 : /** Add dataset argument. */
2176 : GDALInConstructionAlgorithmArg &
2177 : AddArg(const std::string &longName, char chShortName,
2178 : const std::string &helpMessage, GDALArgDatasetValue *pValue,
2179 : GDALArgDatasetValueType type = GDAL_OF_RASTER | GDAL_OF_VECTOR |
2180 : GDAL_OF_MULTIDIM_RASTER);
2181 :
2182 : /** Add list of string argument. */
2183 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2184 : char chShortName,
2185 : const std::string &helpMessage,
2186 : std::vector<std::string> *pValue);
2187 :
2188 : /** Add list of integer argument. */
2189 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2190 : char chShortName,
2191 : const std::string &helpMessage,
2192 : std::vector<int> *pValue);
2193 :
2194 : /** Add list of real argument. */
2195 : GDALInConstructionAlgorithmArg &AddArg(const std::string &longName,
2196 : char chShortName,
2197 : const std::string &helpMessage,
2198 : std::vector<double> *pValue);
2199 :
2200 : /** Add list of dataset argument. */
2201 : GDALInConstructionAlgorithmArg &
2202 : AddArg(const std::string &longName, char chShortName,
2203 : const std::string &helpMessage,
2204 : std::vector<GDALArgDatasetValue> *pValue,
2205 : GDALArgDatasetValueType type = GDAL_OF_RASTER | GDAL_OF_VECTOR |
2206 : GDAL_OF_MULTIDIM_RASTER);
2207 :
2208 : /** Add input dataset argument. */
2209 : GDALInConstructionAlgorithmArg &
2210 : AddInputDatasetArg(GDALArgDatasetValue *pValue,
2211 : GDALArgDatasetValueType type = GDAL_OF_RASTER |
2212 : GDAL_OF_VECTOR |
2213 : GDAL_OF_MULTIDIM_RASTER,
2214 : bool positionalAndRequired = true);
2215 :
2216 : /** Add input dataset argument. */
2217 : GDALInConstructionAlgorithmArg &
2218 : AddInputDatasetArg(std::vector<GDALArgDatasetValue> *pValue,
2219 : GDALArgDatasetValueType type = GDAL_OF_RASTER |
2220 : GDAL_OF_VECTOR |
2221 : GDAL_OF_MULTIDIM_RASTER,
2222 : bool positionalAndRequired = true);
2223 :
2224 : /** Add open option(s) argument. */
2225 : GDALInConstructionAlgorithmArg &
2226 : AddOpenOptionsArg(std::vector<std::string> *pValue);
2227 :
2228 : /** Add input format(s) argument. */
2229 : GDALInConstructionAlgorithmArg &
2230 : AddInputFormatsArg(std::vector<std::string> *pValue);
2231 :
2232 : /** Add output dataset argument. */
2233 : GDALInConstructionAlgorithmArg &
2234 : AddOutputDatasetArg(GDALArgDatasetValue *pValue,
2235 : GDALArgDatasetValueType type = GDAL_OF_RASTER |
2236 : GDAL_OF_VECTOR |
2237 : GDAL_OF_MULTIDIM_RASTER,
2238 : bool positionalAndRequired = true);
2239 :
2240 : /** Add \--overwrite argument. */
2241 : GDALInConstructionAlgorithmArg &AddOverwriteArg(bool *pValue);
2242 :
2243 : /** Add \--update argument. */
2244 : GDALInConstructionAlgorithmArg &AddUpdateArg(bool *pValue);
2245 :
2246 : /** Add (non-CLI) output-string argument. */
2247 : GDALInConstructionAlgorithmArg &AddOutputStringArg(std::string *pValue);
2248 :
2249 : /** Add output format argument. */
2250 : GDALInConstructionAlgorithmArg &
2251 : AddOutputFormatArg(std::string *pValue, bool bStreamAllowed = false,
2252 : bool bGDALGAllowed = false);
2253 :
2254 : /** Add output data type argument. */
2255 : GDALInConstructionAlgorithmArg &AddOutputDataTypeArg(std::string *pValue);
2256 :
2257 : /** Add creation option(s) argument. */
2258 : GDALInConstructionAlgorithmArg &
2259 : AddCreationOptionsArg(std::vector<std::string> *pValue);
2260 :
2261 : /** Add layer creation option(s) argument. */
2262 : GDALInConstructionAlgorithmArg &
2263 : AddLayerCreationOptionsArg(std::vector<std::string> *pValue);
2264 :
2265 : /** Add (single) layer name argument. */
2266 : GDALInConstructionAlgorithmArg &AddLayerNameArg(std::string *pValue);
2267 :
2268 : /** Add (potentially multiple) layer name(s) argument. */
2269 : GDALInConstructionAlgorithmArg &
2270 : AddLayerNameArg(std::vector<std::string> *pValue);
2271 :
2272 : /** Add bbox=xmin,ymin,xmax,ymax argument. */
2273 : GDALInConstructionAlgorithmArg &
2274 : AddBBOXArg(std::vector<double> *pValue, const char *helpMessage = nullptr);
2275 :
2276 : /** Add active layer argument. */
2277 : GDALInConstructionAlgorithmArg &AddActiveLayerArg(std::string *pValue);
2278 :
2279 : /** Add \--progress argument. */
2280 : GDALInConstructionAlgorithmArg &AddProgressArg();
2281 :
2282 : /** Validation function to use for key=value type of arguments. */
2283 : bool ValidateKeyValue(const GDALAlgorithmArg &arg) const;
2284 :
2285 : /** Return whether output-format or output arguments express GDALG output */
2286 : bool IsGDALGOutput() const;
2287 :
2288 : /** Return value for ProcessGDALGOutput */
2289 : enum class ProcessGDALGOutputRet
2290 : {
2291 : /** GDALG output requested and successful. */
2292 : GDALG_OK,
2293 : /** GDALG output requested but an error has occurred. */
2294 : GDALG_ERROR,
2295 : /** GDALG output not requeste. RunImpl() must be run. */
2296 : NOT_GDALG,
2297 : };
2298 :
2299 : /** Process output to a .gdalg file */
2300 : virtual ProcessGDALGOutputRet ProcessGDALGOutput();
2301 :
2302 : /** Method executed by Run() when m_executionForStreamOutput is set to
2303 : * ensure the command is safe to execute in a streamed dataset context.
2304 : */
2305 : virtual bool CheckSafeForStreamOutput();
2306 :
2307 : //! @cond Doxygen_Suppress
2308 : void AddAliasFor(GDALInConstructionAlgorithmArg *arg,
2309 : const std::string &alias);
2310 : void SetPositional(GDALInConstructionAlgorithmArg *arg);
2311 :
2312 : //! @endcond
2313 :
2314 : /** Set whether this algorithm should be reported in JSON usage. */
2315 125 : void SetDisplayInJSONUsage(bool b)
2316 : {
2317 125 : m_displayInJSONUsage = b;
2318 125 : }
2319 :
2320 : //! @cond Doxygen_Suppress
2321 : void ReportError(CPLErr eErrClass, CPLErrorNum err_no, const char *fmt,
2322 : ...) const CPL_PRINT_FUNC_FORMAT(4, 5);
2323 : //! @endcond
2324 :
2325 : /** Return the list of arguments for CLI usage */
2326 : std::pair<std::vector<std::pair<GDALAlgorithmArg *, std::string>>, size_t>
2327 : GetArgNamesForCLI() const;
2328 :
2329 : private:
2330 : const std::string m_name{};
2331 : const std::string m_description{};
2332 : const std::string m_helpURL{};
2333 : const std::string m_helpFullURL{};
2334 : bool m_parsedSubStringAlreadyCalled = false;
2335 : bool m_displayInJSONUsage = true;
2336 : bool m_specialActionRequested = false;
2337 : bool m_helpRequested = false;
2338 :
2339 : // Used by program-output directives in .rst files
2340 : bool m_helpDocRequested = false;
2341 :
2342 : bool m_JSONUsageRequested = false;
2343 : bool m_dummyBoolean = false; // Used for --version
2344 : bool m_parseForAutoCompletion = false;
2345 : std::string m_referencePath{};
2346 : std::vector<std::string> m_dummyConfigOptions{};
2347 : std::vector<std::unique_ptr<GDALAlgorithmArg>> m_args{};
2348 : std::map<std::string, GDALAlgorithmArg *> m_mapLongNameToArg{};
2349 : std::map<std::string, GDALAlgorithmArg *> m_mapShortNameToArg{};
2350 : std::vector<GDALAlgorithmArg *> m_positionalArgs{};
2351 : GDALAlgorithmRegistry m_subAlgRegistry{};
2352 : std::unique_ptr<GDALAlgorithm> m_selectedSubAlgHolder{};
2353 : std::function<std::vector<std::string>(const std::vector<std::string> &)>
2354 : m_autoCompleteFunction{};
2355 :
2356 : GDALInConstructionAlgorithmArg &
2357 : AddArg(std::unique_ptr<GDALInConstructionAlgorithmArg> arg);
2358 : bool ParseArgument(
2359 : GDALAlgorithmArg *arg, const std::string &name,
2360 : const std::string &value,
2361 : std::map<
2362 : GDALAlgorithmArg *,
2363 : std::variant<std::vector<std::string>, std::vector<int>,
2364 : std::vector<double>, std::vector<GDALArgDatasetValue>>>
2365 : &inConstructionValues);
2366 :
2367 : bool ValidateFormat(const GDALAlgorithmArg &arg, bool bStreamAllowed,
2368 : bool bGDALGAllowed) const;
2369 :
2370 : virtual bool RunImpl(GDALProgressFunc pfnProgress, void *pProgressData) = 0;
2371 :
2372 : /** Extract the last option and its potential value from the provided
2373 : * argument list, and remove them from the list.
2374 : */
2375 : void ExtractLastOptionAndValue(std::vector<std::string> &args,
2376 : std::string &option,
2377 : std::string &value) const;
2378 :
2379 : GDALAlgorithm(const GDALAlgorithm &) = delete;
2380 : GDALAlgorithm &operator=(const GDALAlgorithm &) = delete;
2381 : };
2382 :
2383 : //! @cond Doxygen_Suppress
2384 : struct GDALAlgorithmHS
2385 : {
2386 : private:
2387 : std::unique_ptr<GDALAlgorithm> uniquePtr{};
2388 :
2389 : GDALAlgorithmHS(const GDALAlgorithmHS &) = delete;
2390 : GDALAlgorithmHS &operator=(const GDALAlgorithmHS &) = delete;
2391 :
2392 : public:
2393 : GDALAlgorithm *ptr = nullptr;
2394 :
2395 106 : GDALAlgorithmHS() = default;
2396 :
2397 764 : explicit GDALAlgorithmHS(std::unique_ptr<GDALAlgorithm> alg)
2398 764 : : uniquePtr(std::move(alg)), ptr(uniquePtr.get())
2399 : {
2400 764 : }
2401 :
2402 106 : static std::unique_ptr<GDALAlgorithmHS> FromRef(GDALAlgorithm &alg)
2403 : {
2404 106 : auto ret = std::make_unique<GDALAlgorithmHS>();
2405 106 : ret->ptr = &alg;
2406 106 : return ret;
2407 : }
2408 : };
2409 :
2410 : //! @endcond
2411 :
2412 : /************************************************************************/
2413 : /* GDALGlobalAlgorithmRegistry */
2414 : /************************************************************************/
2415 :
2416 : /** Global registry of GDAL algorithms.
2417 : */
2418 : class CPL_DLL GDALGlobalAlgorithmRegistry final : public GDALAlgorithmRegistry
2419 : {
2420 : public:
2421 : /** Name of the root "gdal" algorithm. */
2422 : static constexpr const char *ROOT_ALG_NAME = "gdal";
2423 :
2424 : /** Get the singleton */
2425 : static GDALGlobalAlgorithmRegistry &GetSingleton();
2426 :
2427 : /** Instantiate an algorithm by its name or one of its alias. */
2428 : std::unique_ptr<GDALAlgorithm>
2429 : Instantiate(const std::string &name) const override;
2430 : };
2431 :
2432 : /************************************************************************/
2433 : /* GDAL_STATIC_REGISTER_ALG() */
2434 : /************************************************************************/
2435 :
2436 : /** Static registration of an algorithm by its class name (which must implement
2437 : * GDALAlgorithm)
2438 : */
2439 : #define GDAL_STATIC_REGISTER_ALG(MyAlgorithm) \
2440 : static bool MyAlgorithm##_static_registration = \
2441 : GDALGlobalAlgorithmRegistry::GetSingleton().Register<MyAlgorithm>()
2442 :
2443 : #endif // #if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS) && (defined(DOXYGEN_SKIP) || __cplusplus >= 201703L || _MSC_VER >= 1920)
2444 :
2445 : #endif // GDAL_ALGORITHM_INCLUDED
|