LCOV - code coverage report
Current view: top level - gcore - gdalalgorithmregistry.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 144 146 98.6 %
Date: 2026-01-09 05:19:41 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             : #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             : }

Generated by: LCOV version 1.14