Coverage Report

Created: 2025-06-13 06:29

/src/gdal/gcore/gdalalgorithmregistry.cpp
Line
Count
Source (jump to first uncovered line)
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
0
GDALAlgorithmRegistry::~GDALAlgorithmRegistry() = default;
27
28
/************************************************************************/
29
/*                GDALAlgorithmRegistry::Register()                     */
30
/************************************************************************/
31
32
bool GDALAlgorithmRegistry::Register(const GDALAlgorithmRegistry::AlgInfo &info)
33
0
{
34
0
    if (cpl::contains(m_mapNameToInfo, info.m_name))
35
0
    {
36
0
        CPLError(CE_Failure, CPLE_AppDefined,
37
0
                 "GDAL algorithm '%s' already registered!",
38
0
                 info.m_name.c_str());
39
0
        return false;
40
0
    }
41
0
    for (const std::string &alias : info.m_aliases)
42
0
    {
43
0
        if (cpl::contains(m_mapAliasToInfo, alias) ||
44
0
            cpl::contains(m_mapHiddenAliasToInfo, alias))
45
0
        {
46
0
            CPLError(CE_Failure, CPLE_AppDefined,
47
0
                     "An algorithm with alias '%s' is already registered!",
48
0
                     alias.c_str());
49
0
            return false;
50
0
        }
51
0
    }
52
0
    m_mapNameToInfo[info.m_name] = info;
53
0
    bool hidden = false;
54
0
    for (const std::string &alias : info.m_aliases)
55
0
    {
56
0
        if (alias == HIDDEN_ALIAS_SEPARATOR)
57
0
            hidden = true;
58
0
        else if (hidden)
59
0
            m_mapAliasToInfo[alias] = info;
60
0
        else
61
0
            m_mapHiddenAliasToInfo[alias] = info;
62
0
    }
63
0
    return true;
64
0
}
65
66
/************************************************************************/
67
/*                   GDALAlgorithmRegistry::Instantiate()               */
68
/************************************************************************/
69
70
std::unique_ptr<GDALAlgorithm>
71
GDALAlgorithmRegistry::Instantiate(const std::string &name) const
72
0
{
73
0
    auto iter = m_mapNameToInfo.find(name);
74
0
    if (iter == m_mapNameToInfo.end())
75
0
    {
76
0
        iter = m_mapAliasToInfo.find(name);
77
0
        if (iter == m_mapAliasToInfo.end())
78
0
        {
79
0
            iter = m_mapHiddenAliasToInfo.find(name);
80
0
            if (iter == m_mapHiddenAliasToInfo.end())
81
0
            {
82
0
                return nullptr;
83
0
            }
84
0
        }
85
0
    }
86
0
    auto alg = iter->second.m_creationFunc();
87
0
    alg->m_aliases = iter->second.m_aliases;
88
0
    return alg;
89
0
}
90
91
/************************************************************************/
92
/*                GDALAlgorithmRegistry::GetNames()                     */
93
/************************************************************************/
94
95
std::vector<std::string> GDALAlgorithmRegistry::GetNames() const
96
0
{
97
0
    std::vector<std::string> res;
98
0
    for (const auto &iter : m_mapNameToInfo)
99
0
    {
100
0
        res.push_back(iter.first);
101
0
    }
102
0
    return res;
103
0
}
104
105
0
GDALGlobalAlgorithmRegistry::GDALGlobalAlgorithmRegistry() = default;
106
107
0
GDALGlobalAlgorithmRegistry::~GDALGlobalAlgorithmRegistry() = default;
108
109
/************************************************************************/
110
/*              GDALGlobalAlgorithmRegistry::GetSingleton()             */
111
/************************************************************************/
112
113
/* static */ GDALGlobalAlgorithmRegistry &
114
GDALGlobalAlgorithmRegistry::GetSingleton()
115
0
{
116
0
    static GDALGlobalAlgorithmRegistry singleton;
117
0
    return singleton;
118
0
}
119
120
/************************************************************************/
121
/*               GDALGlobalAlgorithmRegistry::Instantiate()             */
122
/************************************************************************/
123
124
std::unique_ptr<GDALAlgorithm>
125
GDALGlobalAlgorithmRegistry::Instantiate(const std::string &name) const
126
0
{
127
0
    if (name == GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME)
128
0
        return std::make_unique<GDALMainAlgorithm>();
129
0
    auto alg = GDALAlgorithmRegistry::Instantiate(name);
130
0
    if (!alg)
131
0
    {
132
0
        alg = InstantiateDeclaredSubAlgorithm(
133
0
            {GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME, name});
134
0
    }
135
0
    if (alg)
136
0
    {
137
0
        alg->SetCallPath({GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME, name});
138
0
    }
139
0
    return alg;
140
0
}
141
142
/************************************************************************/
143
/*             GDALGlobalAlgorithmRegistry::DeclareAlgorithm()          */
144
/************************************************************************/
145
146
void GDALGlobalAlgorithmRegistry::DeclareAlgorithm(
147
    const std::vector<std::string> &path, InstantiateFunc instantiateFunc)
