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

Generated by: LCOV version 1.14