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 : 16 : #include "cpl_vsi.h" 17 : 18 : #include "gdal_priv.h" 19 : 20 : #include <cassert> 21 : 22 : /************************************************************************/ 23 : /* GDALAlgorithmRegistry::~GDALAlgorithmRegistry() */ 24 : /************************************************************************/ 25 : 26 : GDALAlgorithmRegistry::~GDALAlgorithmRegistry() = default; 27 : 28 : /************************************************************************/ 29 : /* GDALAlgorithmRegistry::Register() */ 30 : /************************************************************************/ 31 : 32 67785 : bool GDALAlgorithmRegistry::Register(const GDALAlgorithmRegistry::AlgInfo &info) 33 : { 34 67785 : if (cpl::contains(m_mapNameToInfo, info.m_name)) 35 : { 36 1 : CPLError(CE_Failure, CPLE_AppDefined, 37 : "GDAL algorithm '%s' already registered!", 38 : info.m_name.c_str()); 39 1 : return false; 40 : } 41 74291 : for (const std::string &alias : info.m_aliases) 42 : { 43 13017 : if (cpl::contains(m_mapAliasToInfo, alias) || 44 6508 : cpl::contains(m_mapHiddenAliasToInfo, alias)) 45 : { 46 2 : CPLError(CE_Failure, CPLE_AppDefined, 47 : "An algorithm with alias '%s' is already registered!", 48 : alias.c_str()); 49 2 : return false; 50 : } 51 : } 52 67782 : m_mapNameToInfo[info.m_name] = info; 53 67782 : bool hidden = false; 54 74288 : for (const std::string &alias : info.m_aliases) 55 : { 56 6506 : if (alias == HIDDEN_ALIAS_SEPARATOR) 57 2079 : hidden = true; 58 4427 : else if (hidden) 59 3537 : m_mapAliasToInfo[alias] = info; 60 : else 61 890 : m_mapHiddenAliasToInfo[alias] = info; 62 : } 63 67782 : return true; 64 : } 65 : 66 : /************************************************************************/ 67 : /* GDALAlgorithmRegistry::Instantiate() */ 68 : /************************************************************************/ 69 : 70 : std::unique_ptr<GDALAlgorithm> 71 4396 : GDALAlgorithmRegistry::Instantiate(const std::string &name) const 72 : { 73 4396 : auto iter = m_mapNameToInfo.find(name); 74 4396 : if (iter == m_mapNameToInfo.end()) 75 : { 76 181 : iter = m_mapAliasToInfo.find(name); 77 181 : if (iter == m_mapAliasToInfo.end()) 78 : { 79 175 : iter = m_mapHiddenAliasToInfo.find(name); 80 175 : if (iter == m_mapHiddenAliasToInfo.end()) 81 : { 82 175 : return nullptr; 83 : } 84 : } 85 : } 86 8442 : auto alg = iter->second.m_creationFunc(); 87 4221 : alg->m_aliases = iter->second.m_aliases; 88 4221 : return alg; 89 : } 90 : 91 : /************************************************************************/ 92 : /* GDALAlgorithmRegistry::GetNames() */ 93 : /************************************************************************/ 94 : 95 569 : std::vector<std::string> GDALAlgorithmRegistry::GetNames() const 96 : { 97 569 : std::vector<std::string> res; 98 3238 : for (const auto &iter : m_mapNameToInfo) 99 : { 100 2669 : res.push_back(iter.first); 101 : } 102 569 : return res; 103 : } 104 : 105 : GDALGlobalAlgorithmRegistry::GDALGlobalAlgorithmRegistry() = default; 106 : 107 : GDALGlobalAlgorithmRegistry::~GDALGlobalAlgorithmRegistry() = default; 108 : 109 : /************************************************************************/ 110 : /* GDALGlobalAlgorithmRegistry::GetSingleton() */ 111 : /************************************************************************/ 112 : 113 : /* static */ GDALGlobalAlgorithmRegistry & 114 23568 : GDALGlobalAlgorithmRegistry::GetSingleton() 115 : { 116 23568 : static GDALGlobalAlgorithmRegistry singleton; 117 23568 : return singleton; 118 : } 119 : 120 : /************************************************************************/ 121 : /* GDALGlobalAlgorithmRegistry::Instantiate() */ 122 : /************************************************************************/ 123 : 124 : std::unique_ptr<GDALAlgorithm> 125 1562 : GDALGlobalAlgorithmRegistry::Instantiate(const std::string &name) const 126 : { 127 1562 : if (name == GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME) 128 183 : return std::make_unique<GDALMainAlgorithm>(); 129 2758 : auto alg = GDALAlgorithmRegistry::Instantiate(name); 130 1379 : if (!alg) 131 : { 132 116 : alg = InstantiateDeclaredSubAlgorithm( 133 87 : {GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME, name}); 134 : } 135 1379 : if (alg) 136 : { 137 4119 : alg->SetCallPath({GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME, name}); 138 : } 139 1379 : return alg; 140 : } 141 : 142 : /************************************************************************/ 143 : /* GDALGlobalAlgorithmRegistry::DeclareAlgorithm() */ 144 : /************************************************************************/ 145 : 146 13483 : void GDALGlobalAlgorithmRegistry::DeclareAlgorithm( 147 : const std::vector<std::string> &path, InstantiateFunc instantiateFunc) 148 : { 149 13483 : Node *curNode = &m_root; 150 45488 : for (size_t i = 0; i < path.size(); ++i) 151 : { 152 32005 : const std::string &name = path[i]; 153 32005 : auto iter = curNode->children.find(name); 154 32005 : if (iter == curNode->children.end()) 155 : { 156 12665 : Node newNode; 157 12665 : if (i + 1 == path.size()) 158 : { 159 12664 : newNode.instantiateFunc = instantiateFunc; 160 : } 161 : else 162 : { 163 : newNode.instantiateFunc = 164 4 : [name]() -> std::unique_ptr<GDALAlgorithm> 165 : { 166 4 : return std::make_unique<GDALContainerAlgorithm>( 167 8 : name, std::string("Command for ").append(name)); 168 1 : }; 169 : } 170 12665 : curNode = 171 25330 : &(curNode->children.insert(std::pair(name, std::move(newNode))) 172 12665 : .first->second); 173 : } 174 : else 175 : { 176 19340 : curNode = &(iter->second); 177 : } 178 : } 179 13483 : } 180 : 181 : /************************************************************************/ 182 : /* GDALGlobalAlgorithmRegistry::GetNodeFromPath() */ 183 : /************************************************************************/ 184 : 185 : const GDALGlobalAlgorithmRegistry::Node * 186 15302 : GDALGlobalAlgorithmRegistry::GetNodeFromPath( 187 : const std::vector<std::string> &path) const 188 : { 189 15302 : if (!path.empty()) 190 : { 191 14865 : const Node *curNode = &m_root; 192 14865 : bool first = true; 193 28694 : for (const std::string &name : path) 194 : { 195 22667 : if (first && name == GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME) 196 : { 197 1228 : first = false; 198 1228 : continue; 199 : } 200 21439 : first = false; 201 21439 : auto iter = curNode->children.find(name); 202 21439 : if (iter == curNode->children.end()) 203 8838 : return nullptr; 204 12601 : curNode = &(iter->second); 205 : } 206 6027 : return curNode; 207 : } 208 437 : return nullptr; 209 : } 210 : 211 : /************************************************************************/ 212 : /* GDALGlobalAlgorithmRegistry::GetDeclaredSubAlgorithmNames() */ 213 : /************************************************************************/ 214 : 215 : std::vector<std::string> 216 2240 : GDALGlobalAlgorithmRegistry::GetDeclaredSubAlgorithmNames( 217 : const std::vector<std::string> &path) const 218 : { 219 2240 : const GDALGlobalAlgorithmRegistry::Node *node = GetNodeFromPath(path); 220 2240 : std::vector<std::string> ret; 221 2240 : if (node) 222 : { 223 256 : for (const auto &[name, subnode] : node->children) 224 : { 225 : // If there is an instantiation function, run it, to avoid 226 : // reporting algorithms that might be in drivers built as 227 : // deferred loaded plugins, but not available at runtime. 228 164 : if (!subnode.instantiateFunc || subnode.instantiateFunc()) 229 : { 230 164 : ret.push_back(name); 231 : } 232 : } 233 : } 234 2240 : return ret; 235 : } 236 : 237 : /************************************************************************/ 238 : /* GDALGlobalAlgorithmRegistry::HasDeclaredSubAlgorithm() */ 239 : /************************************************************************/ 240 : 241 12892 : bool GDALGlobalAlgorithmRegistry::HasDeclaredSubAlgorithm( 242 : const std::vector<std::string> &path) const 243 : { 244 12892 : return GetNodeFromPath(path) != nullptr; 245 : } 246 : 247 : /************************************************************************/ 248 : /* GDALGlobalAlgorithmRegistry::InstantiateDeclaredSubAlgorithm() */ 249 : /************************************************************************/ 250 : 251 : std::unique_ptr<GDALAlgorithm> 252 170 : GDALGlobalAlgorithmRegistry::InstantiateDeclaredSubAlgorithm( 253 : const std::vector<std::string> &path) const 254 : { 255 170 : const GDALGlobalAlgorithmRegistry::Node *node = GetNodeFromPath(path); 256 170 : if (node && node->instantiateFunc) 257 : { 258 156 : auto alg = node->instantiateFunc(); 259 78 : if (alg) 260 : { 261 156 : auto callPath = path; 262 78 : if (path[0] != GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME) 263 0 : callPath.insert(callPath.begin(), 264 0 : GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME); 265 78 : alg->SetCallPath(callPath); 266 : } 267 78 : return alg; 268 : } 269 92 : return nullptr; 270 : } 271 : 272 : /************************************************************************/ 273 : /* struct GDALAlgorithmRegistryHS */ 274 : /************************************************************************/ 275 : 276 : struct GDALAlgorithmRegistryHS 277 : { 278 : GDALAlgorithmRegistry *ptr = nullptr; 279 : }; 280 : 281 : /************************************************************************/ 282 : /* GDALGetGlobalAlgorithmRegistry() */ 283 : /************************************************************************/ 284 : 285 : /** Gets a handle to the GDALGetGlobalAlgorithmRegistry which references 286 : * all available top-level GDAL algorithms ("raster", "vector", etc.) 287 : * 288 : * The handle must be released with GDALAlgorithmRegistryRelease() (but 289 : * this does not destroy the GDALAlgorithmRegistryRelease singleton). 290 : * 291 : * @since 3.11 292 : */ 293 1363 : GDALAlgorithmRegistryH GDALGetGlobalAlgorithmRegistry() 294 : { 295 2726 : auto ret = std::make_unique<GDALAlgorithmRegistryHS>(); 296 1363 : ret->ptr = &(GDALGlobalAlgorithmRegistry::GetSingleton()); 297 2726 : return ret.release(); 298 : } 299 : 300 : /************************************************************************/ 301 : /* GDALAlgorithmRegistryRelease() */ 302 : /************************************************************************/ 303 : 304 : /** Release a handle to an algorithm registry, but this does not destroy the 305 : * registry itself. 306 : * 307 : * @since 3.11 308 : */ 309 1363 : void GDALAlgorithmRegistryRelease(GDALAlgorithmRegistryH hReg) 310 : { 311 1363 : delete hReg; 312 1363 : } 313 : 314 : /************************************************************************/ 315 : /* GDALAlgorithmRegistryGetAlgNames() */ 316 : /************************************************************************/ 317 : 318 : /** Return the names of the algorithms registered in the registry passed as 319 : * parameter. 320 : * 321 : * @param hReg Handle to a registry. Must NOT be null. 322 : * @return a NULL terminated list of names, which must be destroyed with 323 : * CSLDestroy() 324 : * 325 : * @since 3.11 326 : */ 327 2 : char **GDALAlgorithmRegistryGetAlgNames(GDALAlgorithmRegistryH hReg) 328 : { 329 2 : VALIDATE_POINTER1(hReg, __func__, nullptr); 330 2 : return CPLStringList(hReg->ptr->GetNames()).StealList(); 331 : } 332 : 333 : /************************************************************************/ 334 : /* GDALAlgorithmRegistryInstantiateAlg() */ 335 : /************************************************************************/ 336 : 337 : /** Instantiate an algorithm available in a registry from its name. 338 : * 339 : * @param hReg Handle to a registry. Must NOT be null. 340 : * @param pszAlgName Algorithm name. Must NOT be null. 341 : * @return an handle to the algorithm (to be freed with GDALAlgorithmRelease), 342 : * or NULL if the algorithm does not exist or another error occurred. 343 : * 344 : * @since 3.11 345 : */ 346 1365 : GDALAlgorithmH GDALAlgorithmRegistryInstantiateAlg(GDALAlgorithmRegistryH hReg, 347 : const char *pszAlgName) 348 : { 349 1365 : VALIDATE_POINTER1(hReg, __func__, nullptr); 350 1365 : VALIDATE_POINTER1(pszAlgName, __func__, nullptr); 351 2730 : auto alg = hReg->ptr->Instantiate(pszAlgName); 352 2730 : return alg ? std::make_unique<GDALAlgorithmHS>(std::move(alg)).release() 353 2730 : : nullptr; 354 : }