148
0
{
149
0
    Node *curNode = &m_root;
150
0
    for (size_t i = 0; i < path.size(); ++i)
151
0
    {
152
0
        const std::string &name = path[i];
153
0
        auto iter = curNode->children.find(name);
154
0
        if (iter == curNode->children.end())
155
0
        {
156
0
            Node newNode;
157
0
            if (i + 1 == path.size())
158
0
            {
159
0
                newNode.instantiateFunc = instantiateFunc;
160
0
            }
161
0
            else
162
0
            {
163
0
                newNode.instantiateFunc =
164
0
                    [name]() -> std::unique_ptr<GDALAlgorithm>
165
0
                {
166
0
                    return std::make_unique<GDALContainerAlgorithm>(
167
0
                        name, std::string("Command for ").append(name));
168
0
                };
169
0
            }
170
0
            curNode =
171
0
                &(curNode->children.insert(std::pair(name, std::move(newNode)))
172
0
                      .first->second);
173
0
        }
174
0
        else
175
0
        {
176
0
            curNode = &(iter->second);
177
0
        }
178
0
    }
179
0
}
180
181
/************************************************************************/
182
/*            GDALGlobalAlgorithmRegistry::GetNodeFromPath()            */
183
/************************************************************************/
184
185
const GDALGlobalAlgorithmRegistry::Node *
186
GDALGlobalAlgorithmRegistry::GetNodeFromPath(
187
    const std::vector<std::string> &path) const
188
0
{
189
0
    if (!path.empty())
190
0
    {
191
0
        const Node *curNode = &m_root;
192
0
        bool first = true;
193
0
        for (const std::string &name : path)
194
0
        {
195
0
            if (first && name == GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME)
196
0
            {
197
0
                first = false;
198
0
                continue;
199
0
            }
200
0
            first = false;
201
0
            auto iter = curNode->children.find(name);
202
0
            if (iter == curNode->children.end())
203
0
                return nullptr;
204
0
            curNode = &(iter->second);
205
0
        }
206
0
        return curNode;
207
0
    }
208
0
    return nullptr;
209
0
}
210
211
/************************************************************************/
212
/*     GDALGlobalAlgorithmRegistry::GetDeclaredSubAlgorithmNames()      */
213
/************************************************************************/
214
215
std::vector<std::string>
216
GDALGlobalAlgorithmRegistry::GetDeclaredSubAlgorithmNames(
217
    const std::vector<std::string> &path) const
218
0
{
219
0
    const GDALGlobalAlgorithmRegistry::Node *node = GetNodeFromPath(path);
220
0
    std::vector<std::string> ret;
221
0
    if (node)
222
0
    {
223
0
        for (const auto &[name, subnode] : node->children)
224
0
        {
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
0
            if (!subnode.instantiateFunc || subnode.instantiateFunc())
229
0
            {
230
0
                ret.push_back(name);
231
0
            }
232
0
        }
233
0
    }
234
0
    return ret;
235
0
}
236
237
/************************************************************************/
238
/*       GDALGlobalAlgorithmRegistry::HasDeclaredSubAlgorithm()         */
239
/************************************************************************/
240
241
bool GDALGlobalAlgorithmRegistry::HasDeclaredSubAlgorithm(
242
    const std::vector<std::string> &path) const
243
0
{
244
0
    return GetNodeFromPath(path) != nullptr;
245
0
}
246
247
/************************************************************************/
248
/*     GDALGlobalAlgorithmRegistry::InstantiateDeclaredSubAlgorithm()   */
249
/************************************************************************/
250
251
std::unique_ptr<GDALAlgorithm>
252
GDALGlobalAlgorithmRegistry::InstantiateDeclaredSubAlgorithm(
253
    const std::vector<std::string> &path) const
254
0
{
255
0
    const GDALGlobalAlgorithmRegistry::Node *node = GetNodeFromPath(path);
256
0
    if (node && node->instantiateFunc)
257
0
    {
258
0
        auto alg = node->instantiateFunc();
259
0
        if (alg)
260
0
        {
261
0
            auto callPath = path;
262
0
            if (path[0] != GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME)
263
0
                callPath.insert(callPath.begin(),
264
0
                                GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME);
265
0
            alg->SetCallPath(callPath);
266
0
        }
267
0
        return alg;
268
0
    }
269
0
    return nullptr;
270
0
}
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
GDALAlgorithmRegistryH GDALGetGlobalAlgorithmRegistry()
294
0
{
295
0
    auto ret = std::make_unique<GDALAlgorithmRegistryHS>();
296
0
    ret->ptr = &(GDALGlobalAlgorithmRegistry::GetSingleton());
297
0
    return ret.release();
298
0
}
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
void GDALAlgorithmRegistryRelease(GDALAlgorithmRegistryH hReg)
310
0
{
311
0
    delete hReg;
312
0
}
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
char **GDALAlgorithmRegistryGetAlgNames(GDALAlgorithmRegistryH hReg)
328
0
{
329
0
    VALIDATE_POINTER1(hReg, __func__, nullptr);
330
0
    return CPLStringList(hReg->ptr->GetNames()).StealList();
331
0
}
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
GDALAlgorithmH GDALAlgorithmRegistryInstantiateAlg(GDALAlgorithmRegistryH hReg,
347
                                                   const char *pszAlgName)
348
0
{
349
0
    VALIDATE_POINTER1(hReg, __func__, nullptr);
350
0
    VALIDATE_POINTER1(pszAlgName, __func__, nullptr);
351
0
    auto alg = hReg->ptr->Instantiate(pszAlgName);
352
0
    return alg ? std::make_unique<GDALAlgorithmHS>(std::move(alg)).release()
353
0
               : nullptr;
354
0
}