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