Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
ProgramOptions.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* ProgramOptions.h (C) 2000-2026 */
9/* */
10/* Analyseur d'options de programme (remplacement de boost::program_options).*/
11/*---------------------------------------------------------------------------*/
12#ifndef ARCCORE_ALINA_PROGRAMOPTIONS_H
13#define ARCCORE_ALINA_PROGRAMOPTIONS_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "arccore/common/CommonGlobal.h"
18
19#include <any>
20#include <string>
21#include <vector>
22#include <map>
23#include <memory>
24#include <sstream>
25#include <iostream>
26#include <stdexcept>
27#include <algorithm>
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane::ProgramOptions
33{
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38template <typename T>
39class typed_value;
40
42
43/*---------------------------------------------------------------------------*/
44/*---------------------------------------------------------------------------*/
48class ARCCORE_COMMON_EXPORT option_value
49{
50 public:
51
52 virtual ~option_value() = default;
53 virtual std::any parse(const std::string& s) const = 0;
54 virtual std::string default_string() const = 0;
55 virtual bool has_default() const = 0;
56 virtual bool is_required() const = 0;
57 virtual bool is_bool_switch() const = 0;
58 virtual bool is_multitoken() const = 0;
59 virtual std::any default_value_any() const = 0;
60 virtual void assign_bound(const std::any& value) const = 0;
61};
62
63/*---------------------------------------------------------------------------*/
64/*---------------------------------------------------------------------------*/
68template <typename T>
69class typed_value : public option_value
70{
71 public:
72
73 typed_value() = default;
74
75 explicit typed_value(T* bound_variable)
76 : m_bound_variable(bound_variable)
77 {}
78
79 typed_value* default_value(const T& value)
80 {
81 m_default_value = value;
82 m_has_default = true;
83 return this;
84 }
85
86 typed_value* required()
87 {
88 m_is_required = true;
89 return this;
90 }
91
92 typed_value* multitoken()
93 {
94 m_is_multitoken = true;
95 return this;
96 }
97
98 std::any parse(const std::string& s) const override
99 {
100 return std::any(parse_impl(s));
101 }
102
103 T parse_impl(const std::string& s) const
104 {
105 T value{};
106 if constexpr (std::is_same_v<T, std::string>) {
107 value = s;
108 }
109 else {
110 std::istringstream iss(s);
111 iss >> value;
112 if (iss.fail())
113 throw std::logic_error("Failed to parse option value \"" + s + "\"");
114 }
115 return value;
116 }
117
118 std::string default_string() const override
119 {
120 if (!m_has_default)
121 return {};
122 return default_string_impl(m_default_value);
123 }
124
125 static std::string default_string_impl(const T& value)
126 {
127 if constexpr (std::is_same_v<T, std::string>) {
128 return value;
129 }
130 else if constexpr (std::is_same_v<T, bool>) {
131 return value ? "true" : "false";
132 }
133 else {
134 std::ostringstream oss;
135 oss << value;
136 return oss.str();
137 }
138 }
139
140 bool has_default() const override { return m_has_default; }
141 bool is_required() const override { return m_is_required; }
142 bool is_bool_switch() const override { return false; }
143 bool is_multitoken() const override { return m_is_multitoken; }
144
145 std::any default_value_any() const override
146 {
147 return std::any(m_default_value);
148 }
149
150 void assign_bound(const std::any& value) const override
151 {
152 if (m_bound_variable)
153 *m_bound_variable = std::any_cast<T>(value);
154 }
155
156 private:
157
158 T* m_bound_variable = nullptr;
159 T m_default_value{};
160 bool m_has_default{ false };
161 bool m_is_required{ false };
162 bool m_is_multitoken{ false };
163};
164
165/*---------------------------------------------------------------------------*/
166/*---------------------------------------------------------------------------*/
170template <>
171class typed_value<bool> : public option_value
172{
173 public:
174
175 typed_value() = default;
176
177 explicit typed_value(bool* bound_variable)
178 : m_bound_variable(bound_variable)
179 , m_default_value(false)
180 , m_has_default(true)
181 , m_is_bool_switch(true)
182 {}
183
184 typed_value* default_value(const bool& value)
185 {
186 m_default_value = value;
187 m_has_default = true;
188 return this;
189 }
190
191 typed_value* required()
192 {
193 m_is_required = true;
194 return this;
195 }
196
197 typed_value* multitoken()
198 {
199 return this;
200 }
201
202 std::any parse(const std::string& s) const override
203 {
204 return std::any(parse_impl(s));
205 }
206
207 bool parse_impl(const std::string& s) const
208 {
209 if (s == "true" || s == "1" || s == "yes" || s == "on")
210 return true;
211 if (s == "false" || s == "0" || s == "no" || s == "off")
212 return false;
213 throw std::logic_error("Failed to parse bool option value \"" + s + "\"");
214 }
215
216 std::string default_string() const override
217 {
218 if (!m_has_default)
219 return {};
220 return m_default_value ? "true" : "false";
221 }
222
223 bool has_default() const override { return m_has_default; }
224 bool is_required() const override { return m_is_required; }
225 bool is_bool_switch() const override { return m_is_bool_switch; }
226 bool is_multitoken() const override { return false; }
227
228 std::any default_value_any() const override
229 {
230 return std::any(m_default_value);
231 }
232
233 void assign_bound(const std::any& value) const override
234 {
235 if (m_bound_variable)
236 *m_bound_variable = std::any_cast<bool>(value);
237 }
238
239 private:
240
241 bool* m_bound_variable = nullptr;
242 bool m_default_value = false;
243 bool m_has_default = true;
244 bool m_is_bool_switch = true;
245 bool m_is_required{ false };
246};
247
248/*---------------------------------------------------------------------------*/
249/*---------------------------------------------------------------------------*/
253template <>
254class typed_value<std::vector<std::string>> : public option_value
255{
256 public:
257
258 typed_value() = default;
259
260 explicit typed_value(std::vector<std::string>* bound_variable)
261 : m_bound_variable(bound_variable)
262 {}
263
264 typed_value* default_value(const std::vector<std::string>& value)
265 {
266 m_default_value = value;
267 m_has_default = true;
268 return this;
269 }
270
271 typed_value* required()
272 {
273 m_is_required = true;
274 return this;
275 }
276
277 typed_value* multitoken()
278 {
279 m_is_multitoken = true;
280 return this;
281 }
282
283 std::any parse(const std::string& s) const override
284 {
285 std::vector<std::string> v;
286 v.push_back(s);
287 return std::any(std::move(v));
288 }
289
290 std::string default_string() const override
291 {
292 if (!m_has_default || m_default_value.empty())
293 return {};
294 std::string result;
295 for (size_t i = 0; i < m_default_value.size(); ++i) {
296 if (i > 0)
297 result += " ";
298 result += m_default_value[i];
299 }
300 return result;
301 }
302
303 bool has_default() const override { return m_has_default; }
304 bool is_required() const override { return m_is_required; }
305 bool is_bool_switch() const override { return false; }
306 bool is_multitoken() const override { return m_is_multitoken; }
307
308 std::any default_value_any() const override
309 {
310 return std::any(m_default_value);
311 }
312
313 void assign_bound(const std::any& value) const override
314 {
315 if (m_bound_variable)
316 *m_bound_variable = std::any_cast<std::vector<std::string>>(value);
317 }
318
319 private:
320
321 std::vector<std::string>* m_bound_variable = nullptr;
322 std::vector<std::string> m_default_value;
323 bool m_has_default{ false };
324 bool m_is_required{ false };
325 bool m_is_multitoken{ true };
326};
327
328/*---------------------------------------------------------------------------*/
329/*---------------------------------------------------------------------------*/
336class ARCCORE_COMMON_EXPORT untyped_value : public option_value
337{
338 public:
339
340 std::any parse(const std::string&) const override
341 {
342 return std::any(true);
343 }
344
345 std::string default_string() const override { return {}; }
346
347 bool has_default() const override { return false; }
348 bool is_required() const override { return false; }
349 bool is_bool_switch() const override { return true; }
350 bool is_multitoken() const override { return false; }
351
352 std::any default_value_any() const override
353 {
354 return std::any(false);
355 }
356
357 void assign_bound(const std::any&) const override {}
358};
359
360/*---------------------------------------------------------------------------*/
361/*---------------------------------------------------------------------------*/
365template <typename T>
367value()
368{
369 return new typed_value<T>();
370}
371
372/*---------------------------------------------------------------------------*/
373/*---------------------------------------------------------------------------*/
377template <typename T>
378typed_value<T>*
379value(T* v)
380{
381 return new typed_value<T>(v);
382}
383
384/*---------------------------------------------------------------------------*/
385/*---------------------------------------------------------------------------*/
389inline typed_value<bool>*
390bool_switch()
391{
392 return new typed_value<bool>();
393}
394
395/*---------------------------------------------------------------------------*/
396/*---------------------------------------------------------------------------*/
400inline typed_value<bool>*
401bool_switch(bool* v)
402{
403 return new typed_value<bool>(v);
404}
405
406/*---------------------------------------------------------------------------*/
407/*---------------------------------------------------------------------------*/
412{
413 std::string long_name;
414 std::string short_name;
415 std::string description;
416 std::shared_ptr<option_value> value_semantic;
417 bool has_short{ false };
418};
419
420/*---------------------------------------------------------------------------*/
421/*---------------------------------------------------------------------------*/
425class ARCCORE_COMMON_EXPORT options_description
426{
427 public:
428
429 explicit options_description(const std::string& title = "Options");
430
434 class ARCCORE_COMMON_EXPORT options_proxy
435 {
436 public:
437
438 explicit options_proxy(options_description& desc)
439 : m_desc(desc)
440 {}
441
442 options_proxy& operator()(const char* name, const char* description);
443 options_proxy& operator()(const char* name, const typed_value<bool>* value,
444 const char* description);
445 options_proxy& operator()(const char* name, const typed_value<bool>* value);
446
447 template <typename T>
448 options_proxy& operator()(const char* name, const typed_value<T>* value,
449 const char* description)
450 {
451 m_desc.add_option(name, std::shared_ptr<option_value>(const_cast<typed_value<T>*>(value)),
452 description);
453 return *this;
454 }
455
456 template <typename T>
457 options_proxy& operator()(const char* name, const typed_value<T>* value)
458 {
459 m_desc.add_option(name, std::shared_ptr<option_value>(const_cast<typed_value<T>*>(value)),
460 std::string());
461 return *this;
462 }
463
464 private:
465
466 options_description& m_desc;
467 };
468
469 options_proxy add_options();
470
471 void add_option(const std::string& name,
472 std::shared_ptr<option_value> value_semantic,
473 const std::string& description);
474
475 const std::vector<option_descriptor>& options() const { return m_options; }
476 const option_descriptor* find(const std::string& name) const;
477 const option_descriptor* find_by_short(char short_name) const;
478
479 ARCCORE_COMMON_EXPORT friend std::ostream& operator<<(std::ostream& os, const options_description& desc);
480
481 private:
482
483 std::vector<option_descriptor> m_options;
484 std::string m_title;
485};
486
487/*---------------------------------------------------------------------------*/
488/*---------------------------------------------------------------------------*/
492class ARCCORE_COMMON_EXPORT variables_map
493{
494 public:
495
496 class variable_value
497 {
498 public:
499
500 variable_value() = default;
501
502 // explicit do not build with gcc-12
503 variable_value(std::any value, bool is_default = false)
504 : m_value(std::move(value))
505 , m_is_default(is_default)
506 {}
507
508 bool empty() const { return !m_value.has_value(); }
509 bool is_default() const { return m_is_default; }
510
511 template <typename T>
512 T as() const
513 {
514 try {
515 return std::any_cast<T>(m_value);
516 }
517 catch (const std::bad_any_cast&) {
518 throw std::logic_error("Type mismatch in variable_value::as<T>()");
519 }
520 }
521
522 void set_semantic(std::shared_ptr<option_value> semantic)
523 {
524 m_semantic = std::move(semantic);
525 }
526
527 const std::shared_ptr<option_value>& semantic() const { return m_semantic; }
528 std::any& value_ref() { return m_value; }
529
530 private:
531
532 std::any m_value;
533 bool m_is_default{ false };
534 std::shared_ptr<option_value> m_semantic;
535 };
536
537 void add(const std::string& name, variable_value value);
538 bool count(const std::string& name) const;
539 const variable_value& operator[](const std::string& name) const;
540
541 void set_semantic(const std::string& name, std::shared_ptr<option_value> semantic);
542
543 using iterator = std::map<std::string, variable_value>::iterator;
544 using const_iterator = std::map<std::string, variable_value>::const_iterator;
545 iterator begin() { return m_values.begin(); }
546 iterator end() { return m_values.end(); }
547 const_iterator begin() const { return m_values.begin(); }
548 const_iterator end() const { return m_values.end(); }
549
550 private:
551
552 std::map<std::string, variable_value> m_values;
553};
554
555/*---------------------------------------------------------------------------*/
556/*---------------------------------------------------------------------------*/
560class ARCCORE_COMMON_EXPORT positional_options_description
561{
562 public:
563
564 positional_options_description& add(const std::string& name, int count);
565
566 const std::vector<std::pair<std::string, int>>& options() const { return m_options; }
567
568 private:
569
570 std::vector<std::pair<std::string, int>> m_options;
571};
572
573/*---------------------------------------------------------------------------*/
574/*---------------------------------------------------------------------------*/
578class ARCCORE_COMMON_EXPORT parsed_options
579{
580 public:
581
583 {
584 std::string name;
585 std::vector<std::string> values;
586 };
587
588 explicit parsed_options(const options_description* desc)
589 : m_desc(desc)
590 {}
591
592 const options_description& description() const { return *m_desc; }
593
594 void add_option(const std::string& name, std::vector<std::string> values)
595 {
596 m_parsed.push_back({ name, std::move(values) });
597 }
598
599 const std::vector<parsed_option>& options() const { return m_parsed; }
600
601 private:
602
603 const options_description* m_desc = nullptr;
604 std::vector<parsed_option> m_parsed;
605};
606
607/*---------------------------------------------------------------------------*/
608/*---------------------------------------------------------------------------*/
612class ARCCORE_COMMON_EXPORT command_line_parser
613{
614 public:
615
616 command_line_parser(int argc, char** argv)
617 : m_argc(argc)
618 , m_argv(argv)
619 {}
620
621 command_line_parser& options(const options_description& desc)
622 {
623 m_desc = &desc;
624 return *this;
625 }
626
627 command_line_parser& positional(const positional_options_description& pos)
628 {
629 m_positional = &pos;
630 return *this;
631 }
632
634
635 private:
636
637 int m_argc = 0;
638 char** m_argv = nullptr;
639 const options_description* m_desc = nullptr;
640 const positional_options_description* m_positional = nullptr;
641};
642
643/*---------------------------------------------------------------------------*/
644/*---------------------------------------------------------------------------*/
645
646extern "C++" ARCCORE_COMMON_EXPORT parsed_options
647parse_command_line(int argc, char** argv, const options_description& desc);
648
649extern "C++" ARCCORE_COMMON_EXPORT void
650store(const parsed_options& parsed, variables_map& vm);
651
652extern "C++" ARCCORE_COMMON_EXPORT void
653notify(variables_map& vm);
654
655/*---------------------------------------------------------------------------*/
656/*---------------------------------------------------------------------------*/
657
658} // namespace Arcane::ProgramOptions
659
660/*---------------------------------------------------------------------------*/
661/*---------------------------------------------------------------------------*/
662
663#endif
parsed_options run()
Algorithme d'analyse principal.
Base effacée de type pour la sémantique des valeurs d'options.
Proxy pour les appels en chaîne add_options()().
Décrit un ensemble d'options en ligne de commande.
Résultat de l'analyse des arguments en ligne de commande.
Décrit les arguments positionnels (non-options).
Valeur d'option typée avec prise en charge des valeurs par défaut, requises et multitokens.
Option de présence uniquement (pas de valeur, juste un drapeau).
Stocke les valeurs d'options analysées.
Descripteur interne pour une seule option.