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

Generated by: LCOV version 1.14