Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
vpJsonArgumentParser.h
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2023 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 _vpJsonArgumentParser_h_
35#define _vpJsonArgumentParser_h_
36#include <visp3/core/vpConfig.h>
37
38#if defined(VISP_HAVE_NLOHMANN_JSON)
39#include <nlohmann/json.hpp>
40#include <visp3/core/vpException.h>
41#include <sstream>
42
43
51template<typename T>
52nlohmann::json convertCommandLineArgument(const std::string &arg)
53{
54 nlohmann::json j = nlohmann::json::parse(arg);
55 return j;
56}
63template<>
64nlohmann::json convertCommandLineArgument<std::string>(const std::string &arg)
65{
66 nlohmann::json j = arg;
67 return j;
68}
132class VISP_EXPORT vpJsonArgumentParser
133{
134public:
151 vpJsonArgumentParser(const std::string &description, const std::string &jsonFileArgumentName, const std::string &nestSeparator);
152
160 std::string help() const;
161
162
177 template<typename T>
178 vpJsonArgumentParser &addArgument(const std::string &name, T &parameter, const bool required = true, const std::string &help = "No description")
179 {
180 const auto getter = [name, this](nlohmann::json &j, bool create) -> nlohmann::json * {
181 size_t pos = 0;
182 nlohmann::json *f = &j;
183 std::string token;
184 std::string name_copy = name;
185
186 while ((pos = name_copy.find(nestSeparator)) != std::string::npos) {
187 token = name_copy.substr(0, pos);
188
189 name_copy.erase(0, pos + nestSeparator.length());
190 if (create && !f->contains(token)) {
191 (*f)[token] = {};
192 }
193 else if (!f->contains(token)) {
194 return nullptr;
195 }
196 f = &(f->at(token));
197 }
198 if (create && !f->contains(name_copy)) {
199 (*f)[name_copy] = {};
200 }
201 else if (!f->contains(name_copy)) {
202 return nullptr;
203 }
204 f = &(f->at(name_copy));
205 return f;
206 };
207
208 parsers[name] = [&parameter, required, getter, name](nlohmann::json &j) {
209 const nlohmann::json *field = getter(j, false);
210 const bool fieldHasNoValue = field == nullptr || (field != nullptr && field->is_null());
211 if (required && fieldHasNoValue) {
212 std::stringstream ss;
213 ss << "Argument " << name << " is required, but no value was provided" << std::endl;
214 throw vpException(vpException::badValue, ss.str());
215 }
216 else if (!fieldHasNoValue) {
217 field->get_to(parameter);
218 }
219 };
220
221 updaters[name] = [getter](nlohmann::json &j, const std::string &s) {
222 nlohmann::json *field = getter(j, true);
223 *field = convertCommandLineArgument<T>(s);
224 };
225
226 helpers[name] = [help, parameter, required]() -> std::string {
227 std::stringstream ss;
228 nlohmann::json repr = parameter;
229 ss << help << std::endl << "Default: " << repr;
230 if (required) {
231 ss << std::endl << "Required";
232 }
233 else {
234 ss << std::endl << "Optional";
235 }
236 return ss.str();
237 };
238
239 nlohmann::json *exampleField = getter(exampleJson, true);
240 *exampleField = parameter;
241
242 return *this;
243 }
244
251 void parse(int argc, const char *argv []);
252
253
254private:
255 std::string description; // Program description
256 std::string jsonFileArgumentName; // Name of the argument that points to the json file: ./program --config settings.json. Here jsonFileArgumentName == "--config"
257 std::string nestSeparator; // JSON nesting delimiter character. Used to access JSON nested objects from a single string
258 std::map<std::string, std::function<void(nlohmann::json &)>> parsers; // Functions that update the variables with the values contained in the JSON document (should be used after calling updaters)
259 std::map<std::string, std::function<void(nlohmann::json &, const std::string &)>> updaters; // Update the base json document with command line arguments
260 std::map<std::string, std::function<std::string()>> helpers; // Functions that output the usage and description of command line arguments: used when the help flag is given as argument
261 nlohmann::json exampleJson; // Example JSON argument file: displayed when user calls for help
262};
263
264#endif // VISP_HAVE_NLOHMANN_JSON
265
266#endif
error that can be emitted by ViSP classes.
Definition vpException.h:59
@ badValue
Used to indicate that a value is not in the allowed range.
Definition vpException.h:85
Command line argument parsing with support for JSON files. If a JSON file is supplied,...
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.