Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpJsonArgumentParser.h
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * An argument parser that can both use JSON files and command line arguments as inputs.
32 */
33
34#ifndef VP_JSON_ARGUMENT_PARSER_H
35#define VP_JSON_ARGUMENT_PARSER_H
36
37#include <visp3/core/vpConfig.h>
38
39#if defined(VISP_HAVE_NLOHMANN_JSON)
40#include VISP_NLOHMANN_JSON(json.hpp)
41#include <visp3/core/vpException.h>
42#include <sstream>
43
44
51
52template<typename T>
53nlohmann::json convertCommandLineArgument(const std::string &arg)
54{
55 nlohmann::json j = nlohmann::json::parse(arg);
56 return j;
57}
58
65template<>
66nlohmann::json convertCommandLineArgument<std::string>(const std::string &arg)
67{
68 nlohmann::json j = arg;
69 return j;
70}
71
73
137class VISP_EXPORT vpJsonArgumentParser
138{
139public:
140
142 {
145 };
146
163 vpJsonArgumentParser(const std::string &description, const std::string &jsonFileArgumentName, const std::string &nestSeparator);
164
172 std::string help() const;
173
188 template<typename T>
189 vpJsonArgumentParser &addArgument(const std::string &name, T &parameter, const bool required = true, const std::string &help = "No description")
190 {
191 m_argumentType[name] = WITH_FIELD;
192 const auto getter = [name, this](nlohmann::json &j, bool create) -> nlohmann::json * {
193 size_t pos = 0;
194 nlohmann::json *f = &j;
195 std::string token;
196 std::string name_copy = name;
197
198 while ((pos = name_copy.find(m_nestSeparator)) != std::string::npos) {
199 token = name_copy.substr(0, pos);
200
201 name_copy.erase(0, pos + m_nestSeparator.length());
202 if (create && !f->contains(token)) {
203 (*f)[token] = {};
204 }
205 else if (!f->contains(token)) {
206 return nullptr;
207 }
208 f = &(f->at(token));
209 }
210 if (create && !f->contains(name_copy)) {
211 (*f)[name_copy] = {};
212 }
213 else if (!f->contains(name_copy)) {
214 return nullptr;
215 }
216 f = &(f->at(name_copy));
217 return f;
218 };
219
220 m_parsers[name] = [&parameter, required, getter, name](nlohmann::json &j) {
221 const nlohmann::json *field = getter(j, false);
222 const bool fieldHasNoValue = field == nullptr || (field != nullptr && field->is_null());
223 if (required && fieldHasNoValue) {
224 std::stringstream ss;
225 ss << "Argument " << name << " is required, but no value was provided" << std::endl;
226 throw vpException(vpException::badValue, ss.str());
227 }
228 else if (!fieldHasNoValue) {
229 field->get_to(parameter);
230 }
231 };
232
233 m_updaters[name] = [getter](nlohmann::json &j, const std::string &s) {
234 nlohmann::json *field = getter(j, true);
235 *field = convertCommandLineArgument<T>(s);
236 };
237
238 m_helpers[name] = [help, parameter, required]() -> std::string {
239 std::stringstream ss;
240 nlohmann::json repr = parameter;
241 ss << help << std::endl << "Default: " << repr;
242 if (required) {
243 ss << std::endl << "Required";
244 }
245 else {
246 ss << std::endl << "Optional";
247 }
248 return ss.str();
249 };
250
251 nlohmann::json *exampleField = getter(m_exampleJson, true);
252 *exampleField = parameter;
253
254 return *this;
255 }
256
266 vpJsonArgumentParser &addFlag(const std::string &name, bool &parameter, const std::string &help = "No description");
267
274 void parse(int argc, const char *argv[]);
275
276private:
277 std::string m_description; // Program description
278 std::string m_jsonFileArgumentName; // Name of the argument that points to the json file: ./program --config settings.json. Here jsonFileArgumentName == "--config"
279 std::string m_nestSeparator; // JSON nesting delimiter character. Used to access JSON nested objects from a single string
280 std::map<std::string, std::function<void(nlohmann::json &)>> m_parsers; // Functions that update the variables with the values contained in the JSON document (should be used after calling updaters)
281 std::map<std::string, vpJsonArgumentType> m_argumentType; // Update the base json document with command line arguments
282 std::map<std::string, std::function<void(nlohmann::json &, const std::string &)>> m_updaters; // Update the base json document with command line arguments
283 std::map<std::string, std::function<std::string()>> m_helpers; // Functions that output the usage and description of command line arguments: used when the help flag is given as argument
284 nlohmann::json m_exampleJson; // Example JSON argument file: displayed when user calls for help
285};
286
287END_VISP_NAMESPACE
288
289#endif // VISP_HAVE_NLOHMANN_JSON
290
291#endif
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ badValue
Used to indicate that a value is not in the allowed range.
Definition vpException.h:73
Command line argument parsing with support for JSON files. If a JSON file is supplied,...
std::string help() const
Generate a help message, containing the description of the arguments, their default value and whether...
vpJsonArgumentParser & addArgument(const std::string &name, T &parameter, const bool required=true, const std::string &help="No description")
Add an argument that can be provided by the user, either via command line or through the json file.
vpJsonArgumentParser(const std::string &description, const std::string &jsonFileArgumentName, const std::string &nestSeparator)
Create a new argument parser, that can take into account both a JSON configuration file and command l...