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-04-07 13:24:38 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             : #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             : }

Generated by: LCOV version 1.14