Ookii.CommandLine for C++  2.0.0
command_line_argument.h
Go to the documentation of this file.
1 #ifndef OOKII_COMMAND_LINE_ARGUMENT_H_
7 #define OOKII_COMMAND_LINE_ARGUMENT_H_
8 
9 #pragma once
10 
11 #include <functional>
12 #include "command_line_switch.h"
13 #include "parsing_mode.h"
14 
15 namespace ookii
16 {
17  // Forward declaration.
18  template<typename CharType, typename Traits, typename Alloc>
20 
21  namespace details
22  {
23  template<typename CharType, typename Traits, typename Alloc>
24  struct argument_storage
25  {
26  using string_type = std::basic_string<CharType, Traits, Alloc>;
27 
28  argument_storage(string_type name)
29  : name{name}
30  {
31  }
32 
33  string_type name;
34  string_type value_description;
35  string_type description;
36  std::optional<size_t> position;
37  std::vector<string_type> aliases;
38  std::vector<CharType> short_aliases;
39  bool is_required{};
40  bool cancel_parsing{};
41  bool has_long_name{true};
42  CharType multi_value_separator{};
43  CharType short_name{};
44  };
45 
46  template<typename T, typename Element, typename CharType, typename Traits>
47  struct typed_argument_storage
48  {
49  using converter_type = std::function<std::optional<Element>(std::basic_string_view<CharType, Traits>, const std::locale &)>;
50 
51  typed_argument_storage(T &value)
52  : value{value}
53  {
54  }
55 
56  T &value;
57  std::optional<Element> default_value;
58  converter_type converter;
59  };
60 
61  template<typename T, typename CharType, typename Traits, typename Alloc>
62  struct action_argument_storage
63  {
64  using converter_type = std::function<std::optional<T>(std::basic_string_view<CharType, Traits>, const std::locale &)>;
65  using function_type = std::function<bool(const T &value, basic_command_line_parser<CharType, Traits, Alloc> &parser)>;
66 
67  action_argument_storage(function_type action)
68  : action{action}
69  {
70  }
71 
72  function_type action;
73  converter_type converter;
74  };
75 
76  template<typename T>
77  struct element_type
78  {
79  using type = T;
80  };
81 
82  template<typename T>
83  struct element_type<std::optional<T>>
84  {
85  using type = T;
86  };
87  }
88 
90  enum class set_value_result
91  {
93  success,
95  error,
97  cancel
98  };
99 
106  template<typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
108  {
109  public:
111  using storage_type = details::argument_storage<CharType, Traits, Alloc>;
113  using string_type = typename storage_type::string_type;
115  using string_view_type = std::basic_string_view<CharType, Traits>;
117  using stream_type = std::basic_ostream<CharType, Traits>;
120 
122 
123  virtual ~command_line_argument_base() = default;
124 
125  command_line_argument_base &operator=(const command_line_argument_base &) = delete;
126 
133  const string_type &name() const noexcept
134  {
135  return _storage.name;
136  }
137 
144  CharType short_name() const noexcept
145  {
146  return _storage.short_name;
147  }
148 
152  bool has_short_name() const noexcept
153  {
154  return _storage.short_name != '\0';
155  }
156 
160  bool has_long_name() const noexcept
161  {
162  return _storage.has_long_name;
163  }
164 
170  {
171  if (has_short_name())
172  {
173  return string_view_type(&_storage.short_name, 1);
174  }
175  else
176  {
177  return name();
178  }
179  }
180 
184  {
185  if (has_long_name() && parser.mode() == parsing_mode::long_short)
186  {
187  return parser.long_prefix() + name();
188  }
189  else
190  {
191  return parser.prefixes()[0] + name();
192  }
193  }
194 
200  const std::vector<string_type> &aliases() const noexcept
201  {
202  return _storage.aliases;
203  }
204 
213  const std::vector<CharType> &short_aliases() const noexcept
214  {
215  return _storage.short_aliases;
216  }
217 
227  const string_type &value_description() const noexcept
228  {
229  return _storage.value_description;
230  }
231 
241  const string_type &description() const noexcept
242  {
243  return _storage.description;
244  }
245 
254  std::optional<size_t> position() const noexcept
255  {
256  return _storage.position;
257  }
258 
264  bool is_required() const noexcept
265  {
266  return _storage.is_required;
267  }
268 
280  bool cancel_parsing() const noexcept
281  {
282  return _storage.cancel_parsing;
283  }
284 
290  bool has_value() const noexcept
291  {
292  return _has_value;
293  }
294 
299  virtual bool is_switch() const noexcept = 0;
300 
305  virtual bool is_multi_value() const noexcept
306  {
307  return false;
308  }
309 
316  virtual void reset()
317  {
318  _has_value = false;
319  }
320 
332 
342  virtual void apply_default_value() = 0;
343 
354 
361  virtual stream_type &write_default_value(stream_type &stream) const = 0;
362 
365  virtual bool has_default_value() const noexcept = 0;
366 
367  protected:
371  void set_value() noexcept
372  {
373  _has_value = true;
374  }
375 
377  const storage_type &base_storage() const
378  {
379  return _storage;
380  }
381 
386  : _storage{std::move(storage)}
387  {
388  // Normalize elements based on parsing mode.
389  if (parser.mode() == parsing_mode::long_short)
390  {
391  if (!_storage.has_long_name)
392  {
393  if (_storage.short_name == '\0')
394  {
395  throw std::logic_error("Argument has neither a long nor a short name.");
396  }
397 
398  _storage.name = _storage.short_name;
399  _storage.aliases.clear();
400  }
401 
402  if (_storage.short_name == '\0')
403  {
404  _storage.short_aliases.clear();
405  }
406  }
407  else
408  {
409  _storage.short_name = static_cast<CharType>('\0');
410  _storage.has_long_name = true;
411  _storage.short_aliases.clear();
412  }
413  }
414 
415  private:
416  storage_type _storage;
417  bool _has_value{};
418  };
419 
430  template<class T, typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
431  class command_line_argument final : public command_line_argument_base<CharType, Traits, Alloc>
432  {
433  public:
437  using value_type = T;
442  using element_type = typename details::element_type<T>::type;
448  using typed_storage_type = details::typed_argument_storage<value_type, element_type, CharType, Traits>;
451 
459  command_line_argument(const typename base_type::parser_type &parser, typename base_type::storage_type &&storage,
460  typed_storage_type &&typed_storage)
461  : base_type{parser, std::move(storage)},
462  _storage{std::move(typed_storage)}
463  {
464  }
465 
471  bool is_switch() const noexcept override
472  {
473  return details::is_switch<T>::value;
474  }
475 
478  {
479  std::optional<element_type> converted;
480  if (_storage.converter)
481  converted = _storage.converter(value, parser.locale());
482  else
484 
485  if (!converted)
487 
488  _storage.value = std::move(*converted);
491  }
492 
494  set_value_result set_switch_value([[maybe_unused]] parser_type &parser) override
495  {
496  return set_switch_value_core();
497  }
498 
500  void apply_default_value() override
501  {
502  if (!this->has_value() && _storage.default_value)
503  {
504  _storage.value = *_storage.default_value;
505  }
506  }
507 
509  typename base_type::stream_type &write_default_value(typename base_type::stream_type &stream) const override
510  {
511  if (_storage.default_value)
512  {
513  stream << *_storage.default_value;
514  }
515 
516  return stream;
517  }
518 
520  bool has_default_value() const noexcept override
521  {
522  return _storage.default_value.has_value();
523  }
524 
525  private:
526  template<typename T2 = T>
527  std::enable_if_t<details::is_switch<T2>::value, set_value_result> set_switch_value_core()
528  {
529  _storage.value = true;
532  }
533 
534  template<typename T2 = T>
535  std::enable_if_t<!details::is_switch<T2>::value, set_value_result> set_switch_value_core()
536  {
538  }
539 
540  typed_storage_type _storage;
541  };
542 
552  template<typename T, typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
553  class multi_value_command_line_argument : public command_line_argument_base<CharType, Traits, Alloc>
554  {
555  public:
559  using value_type = T;
561  using element_type = typename T::value_type;
567  using typed_storage_type = details::typed_argument_storage<T, element_type, CharType, Traits>;
570 
579  typed_storage_type &&typed_storage)
580  : base_type{parser, std::move(storage)},
581  _storage{std::move(typed_storage)}
582  {
583  }
584 
586  bool is_switch() const noexcept override
587  {
588  return details::is_switch<element_type>::value;
589  }
590 
594  bool is_multi_value() const noexcept override
595  {
596  return true;
597  }
598 
603  CharType separator() const noexcept
604  {
605  return this->base_storage().multi_value_separator;
606  }
607 
609  void reset() override
610  {
612  _storage.value.clear();
613  }
614 
617  {
618  for (auto element : tokenize{value, separator()})
619  {
620  std::optional<element_type> converted;
621  if (_storage.converter)
622  converted = _storage.converter(element, parser.locale());
623  else
624  converted = lexical_convert<element_type, CharType, Traits, Alloc>::from_string(element, parser.locale());
625 
626  if (!converted)
628 
629  _storage.value.push_back(std::move(*converted));
630  }
631 
634  }
635 
637  set_value_result set_switch_value([[maybe_unused]] parser_type &parser) override
638  {
639  return set_switch_value_core();
640  }
641 
643  void apply_default_value() override
644  {
645  if (!this->has_value() && _storage.default_value)
646  {
647  _storage.value.push_back(*_storage.default_value);
648  }
649  }
650 
652  typename base_type::stream_type &write_default_value(typename base_type::stream_type &stream) const override
653  {
654  if (_storage.default_value)
655  {
656  stream << *_storage.default_value;
657  }
658 
659  return stream;
660  }
661 
663  bool has_default_value() const noexcept override
664  {
665  return _storage.default_value.has_value();
666  }
667 
668  private:
669  template<typename T2 = element_type>
670  std::enable_if_t<details::is_switch<T2>::value, set_value_result> set_switch_value_core()
671  {
672  _storage.value.push_back(true);
675  }
676 
677  template<typename T2 = element_type>
678  std::enable_if_t<!details::is_switch<T2>::value, set_value_result> set_switch_value_core()
679  {
681  }
682 
683  typed_storage_type _storage;
684  };
685 
698  template<class T, typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
699  class action_command_line_argument final : public command_line_argument_base<CharType, Traits, Alloc>
700  {
701  public:
705  using value_type = T;
710  using element_type = T;
716  using typed_storage_type = details::action_argument_storage<value_type, CharType, Traits, Alloc>;
718  using function_type = typename typed_storage_type::function_type;
721 
730  typed_storage_type &&typed_storage)
731  : base_type{parser, std::move(storage)},
732  _storage{std::move(typed_storage)}
733  {
734  }
735 
741  bool is_switch() const noexcept override
742  {
743  return details::is_switch<T>::value;
744  }
745 
748  {
749  std::optional<element_type> converted;
750  if (_storage.converter)
751  converted = _storage.converter(value, parser.locale());
752  else
754 
755  if (!converted)
757 
759  return invoke_action(*converted, parser);
760  }
761 
764  {
765  return set_switch_value_core(parser);
766  }
767 
769  void apply_default_value() override
770  {
771  // Does nothing; action arguments cannot have a default value.
772  }
773 
775  typename base_type::stream_type &write_default_value(typename base_type::stream_type &stream) const override
776  {
777  // Does nothing; action arguments cannot have a default value.
778  return stream;
779  }
780 
782  bool has_default_value() const noexcept override
783  {
784  return false;
785  }
786 
787  private:
788  set_value_result invoke_action(const T &value, parser_type &parser)
789  {
790  bool result = _storage.action(value, parser);
792  }
793 
794  template<typename T2 = T>
795  std::enable_if_t<details::is_switch<T2>::value, set_value_result> set_switch_value_core(parser_type &parser)
796  {
798  return invoke_action(true, parser);
799  }
800 
801  template<typename T2 = T>
802  std::enable_if_t<!details::is_switch<T2>::value, set_value_result> set_switch_value_core(parser_type &)
803  {
805  }
806 
807  typed_storage_type _storage;
808  };
809 
810 }
811 
812 #endif
Class that provides information about action arguments.
Definition: command_line_argument.h:700
bool is_switch() const noexcept override
Gets a value that indicates whether the argument is a switch, which means it can be supplied without ...
Definition: command_line_argument.h:741
typename base_type::string_view_type string_view_type
The concrete type of std::basic_string_view used.
Definition: command_line_argument.h:714
details::action_argument_storage< value_type, CharType, Traits, Alloc > typed_storage_type
The concrete type of argument information storage used. For internal use.
Definition: command_line_argument.h:716
bool has_default_value() const noexcept override
Gets a value that indicates whether this argument has a default value.
Definition: command_line_argument.h:782
T value_type
The type of the argument's value, which equals T.
Definition: command_line_argument.h:705
void apply_default_value() override
Sets the variable holding the argument's value to the default value.
Definition: command_line_argument.h:769
set_value_result set_switch_value(parser_type &parser) override
Applies the implicit value for a switch argument.
Definition: command_line_argument.h:763
action_command_line_argument(const typename base_type::parser_type &parser, typename base_type::storage_type &&storage, typed_storage_type &&typed_storage)
Initializes a new instance of the command_line_argument class.
Definition: command_line_argument.h:729
set_value_result set_value(string_view_type value, parser_type &parser) override
Used to indicate that the argument has a value.
Definition: command_line_argument.h:747
base_type::stream_type & write_default_value(typename base_type::stream_type &stream) const override
Writes the default value to the specified stream.
Definition: command_line_argument.h:775
typename base_type::string_type string_type
The concrete type of std::basic_string used.
Definition: command_line_argument.h:712
typename typed_storage_type::function_type function_type
The type of the function used by this action argument.
Definition: command_line_argument.h:718
typename base_type::parser_type parser_type
The concrete type of basic_command_line_parser used.
Definition: command_line_argument.h:720
T element_type
The type of the argument's elements, which equals T.
Definition: command_line_argument.h:710
Parses command line arguments into strongly-typed values.
Definition: command_line_parser.h:106
parsing_mode mode() const noexcept
Gets the parsing mode used by this parser.
Definition: command_line_parser.h:243
const std::vector< string_type > & prefixes() const noexcept
Gets a list of all the argument name prefixes accepted by the parser.
Definition: command_line_parser.h:293
const string_type & long_prefix() const noexcept
Gets the long argument prefix.
Definition: command_line_parser.h:303
Abstract base class for regular and multi-value arguments.
Definition: command_line_argument.h:108
virtual void reset()
Resets the argument to indicate it hasn't been set.
Definition: command_line_argument.h:316
void set_value() noexcept
Used to indicate that the argument has a value.
Definition: command_line_argument.h:371
bool has_long_name() const noexcept
Gets a value that indicates whether the argument has a long name.
Definition: command_line_argument.h:160
const string_type & description() const noexcept
Gets the long description of the argument.
Definition: command_line_argument.h:241
const std::vector< string_type > & aliases() const noexcept
Gets a list of aliases that can be used instead of the argument's name.
Definition: command_line_argument.h:200
CharType short_name() const noexcept
Gets the short name of the argument, or a NULL character if it doesn't have one.
Definition: command_line_argument.h:144
const storage_type & base_storage() const
Provides access to the storage fields to derived classes.
Definition: command_line_argument.h:377
typename storage_type::string_type string_type
The concrete type of std::basic_string used.
Definition: command_line_argument.h:113
virtual bool has_default_value() const noexcept=0
Gets a value that indicates whether this argument has a default value.
virtual bool is_multi_value() const noexcept
Gets a value that indicates whether the argument can be provided more than once, collecting all the s...
Definition: command_line_argument.h:305
virtual bool is_switch() const noexcept=0
Gets a value that indicates whether the argument is a switch, which means it can be supplied without ...
const string_type & value_description() const noexcept
Gets the value description for the argument.
Definition: command_line_argument.h:227
string_view_type short_or_long_name() const
Gets the short name if the argument has one, otherwise the long name.
Definition: command_line_argument.h:169
virtual set_value_result set_value(string_view_type value, parser_type &parser)=0
Sets the argument to the specified value.
std::optional< size_t > position() const noexcept
Gets the position of the argument.
Definition: command_line_argument.h:254
const string_type & name() const noexcept
Gets the name of the argument.
Definition: command_line_argument.h:133
virtual stream_type & write_default_value(stream_type &stream) const =0
Writes the default value to the specified stream.
basic_command_line_parser< CharType, Traits, Alloc > parser_type
The concrete type of basic_command_line_parser used.
Definition: command_line_argument.h:119
bool has_value() const noexcept
Gets a value that indicates whether the argument was specified on the last invocation of basic_comman...
Definition: command_line_argument.h:290
virtual void apply_default_value()=0
Sets the variable holding the argument's value to the default value.
const std::vector< CharType > & short_aliases() const noexcept
Gets a list of short aliases that can be used instead of the argument's name.
Definition: command_line_argument.h:213
std::basic_string_view< CharType, Traits > string_view_type
The concrete type of std::basic_string_view used.
Definition: command_line_argument.h:115
command_line_argument_base(const parser_type &parser, storage_type &&storage)
Constructs a command line argument base from a command_line_argument_storage.
Definition: command_line_argument.h:385
string_type name_with_prefix(const parser_type &parser) const
Gets the argument name with the appropriate prefix.
Definition: command_line_argument.h:183
bool cancel_parsing() const noexcept
Gets a value that indicates whether supplying this argument will cancel parsing.
Definition: command_line_argument.h:280
std::basic_ostream< CharType, Traits > stream_type
The concrete type of std::basic_ostream used.
Definition: command_line_argument.h:117
details::argument_storage< CharType, Traits, Alloc > storage_type
The concrete type of argument information storage used. For internal use.
Definition: command_line_argument.h:111
bool is_required() const noexcept
Gets a value that indicates whether the argument is required.
Definition: command_line_argument.h:264
virtual set_value_result set_switch_value(parser_type &parser)=0
Applies the implicit value for a switch argument.
bool has_short_name() const noexcept
Gets a value that indicates whether the argument has a short name.
Definition: command_line_argument.h:152
Class that provides information about arguments that are not multi-value arguments.
Definition: command_line_argument.h:432
T value_type
The type of the argument's value, which equals T.
Definition: command_line_argument.h:437
details::typed_argument_storage< value_type, element_type, CharType, Traits > typed_storage_type
The concrete type of argument information storage used. For internal use.
Definition: command_line_argument.h:448
command_line_argument(const typename base_type::parser_type &parser, typename base_type::storage_type &&storage, typed_storage_type &&typed_storage)
Initializes a new instance of the command_line_argument class.
Definition: command_line_argument.h:459
typename base_type::string_type string_type
The concrete type of std::basic_string used.
Definition: command_line_argument.h:444
typename base_type::parser_type parser_type
The concrete type of basic_command_line_parser used.
Definition: command_line_argument.h:450
typename details::element_type< T >::type element_type
The type of the argument's elements, which equals T.
Definition: command_line_argument.h:442
void apply_default_value() override
Sets the variable holding the argument's value to the default value.
Definition: command_line_argument.h:500
bool is_switch() const noexcept override
Gets a value that indicates whether the argument is a switch, which means it can be supplied without ...
Definition: command_line_argument.h:471
bool has_default_value() const noexcept override
Gets a value that indicates whether this argument has a default value.
Definition: command_line_argument.h:520
typename base_type::string_view_type string_view_type
The concrete type of std::basic_string_view used.
Definition: command_line_argument.h:446
set_value_result set_switch_value([[maybe_unused]] parser_type &parser) override
Applies the implicit value for a switch argument.
Definition: command_line_argument.h:494
set_value_result set_value(string_view_type value, parser_type &parser) override
Used to indicate that the argument has a value.
Definition: command_line_argument.h:477
base_type::stream_type & write_default_value(typename base_type::stream_type &stream) const override
Writes the default value to the specified stream.
Definition: command_line_argument.h:509
Class that provides information about arguments that are not multi-value arguments.
Definition: command_line_argument.h:554
set_value_result set_value(string_view_type value, parser_type &parser) override
Used to indicate that the argument has a value.
Definition: command_line_argument.h:616
bool is_switch() const noexcept override
Gets a value that indicates whether the argument is a switch, which means it can be supplied without ...
Definition: command_line_argument.h:586
typename T::value_type element_type
The type of the argument's container's elements.
Definition: command_line_argument.h:561
typename base_type::string_type string_type
The concrete type of std::basic_string used.
Definition: command_line_argument.h:563
typename base_type::string_view_type string_view_type
The concrete type of std::basic_string_view used.
Definition: command_line_argument.h:565
void reset() override
Resets the argument to indicate it hasn't been set.
Definition: command_line_argument.h:609
typename base_type::parser_type parser_type
The concrete type of basic_command_line_parser used.
Definition: command_line_argument.h:569
details::typed_argument_storage< T, element_type, CharType, Traits > typed_storage_type
The concrete type of argument information storage used. For internal use.
Definition: command_line_argument.h:567
multi_value_command_line_argument(const typename base_type::parser_type &parser, typename base_type::storage_type &&storage, typed_storage_type &&typed_storage)
Initializes a new instance of the multi_value_command_line_argument class.
Definition: command_line_argument.h:578
T value_type
The type of the argument's container, which equals T.
Definition: command_line_argument.h:559
bool is_multi_value() const noexcept override
Gets a value that indicates whether the argument can be provided more than once, collecting all the s...
Definition: command_line_argument.h:594
set_value_result set_switch_value([[maybe_unused]] parser_type &parser) override
Applies the implicit value for a switch argument.
Definition: command_line_argument.h:637
CharType separator() const noexcept
Gets the character used to separate multiple values in a single argument value, or '\0' if no separat...
Definition: command_line_argument.h:603
void apply_default_value() override
Sets the variable holding the argument's value to the default value.
Definition: command_line_argument.h:643
bool has_default_value() const noexcept override
Gets a value that indicates whether this argument has a default value.
Definition: command_line_argument.h:663
base_type::stream_type & write_default_value(typename base_type::stream_type &stream) const override
Writes the default value to the specified stream.
Definition: command_line_argument.h:652
A pseudo-range for string tokenization.
Definition: string_helper.h:264
Provides functionality for switch arguments.
Namespace containing the core Ookii.CommandLine.Cpp types.
Definition: command_line_argument.h:16
@ long_short
Use POSIX-like rules where arguments have separate long and short names.
set_value_result
The result of attempting to set a value for an argument.
Definition: command_line_argument.h:91
@ cancel
The operation was successful, but has requested that parsing will be cancelled.
@ success
The operation was successful.
@ error
There was an error converting the value to the element type of the argument.
@ cancel_parsing
Cancel parsing immediately, disregarding the rest of the command line. Parsing will return with parse...
Provides the ookii::parsing_mode enumeration.
static std::optional< T > from_string(std::basic_string_view< CharType, Traits > value, const std::locale &loc={})
Convert a string to the specified type.
Definition: string_helper.h:217
Template used to specify the default value description for a type.
Definition: value_description.h:30