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 : #include "gdalalgorithm.h" 14 : #include "gdalalg_main.h" 15 : #include "gdalalg_raster.h" 16 : #include "gdalalg_vector.h" 17 : #include "gdalalg_dataset.h" 18 : #include "gdalalg_mdim.h" 19 : #include "gdalalg_convert.h" 20 : #include "gdalalg_info.h" 21 : #include "gdalalg_pipeline.h" 22 : #include "gdalalg_vsi.h" 23 : 24 : #include "cpl_vsi.h" 25 : 26 : #include "gdal_priv.h" 27 : 28 : #include <cassert> 29 : 30 : /************************************************************************/ 31 : /* GDALAlgorithmRegistry::~GDALAlgorithmRegistry() */ 32 : /************************************************************************/ 33 : 34 : GDALAlgorithmRegistry::~GDALAlgorithmRegistry() = default; 35 : 36 : /************************************************************************/ 37 : /* GDALAlgorithmRegistry::Register() */ 38 : /************************************************************************/ 39 : 40 137541 : bool GDALAlgorithmRegistry::Register(const GDALAlgorithmRegistry::AlgInfo &info) 41 : { 42 137541 : if (cpl::contains(m_mapNameToInfo, info.m_name)) 43 : { 44 1 : CPLError(CE_Failure, CPLE_AppDefined, 45 : "GDAL algorithm '%s' already registered!", 46 : info.m_name.c_str()); 47 1 : return false; 48 : } 49 168679 : for (const std::string &alias : info.m_aliases) 50 : { 51 62281 : if (cpl::contains(m_mapAliasToInfo, alias) || 52 31140 : cpl::contains(m_mapHiddenAliasToInfo, alias)) 53 : { 54 2 : CPLError(CE_Failure, CPLE_AppDefined, 55 : "An algorithm with alias '%s' is already registered!", 56 : alias.c_str()); 57 2 : return false; 58 : } 59 : } 60 137538 : m_mapNameToInfo[info.m_name] = info; 61 137538 : bool hidden = false; 62 168676 : for (const std::string &alias : info.m_aliases) 63 : { 64 31138 : if (alias == HIDDEN_ALIAS_SEPARATOR) 65 11785 : hidden = true; 66 19353 : else if (hidden) 67 16143 : m_mapAliasToInfo[alias] = info; 68 : else 69 3210 : m_mapHiddenAliasToInfo[alias] = info; 70 : } 71 137538 : return true; 72 : } 73 : 74 : /************************************************************************/ 75 : /* GDALAlgorithmRegistry::InstantiateTopLevel() */ 76 : /************************************************************************/ 77 : 78 : std::unique_ptr<GDALAlgorithm> 79 10082 : GDALAlgorithmRegistry::InstantiateTopLevel(const std::string &name) const 80 : { 81 10082 : auto iter = m_mapNameToInfo.find(name); 82 10082 : if (iter == m_mapNameToInfo.end()) 83 : { 84 599 : iter = m_mapAliasToInfo.find(name); 85 599 : if (iter == m_mapAliasToInfo.end()) 86 : { 87 593 : iter = m_mapHiddenAliasToInfo.find(name); 88 593 : if (iter == m_mapHiddenAliasToInfo.end()) 89 : { 90 593 : return nullptr; 91 : } 92 : } 93 : } 94 18978 : auto alg = iter->second.m_creationFunc(); 95 9489 : alg->m_aliases = iter->second.m_aliases; 96 9489 : return alg; 97 : } 98 : 99 : /************************************************************************/ 100 : /* GDALAlgorithmRegistry::Instantiate() */ 101 : /************************************************************************/ 102 : 103 : std::unique_ptr<GDALAlgorithm> 104 3515 : GDALAlgorithmRegistry::Instantiate(const std::vector<std::string> &path) const 105 : { 106 3515 : if (path.empty()) 107 1 : return nullptr; 108 7028 : auto alg = Instantiate(path[0]); 109 3531 : for (size_t i = 1; i < path.size() && alg; ++i) 110 : { 111 17 : alg = alg->InstantiateSubAlgorithm(path[i]); 112 : } 113 3514 : return alg; 114 : } 115 : 116 : /************************************************************************/ 117 : /* GDALAlgorithmRegistry::GetNames() */ 118 : /************************************************************************/ 119 : 120 1077 : std::vector<std::string> GDALAlgorithmRegistry::GetNames() const 121 : { 122 1077 : std::vector<std::string> res; 123 7910 : for (const auto &iter : m_mapNameToInfo) 124 : { 125 6833 : res.push_back(iter.first); 126 : } 127 1077 : return res; 128 : } 129 : 130 : /************************************************************************/ 131 : /* GDALAlgorithmRegistry::Instantiate() */ 132 : /************************************************************************/ 133 : 134 : std::unique_ptr<GDALAlgorithm> 135 10449 : GDALAlgorithmRegistry::Instantiate(const std::string &name) const 136 : { 137 10449 : return InstantiateTopLevel(name); 138 : } 139 : 140 : std::unique_ptr<GDALAlgorithm> 141 3513 : GDALAlgorithmRegistry::InstantiateInternal(std::vector<std::string> &path) 142 : { 143 3513 : return Instantiate(path); 144 : } 145 : 146 : /************************************************************************/ 147 : /* GDALGlobalAlgorithmRegistry::GDALGlobalAlgorithmRegistry() */ 148 : /************************************************************************/ 149 : 150 1585 : GDALGlobalAlgorithmRegistry::GDALGlobalAlgorithmRegistry() 151 : { 152 1585 : Register<GDALRasterAlgorithm>(); 153 1585 : Register<GDALVectorAlgorithm>(); 154 1585 : Register<GDALDatasetAlgorithm>(); 155 1585 : Register<GDALMdimAlgorithm>(); 156 1585 : Register<GDALConvertAlgorithm>(); 157 1585 : Register<GDALInfoAlgorithm>(); 158 1585 : Register<GDALPipelineAlgorithm>(); 159 1585 : Register<GDALVSIAlgorithm>(); 160 1585 : } 161 : 162 : GDALGlobalAlgorithmRegistry::~GDALGlobalAlgorithmRegistry() = default; 163 : 164 : /************************************************************************/ 165 : /* GDALGlobalAlgorithmRegistry::GetSingleton() */ 166 : /************************************************************************/ 167 : 168 : /* static */ GDALGlobalAlgorithmRegistry & 169 19918 : GDALGlobalAlgorithmRegistry::GetSingleton() 170 : { 171 19918 : static GDALGlobalAlgorithmRegistry singleton; 172 19918 : return singleton; 173 : } 174 : 175 : /************************************************************************/ 176 : /* GDALGlobalAlgorithmRegistry::InstantiateTopLevel() */ 177 : /************************************************************************/ 178 : 179 : std::unique_ptr<GDALAlgorithm> 180 2660 : GDALGlobalAlgorithmRegistry::InstantiateTopLevel(const std::string &name) const 181 : { 182 2660 : if (name == GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME) 183 367 : return std::make_unique<GDALMainAlgorithm>(); 184 4586 : auto alg = GDALAlgorithmRegistry::InstantiateTopLevel(name); 185 2293 : if (!alg) 186 : { 187 172 : alg = InstantiateDeclaredSubAlgorithm( 188 129 : {GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME, name}); 189 : } 190 2293 : if (alg) 191 : { 192 6861 : alg->SetCallPath({GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME, name}); 193 : } 194 2293 : return alg; 195 : } 196 : 197 : /************************************************************************/ 198 : /* GDALGlobalAlgorithmRegistry::DeclareAlgorithm() */ 199 : /************************************************************************/ 200 : 201 18382 : void GDALGlobalAlgorithmRegistry::DeclareAlgorithm( 202 : const std::vector<std::string> &path, InstantiateFunc instantiateFunc) 203 : { 204 18382 : Node *curNode = &m_root; 205 62501 : for (size_t i = 0; i < path.size(); ++i) 206 : { 207 44119 : const std::string &name = path[i]; 208 44119 : auto iter = curNode->children.find(name); 209 44119 : if (iter == curNode->children.end()) 210 : { 211 17327 : Node newNode; 212 17327 : if (i + 1 == path.size()) 213 : { 214 17326 : newNode.instantiateFunc = instantiateFunc; 215 : } 216 : else 217 : { 218 : newNode.instantiateFunc = 219 4 : [name]() -> std::unique_ptr<GDALAlgorithm> 220 : { 221 4 : return std::make_unique<GDALContainerAlgorithm>( 222 8 : name, std::string("Command for ").append(name)); 223 1 : }; 224 : } 225 17327 : curNode = 226 34654 : &(curNode->children.insert(std::pair(name, std::move(newNode))) 227 17327 : .first->second); 228 : } 229 : else 230 : { 231 26792 : curNode = &(iter->second); 232 : } 233 : } 234 18382 : } 235 : 236 : /************************************************************************/ 237 : /* GDALGlobalAlgorithmRegistry::GetNodeFromPath() */ 238 : /************************************************************************/ 239 : 240 : const GDALGlobalAlgorithmRegistry::Node * 241 22941 : GDALGlobalAlgorithmRegistry::GetNodeFromPath( 242 : const std::vector<std::string> &path) const 243 : { 244 22941 : if (!path.empty()) 245 : { 246 22226 : const Node *curNode = &m_root; 247 22226 : bool first = true; 248 42884 : for (const std::string &name : path) 249 : { 250 34089 : if (first && name == GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME) 251 : { 252 2569 : first = false; 253 2569 : continue; 254 : } 255 31520 : first = false; 256 31520 : auto iter = curNode->children.find(name); 257 31520 : if (iter == curNode->children.end()) 258 13431 : return nullptr; 259 18089 : curNode = &(iter->second); 260 : } 261 8795 : return curNode; 262 : } 263 715 : return nullptr; 264 : } 265 : 266 : /************************************************************************/ 267 : /* GDALGlobalAlgorithmRegistry::GetDeclaredSubAlgorithmNames() */ 268 : /************************************************************************/ 269 : 270 : std::vector<std::string> 271 4767 : GDALGlobalAlgorithmRegistry::GetDeclaredSubAlgorithmNames( 272 : const std::vector<std::string> &path) const 273 : { 274 4767 : const GDALGlobalAlgorithmRegistry::Node *node = GetNodeFromPath(path); 275 4767 : std::vector<std::string> ret; 276 4767 : if (node) 277 : { 278 561 : for (const auto &[name, subnode] : node->children) 279 : { 280 : // If there is an instantiation function, run it, to avoid 281 : // reporting algorithms that might be in drivers built as 282 : // deferred loaded plugins, but not available at runtime. 283 355 : if (!subnode.instantiateFunc || subnode.instantiateFunc()) 284 : { 285 355 : ret.push_back(name); 286 : } 287 : } 288 : } 289 4767 : return ret; 290 : } 291 : 292 : /************************************************************************/ 293 : /* GDALGlobalAlgorithmRegistry::HasDeclaredSubAlgorithm() */ 294 : /************************************************************************/ 295 : 296 17860 : bool GDALGlobalAlgorithmRegistry::HasDeclaredSubAlgorithm( 297 : const std::vector<std::string> &path) const 298 : { 299 17860 : return GetNodeFromPath(path) != nullptr; 300 : } 301 : 302 : /************************************************************************/ 303 : /* GDALGlobalAlgorithmRegistry::InstantiateDeclaredSubAlgorithm() */ 304 : /************************************************************************/ 305 : 306 : std::unique_ptr<GDALAlgorithm> 307 314 : GDALGlobalAlgorithmRegistry::InstantiateDeclaredSubAlgorithm( 308 : const std::vector<std::string> &path) const 309 : { 310 314 : const GDALGlobalAlgorithmRegistry::Node *node = GetNodeFromPath(path); 311 314 : if (node && node->instantiateFunc) 312 : { 313 358 : auto alg = node->instantiateFunc(); 314 179 : if (alg) 315 : { 316 358 : auto callPath = path; 317 179 : if (path[0] != GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME) 318 0 : callPath.insert(callPath.begin(), 319 0 : GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME); 320 179 : alg->SetCallPath(callPath); 321 : } 322 179 : return alg; 323 : } 324 135 : return nullptr; 325 : } 326 : 327 : /************************************************************************/ 328 : /* struct GDALAlgorithmRegistryHS */ 329 : /************************************************************************/ 330 : 331 : struct GDALAlgorithmRegistryHS 332 : { 333 : GDALAlgorithmRegistry *ptr = nullptr; 334 : }; 335 : 336 : /************************************************************************/ 337 : /* GDALGetGlobalAlgorithmRegistry() */ 338 : /************************************************************************/ 339 : 340 : /** Gets a handle to the GDALGetGlobalAlgorithmRegistry which references 341 : * all available top-level GDAL algorithms ("raster", "vector", etc.) 342 : * 343 : * The handle must be released with GDALAlgorithmRegistryRelease() (but 344 : * this does not destroy the GDALAlgorithmRegistryRelease singleton). 345 : * 346 : * @since 3.11 347 : */ 348 2273 : GDALAlgorithmRegistryH GDALGetGlobalAlgorithmRegistry() 349 : { 350 4546 : auto ret = std::make_unique<GDALAlgorithmRegistryHS>(); 351 2273 : ret->ptr = &(GDALGlobalAlgorithmRegistry::GetSingleton()); 352 4546 : return ret.release(); 353 : } 354 : 355 : /************************************************************************/ 356 : /* GDALAlgorithmRegistryRelease() */ 357 : /************************************************************************/ 358 : 359 : /** Release a handle to an algorithm registry, but this does not destroy the 360 : * registry itself. 361 : * 362 : * @since 3.11 363 : */ 364 2273 : void GDALAlgorithmRegistryRelease(GDALAlgorithmRegistryH hReg) 365 : { 366 2273 : delete hReg; 367 2273 : } 368 : 369 : /************************************************************************/ 370 : /* GDALAlgorithmRegistryGetAlgNames() */ 371 : /************************************************************************/ 372 : 373 : /** Return the names of the algorithms registered in the registry passed as 374 : * parameter. 375 : * 376 : * @param hReg Handle to a registry. Must NOT be null. 377 : * @return a NULL terminated list of names, which must be destroyed with 378 : * CSLDestroy() 379 : * 380 : * @since 3.11 381 : */ 382 2 : char **GDALAlgorithmRegistryGetAlgNames(GDALAlgorithmRegistryH hReg) 383 : { 384 2 : VALIDATE_POINTER1(hReg, __func__, nullptr); 385 2 : return CPLStringList(hReg->ptr->GetNames()).StealList(); 386 : } 387 : 388 : /************************************************************************/ 389 : /* GDALAlgorithmRegistryInstantiateAlg() */ 390 : /************************************************************************/ 391 : 392 : /** Instantiate an algorithm available in a registry from its name. 393 : * 394 : * @param hReg Handle to a registry. Must NOT be null. 395 : * @param pszAlgName Algorithm name. Must NOT be null. 396 : * @return an handle to the algorithm (to be freed with GDALAlgorithmRelease), 397 : * or NULL if the algorithm does not exist or another error occurred. 398 : * 399 : * @since 3.11 400 : */ 401 2275 : GDALAlgorithmH GDALAlgorithmRegistryInstantiateAlg(GDALAlgorithmRegistryH hReg, 402 : const char *pszAlgName) 403 : { 404 2275 : VALIDATE_POINTER1(hReg, __func__, nullptr); 405 2275 : VALIDATE_POINTER1(pszAlgName, __func__, nullptr); 406 4550 : auto alg = hReg->ptr->Instantiate(pszAlgName); 407 4550 : return alg ? std::make_unique<GDALAlgorithmHS>(std::move(alg)).release() 408 4550 : : nullptr; 409 : } 410 : 411 : /************************************************************************/ 412 : /* GDALAlgorithmRegistryInstantiateAlgFromPath() */ 413 : /************************************************************************/ 414 : 415 : /** Instantiate an algorithm available in a registry from its path. 416 : * 417 : * @param hReg Handle to a registry. Must NOT be null. 418 : * @param papszAlgPath Algorithm path. Must NOT be null. 419 : * @return an handle to the algorithm (to be freed with GDALAlgorithmRelease), 420 : * or NULL if the algorithm does not exist or another error occurred. 421 : * 422 : * @since 3.12 423 : */ 424 : GDALAlgorithmH 425 1 : GDALAlgorithmRegistryInstantiateAlgFromPath(GDALAlgorithmRegistryH hReg, 426 : const char *const *papszAlgPath) 427 : { 428 1 : VALIDATE_POINTER1(hReg, __func__, nullptr); 429 1 : VALIDATE_POINTER1(papszAlgPath, __func__, nullptr); 430 1 : auto alg = hReg->ptr->Instantiate( 431 2 : static_cast<std::vector<std::string>>(CPLStringList(papszAlgPath))); 432 2 : return alg ? std::make_unique<GDALAlgorithmHS>(std::move(alg)).release() 433 2 : : nullptr; 434 : }