LCOV - code coverage report
Current view: top level - gcore - gdalalgorithmregistry.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 134 136 98.5 %
Date: 2025-10-21 22:35:35 Functions: 19 19 100.0 %

          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      127995 : bool GDALAlgorithmRegistry::Register(const GDALAlgorithmRegistry::AlgInfo &info)
      33             : {
      34      127995 :     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      157609 :     for (const std::string &alias : info.m_aliases)
      42             :     {
      43       59233 :         if (cpl::contains(m_mapAliasToInfo, alias) ||
      44       29616 :             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      127992 :     m_mapNameToInfo[info.m_name] = info;
      53      127992 :     bool hidden = false;
      54      157606 :     for (const std::string &alias : info.m_aliases)
      55             :     {
      56       29614 :         if (alias == HIDDEN_ALIAS_SEPARATOR)
      57       11318 :             hidden = true;
      58       18296 :         else if (hidden)
      59       15520 :             m_mapAliasToInfo[alias] = info;
      60             :         else
      61        2776 :             m_mapHiddenAliasToInfo[alias] = info;
      62             :     }
      63      127992 :     return true;
      64             : }
      65             : 
      66             : /************************************************************************/
      67             : /*             GDALAlgorithmRegistry::InstantiateTopLevel()             */
      68             : /************************************************************************/
      69             : 
      70             : std::unique_ptr<GDALAlgorithm>
      71        8855 : GDALAlgorithmRegistry::InstantiateTopLevel(const std::string &name) const
      72             : {
      73        8855 :     auto iter = m_mapNameToInfo.find(name);
      74        8855 :     if (iter == m_mapNameToInfo.end())
      75             :     {
      76         460 :         iter = m_mapAliasToInfo.find(name);
      77         460 :         if (iter == m_mapAliasToInfo.end())
      78             :         {
      79         454 :             iter = m_mapHiddenAliasToInfo.find(name);
      80         454 :             if (iter == m_mapHiddenAliasToInfo.end())
      81             :             {
      82         454 :                 return nullptr;
      83             :             }
      84             :         }
      85             :     }
      86       16802 :     auto alg = iter->second.m_creationFunc();
      87        8401 :     alg->m_aliases = iter->second.m_aliases;
      88        8401 :     return alg;
      89             : }
      90             : 
      91             : /************************************************************************/
      92             : /*                   GDALAlgorithmRegistry::Instantiate()               */
      93             : /************************************************************************/
      94             : 
      95             : std::unique_ptr<GDALAlgorithm>
      96        3288 : GDALAlgorithmRegistry::Instantiate(const std::vector<std::string> &path) const
      97             : {
      98        3288 :     if (path.empty())
      99           1 :         return nullptr;
     100        6574 :     auto alg = Instantiate(path[0]);
     101        3290 :     for (size_t i = 1; i < path.size() && alg; ++i)
     102             :     {
     103           3 :         alg = alg->InstantiateSubAlgorithm(path[i]);
     104             :     }
     105        3287 :     return alg;
     106             : }
     107             : 
     108             : /************************************************************************/
     109             : /*                GDALAlgorithmRegistry::GetNames()                     */
     110             : /************************************************************************/
     111             : 
     112         952 : std::vector<std::string> GDALAlgorithmRegistry::GetNames() const
     113             : {
     114         952 :     std::vector<std::string> res;
     115        6906 :     for (const auto &iter : m_mapNameToInfo)
     116             :     {
     117        5954 :         res.push_back(iter.first);
     118             :     }
     119         952 :     return res;
     120             : }
     121             : 
     122             : /************************************************************************/
     123             : /*                GDALAlgorithmRegistry::Instantiate()                  */
     124             : /************************************************************************/
     125             : 
     126             : std::unique_ptr<GDALAlgorithm>
     127        9198 : GDALAlgorithmRegistry::Instantiate(const std::string &name) const
     128             : {
     129        9198 :     return InstantiateTopLevel(name);
     130             : }
     131             : 
     132             : std::unique_ptr<GDALAlgorithm>
     133        3286 : GDALAlgorithmRegistry::InstantiateInternal(std::vector<std::string> &path)
     134             : {
     135        3286 :     return Instantiate(path);
     136             : }
     137             : 
     138             : GDALGlobalAlgorithmRegistry::GDALGlobalAlgorithmRegistry() = default;
     139             : 
     140             : GDALGlobalAlgorithmRegistry::~GDALGlobalAlgorithmRegistry() = default;
     141             : 
     142             : /************************************************************************/
     143             : /*              GDALGlobalAlgorithmRegistry::GetSingleton()             */
     144             : /************************************************************************/
     145             : 
     146             : /* static */ GDALGlobalAlgorithmRegistry &
     147       29407 : GDALGlobalAlgorithmRegistry::GetSingleton()
     148             : {
     149       29407 :     static GDALGlobalAlgorithmRegistry singleton;
     150       29407 :     return singleton;
     151             : }
     152             : 
     153             : /************************************************************************/
     154             : /*           GDALGlobalAlgorithmRegistry::InstantiateTopLevel()         */
     155             : /************************************************************************/
     156             : 
     157             : std::unique_ptr<GDALAlgorithm>
     158        2473 : GDALGlobalAlgorithmRegistry::InstantiateTopLevel(const std::string &name) const
     159             : {
     160        2473 :     if (name == GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME)
     161         343 :         return std::make_unique<GDALMainAlgorithm>();
     162        4260 :     auto alg = GDALAlgorithmRegistry::InstantiateTopLevel(name);
     163        2130 :     if (!alg)
     164             :     {
     165         116 :         alg = InstantiateDeclaredSubAlgorithm(
     166          87 :             {GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME, name});
     167             :     }
     168        2130 :     if (alg)
     169             :     {
     170        6372 :         alg->SetCallPath({GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME, name});
     171             :     }
     172        2130 :     return alg;
     173             : }
     174             : 
     175             : /************************************************************************/
     176             : /*             GDALGlobalAlgorithmRegistry::DeclareAlgorithm()          */
     177             : /************************************************************************/
     178             : 
     179       14813 : void GDALGlobalAlgorithmRegistry::DeclareAlgorithm(
     180             :     const std::vector<std::string> &path, InstantiateFunc instantiateFunc)
     181             : {
     182       14813 :     Node *curNode = &m_root;
     183       49920 :     for (size_t i = 0; i < path.size(); ++i)
     184             :     {
     185       35107 :         const std::string &name = path[i];
     186       35107 :         auto iter = curNode->children.find(name);
     187       35107 :         if (iter == curNode->children.end())
     188             :         {
     189       13997 :             Node newNode;
     190       13997 :             if (i + 1 == path.size())
     191             :             {
     192       13996 :                 newNode.instantiateFunc = instantiateFunc;
     193             :             }
     194             :             else
     195             :             {
     196             :                 newNode.instantiateFunc =
     197           4 :                     [name]() -> std::unique_ptr<GDALAlgorithm>
     198             :                 {
     199           4 :                     return std::make_unique<GDALContainerAlgorithm>(
     200           8 :                         name, std::string("Command for ").append(name));
     201           1 :                 };
     202             :             }
     203       13997 :             curNode =
     204       27994 :                 &(curNode->children.insert(std::pair(name, std::move(newNode)))
     205       13997 :                       .first->second);
     206             :         }
     207             :         else
     208             :         {
     209       21110 :             curNode = &(iter->second);
     210             :         }
     211             :     }
     212       14813 : }
     213             : 
     214             : /************************************************************************/
     215             : /*            GDALGlobalAlgorithmRegistry::GetNodeFromPath()            */
     216             : /************************************************************************/
     217             : 
     218             : const GDALGlobalAlgorithmRegistry::Node *
     219       18197 : GDALGlobalAlgorithmRegistry::GetNodeFromPath(
     220             :     const std::vector<std::string> &path) const
     221             : {
     222       18197 :     if (!path.empty())
     223             :     {
     224       17514 :         const Node *curNode = &m_root;
     225       17514 :         bool first = true;
     226       32895 :         for (const std::string &name : path)
     227             :         {
     228       26427 :             if (first && name == GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME)
     229             :             {
     230        1750 :                 first = false;
     231        1750 :                 continue;
     232             :             }
     233       24677 :             first = false;
     234       24677 :             auto iter = curNode->children.find(name);
     235       24677 :             if (iter == curNode->children.end())
     236       11046 :                 return nullptr;
     237       13631 :             curNode = &(iter->second);
     238             :         }
     239        6468 :         return curNode;
     240             :     }
     241         683 :     return nullptr;
     242             : }
     243             : 
     244             : /************************************************************************/
     245             : /*     GDALGlobalAlgorithmRegistry::GetDeclaredSubAlgorithmNames()      */
     246             : /************************************************************************/
     247             : 
     248             : std::vector<std::string>
     249        3913 : GDALGlobalAlgorithmRegistry::GetDeclaredSubAlgorithmNames(
     250             :     const std::vector<std::string> &path) const
     251             : {
     252        3913 :     const GDALGlobalAlgorithmRegistry::Node *node = GetNodeFromPath(path);
     253        3913 :     std::vector<std::string> ret;
     254        3913 :     if (node)
     255             :     {
     256         258 :         for (const auto &[name, subnode] : node->children)
     257             :         {
     258             :             // If there is an instantiation function, run it, to avoid
     259             :             // reporting algorithms that might be in drivers built as
     260             :             // deferred loaded plugins, but not available at runtime.
     261         165 :             if (!subnode.instantiateFunc || subnode.instantiateFunc())
     262             :             {
     263         165 :                 ret.push_back(name);
     264             :             }
     265             :         }
     266             :     }
     267        3913 :     return ret;
     268             : }
     269             : 
     270             : /************************************************************************/
     271             : /*       GDALGlobalAlgorithmRegistry::HasDeclaredSubAlgorithm()         */
     272             : /************************************************************************/
     273             : 
     274       14072 : bool GDALGlobalAlgorithmRegistry::HasDeclaredSubAlgorithm(
     275             :     const std::vector<std::string> &path) const
     276             : {
     277       14072 :     return GetNodeFromPath(path) != nullptr;
     278             : }
     279             : 
     280             : /************************************************************************/
     281             : /*     GDALGlobalAlgorithmRegistry::InstantiateDeclaredSubAlgorithm()   */
     282             : /************************************************************************/
     283             : 
     284             : std::unique_ptr<GDALAlgorithm>
     285         212 : GDALGlobalAlgorithmRegistry::InstantiateDeclaredSubAlgorithm(
     286             :     const std::vector<std::string> &path) const
     287             : {
     288         212 :     const GDALGlobalAlgorithmRegistry::Node *node = GetNodeFromPath(path);
     289         212 :     if (node && node->instantiateFunc)
     290             :     {
     291         156 :         auto alg = node->instantiateFunc();
     292          78 :         if (alg)
     293             :         {
     294         156 :             auto callPath = path;
     295          78 :             if (path[0] != GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME)
     296           0 :                 callPath.insert(callPath.begin(),
     297           0 :                                 GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME);
     298          78 :             alg->SetCallPath(callPath);
     299             :         }
     300          78 :         return alg;
     301             :     }
     302         134 :     return nullptr;
     303             : }
     304             : 
     305             : /************************************************************************/
     306             : /*                    struct GDALAlgorithmRegistryHS                    */
     307             : /************************************************************************/
     308             : 
     309             : struct GDALAlgorithmRegistryHS
     310             : {
     311             :     GDALAlgorithmRegistry *ptr = nullptr;
     312             : };
     313             : 
     314             : /************************************************************************/
     315             : /*                   GDALGetGlobalAlgorithmRegistry()                   */
     316             : /************************************************************************/
     317             : 
     318             : /** Gets a handle to the GDALGetGlobalAlgorithmRegistry which references
     319             :  * all available top-level GDAL algorithms ("raster", "vector", etc.)
     320             :  *
     321             :  * The handle must be released with GDALAlgorithmRegistryRelease() (but
     322             :  * this does not destroy the GDALAlgorithmRegistryRelease singleton).
     323             :  *
     324             :  * @since 3.11
     325             :  */
     326        2112 : GDALAlgorithmRegistryH GDALGetGlobalAlgorithmRegistry()
     327             : {
     328        4224 :     auto ret = std::make_unique<GDALAlgorithmRegistryHS>();
     329        2112 :     ret->ptr = &(GDALGlobalAlgorithmRegistry::GetSingleton());
     330        4224 :     return ret.release();
     331             : }
     332             : 
     333             : /************************************************************************/
     334             : /*                   GDALAlgorithmRegistryRelease()                     */
     335             : /************************************************************************/
     336             : 
     337             : /** Release a handle to an algorithm registry, but this does not destroy the
     338             :  * registry itself.
     339             :  *
     340             :  * @since 3.11
     341             :  */
     342        2112 : void GDALAlgorithmRegistryRelease(GDALAlgorithmRegistryH hReg)
     343             : {
     344        2112 :     delete hReg;
     345        2112 : }
     346             : 
     347             : /************************************************************************/
     348             : /*                   GDALAlgorithmRegistryGetAlgNames()                 */
     349             : /************************************************************************/
     350             : 
     351             : /** Return the names of the algorithms registered in the registry passed as
     352             :  * parameter.
     353             :  *
     354             :  * @param hReg Handle to a registry. Must NOT be null.
     355             :  * @return a NULL terminated list of names, which must be destroyed with
     356             :  * CSLDestroy()
     357             :  *
     358             :  * @since 3.11
     359             :  */
     360           2 : char **GDALAlgorithmRegistryGetAlgNames(GDALAlgorithmRegistryH hReg)
     361             : {
     362           2 :     VALIDATE_POINTER1(hReg, __func__, nullptr);
     363           2 :     return CPLStringList(hReg->ptr->GetNames()).StealList();
     364             : }
     365             : 
     366             : /************************************************************************/
     367             : /*                  GDALAlgorithmRegistryInstantiateAlg()               */
     368             : /************************************************************************/
     369             : 
     370             : /** Instantiate an algorithm available in a registry from its name.
     371             :  *
     372             :  * @param hReg Handle to a registry. Must NOT be null.
     373             :  * @param pszAlgName Algorithm name. Must NOT be null.
     374             :  * @return an handle to the algorithm (to be freed with GDALAlgorithmRelease),
     375             :  * or NULL if the algorithm does not exist or another error occurred.
     376             :  *
     377             :  * @since 3.11
     378             :  */
     379        2114 : GDALAlgorithmH GDALAlgorithmRegistryInstantiateAlg(GDALAlgorithmRegistryH hReg,
     380             :                                                    const char *pszAlgName)
     381             : {
     382        2114 :     VALIDATE_POINTER1(hReg, __func__, nullptr);
     383        2114 :     VALIDATE_POINTER1(pszAlgName, __func__, nullptr);
     384        4228 :     auto alg = hReg->ptr->Instantiate(pszAlgName);
     385        4228 :     return alg ? std::make_unique<GDALAlgorithmHS>(std::move(alg)).release()
     386        4228 :                : nullptr;
     387             : }
     388             : 
     389             : /************************************************************************/
     390             : /*             GDALAlgorithmRegistryInstantiateAlgFromPath()            */
     391             : /************************************************************************/
     392             : 
     393             : /** Instantiate an algorithm available in a registry from its path.
     394             :  *
     395             :  * @param hReg Handle to a registry. Must NOT be null.
     396             :  * @param papszAlgPath Algorithm path. Must NOT be null.
     397             :  * @return an handle to the algorithm (to be freed with GDALAlgorithmRelease),
     398             :  * or NULL if the algorithm does not exist or another error occurred.
     399             :  *
     400             :  * @since 3.12
     401             :  */
     402             : GDALAlgorithmH
     403           1 : GDALAlgorithmRegistryInstantiateAlgFromPath(GDALAlgorithmRegistryH hReg,
     404             :                                             const char *const *papszAlgPath)
     405             : {
     406           1 :     VALIDATE_POINTER1(hReg, __func__, nullptr);
     407           1 :     VALIDATE_POINTER1(papszAlgPath, __func__, nullptr);
     408           1 :     auto alg = hReg->ptr->Instantiate(
     409           2 :         static_cast<std::vector<std::string>>(CPLStringList(papszAlgPath)));
     410           2 :     return alg ? std::make_unique<GDALAlgorithmHS>(std::move(alg)).release()
     411           2 :                : nullptr;
     412             : }

Generated by: LCOV version 1.14