cxxopts.hpp
Go to the documentation of this file.
1/*
2
3Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
22
23*/
24
25#ifndef CXXOPTS_HPP_INCLUDED
26#define CXXOPTS_HPP_INCLUDED
27
28#include <cctype>
29#include <cstring>
30#include <exception>
31#include <iostream>
32#include <map>
33#include <memory>
34#include <regex>
35#include <sstream>
36#include <string>
37#include <unordered_map>
38#include <unordered_set>
39#include <vector>
40
41#ifdef __cpp_lib_optional
42#include <optional>
43#define CXXOPTS_HAS_OPTIONAL
44#endif
45
46#define CXXOPTS__VERSION_MAJOR 2
47#define CXXOPTS__VERSION_MINOR 2
48#define CXXOPTS__VERSION_PATCH 0
49
50namespace cxxopts
51{
52 static constexpr struct
53 {
54 uint8_t major, minor, patch;
56} // namespace cxxopts
57
58//when we ask cxxopts to use Unicode, help strings are processed using ICU,
59//which results in the correct lengths being computed for strings when they
60//are formatted for the help output
61//it is necessary to make sure that <unicode/unistr.h> can be found by the
62//compiler, and that icu-uc is linked in to the binary.
63
64#ifdef CXXOPTS_USE_UNICODE
65#include <unicode/unistr.h>
66
67namespace cxxopts
68{
69 typedef icu::UnicodeString String;
70
71 inline String
72 toLocalString(std::string s)
73 {
74 return icu::UnicodeString::fromUTF8(std::move(s));
75 }
76
77 class UnicodeStringIterator : public std::iterator<std::forward_iterator_tag, int32_t>
78 {
79 public:
80 UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos) : s(string), i(pos)
81 {
82 }
83
84 value_type
85 operator*() const
86 {
87 return s->char32At(i);
88 }
89
90 bool
91 operator==(const UnicodeStringIterator& rhs) const
92 {
93 return s == rhs.s && i == rhs.i;
94 }
95
96 bool
97 operator!=(const UnicodeStringIterator& rhs) const
98 {
99 return !(*this == rhs);
100 }
101
102 UnicodeStringIterator&
103 operator++()
104 {
105 ++i;
106 return *this;
107 }
108
109 UnicodeStringIterator
110 operator+(int32_t v)
111 {
112 return UnicodeStringIterator(s, i + v);
113 }
114
115 private:
116 const icu::UnicodeString* s;
117 int32_t i;
118 };
119
120 inline String&
122 {
123 return s.append(std::move(a));
124 }
125
126 inline String&
127 stringAppend(String& s, int n, UChar32 c)
128 {
129 for (int i = 0; i != n; ++i)
130 {
131 s.append(c);
132 }
133
134 return s;
135 }
136
137 template <typename Iterator>
138 String&
139 stringAppend(String& s, Iterator begin, Iterator end)
140 {
141 while (begin != end)
142 {
143 s.append(*begin);
144 ++begin;
145 }
146
147 return s;
148 }
149
150 inline size_t
151 stringLength(const String& s)
152 {
153 return s.length();
154 }
155
156 inline std::string
157 toUTF8String(const String& s)
158 {
159 std::string result;
160 s.toUTF8String(result);
161
162 return result;
163 }
164
165 inline bool
166 empty(const String& s)
167 {
168 return s.isEmpty();
169 }
170} // namespace cxxopts
171
172namespace std
173{
174 inline cxxopts::UnicodeStringIterator
175 begin(const icu::UnicodeString& s)
176 {
177 return cxxopts::UnicodeStringIterator(&s, 0);
178 }
179
180 inline cxxopts::UnicodeStringIterator
181 end(const icu::UnicodeString& s)
182 {
183 return cxxopts::UnicodeStringIterator(&s, s.length());
184 }
185} // namespace std
186
187//ifdef CXXOPTS_USE_UNICODE
188#else
189
190namespace cxxopts
191{
192 typedef std::string String;
193
194 template <typename T>
195 T
197 {
198 return std::forward<T>(t);
199 }
200
201 inline size_t
203 {
204 return s.length();
205 }
206
207 inline String&
209 {
210 return s.append(std::move(a));
211 }
212
213 inline String&
214 stringAppend(String& s, size_t n, char c)
215 {
216 return s.append(n, c);
217 }
218
219 template <typename Iterator>
220 String&
221 stringAppend(String& s, Iterator begin, Iterator end)
222 {
223 return s.append(begin, end);
224 }
225
226 template <typename T>
227 std::string
229 {
230 return std::forward<T>(t);
231 }
232
233 inline bool
234 empty(const std::string& s)
235 {
236 return s.empty();
237 }
238} // namespace cxxopts
239
240//ifdef CXXOPTS_USE_UNICODE
241#endif
242
243namespace cxxopts
244{
245 namespace
246 {
247#ifdef _WIN32
248 const std::string LQUOTE("\'");
249 const std::string RQUOTE("\'");
250#else
251 const std::string LQUOTE("‘");
252 const std::string RQUOTE("’");
253#endif
254 } // namespace
255
256 class Value : public std::enable_shared_from_this<Value>
257 {
258 public:
259 virtual ~Value() = default;
260
261 virtual std::shared_ptr<Value> clone() const = 0;
262
263 virtual void parse(const std::string& text) const = 0;
264
265 virtual void parse() const = 0;
266
267 virtual bool has_default() const = 0;
268
269 virtual bool is_container() const = 0;
270
271 virtual bool has_implicit() const = 0;
272
273 virtual std::string get_default_value() const = 0;
274
275 virtual std::string get_implicit_value() const = 0;
276
277 virtual std::shared_ptr<Value> default_value(const std::string& value) = 0;
278
279 virtual std::shared_ptr<Value> implicit_value(const std::string& value) = 0;
280
281 virtual bool is_boolean() const = 0;
282 };
283
284 class OptionException : public std::exception
285 {
286 public:
287 OptionException(const std::string& message) : m_message(message)
288 {
289 }
290
291 virtual const char*
292 what() const noexcept
293 {
294 return m_message.c_str();
295 }
296
297 private:
298 std::string m_message;
299 };
300
302 {
303 public:
304 OptionSpecException(const std::string& message) : OptionException(message)
305 {
306 }
307 };
308
310 {
311 public:
312 OptionParseException(const std::string& message) : OptionException(message)
313 {
314 }
315 };
316
318 {
319 public:
320 option_exists_error(const std::string& option) :
321 OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists")
322 {
323 }
324 };
325
327 {
328 public:
329 invalid_option_format_error(const std::string& format) :
330 OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE)
331 {
332 }
333 };
334
336 {
337 public:
338 option_syntax_exception(const std::string& text) :
339 OptionParseException("Argument " + LQUOTE + text + RQUOTE +
340 " starts with a - but has incorrect syntax")
341 {
342 }
343 };
344
346 {
347 public:
349 OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist")
350 {
351 }
352 };
353
355 {
356 public:
357 missing_argument_exception(const std::string& option) :
358 OptionParseException("Option " + LQUOTE + option + RQUOTE + " is missing an argument")
359 {
360 }
361 };
362
364 {
365 public:
367 OptionParseException("Option " + LQUOTE + option + RQUOTE + " requires an argument")
368 {
369 }
370 };
371
373 {
374 public:
375 option_not_has_argument_exception(const std::string& option, const std::string& arg) :
376 OptionParseException("Option " + LQUOTE + option + RQUOTE +
377 " does not take an argument, but argument " + LQUOTE + arg +
378 RQUOTE + " given")
379 {
380 }
381 };
382
384 {
385 public:
387 OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present")
388 {
389 }
390 };
391
393 {
394 public:
395 argument_incorrect_type(const std::string& arg) :
396 OptionParseException("Argument " + LQUOTE + arg + RQUOTE + " failed to parse")
397 {
398 }
399 };
400
402 {
403 public:
404 option_required_exception(const std::string& option) :
405 OptionParseException("Option " + LQUOTE + option + RQUOTE +
406 " is required but not present")
407 {
408 }
409 };
410
411 namespace values
412 {
413 namespace
414 {
415 std::basic_regex<char> integer_pattern("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
416 std::basic_regex<char> truthy_pattern("(t|T)(rue)?");
417 std::basic_regex<char> falsy_pattern("((f|F)(alse)?)?");
418 } // namespace
419
420 namespace detail
421 {
422 template <typename T, bool B>
424
425 template <typename T>
426 struct SignedCheck<T, true>
427 {
428 template <typename U>
429 void
430 operator()(bool negative, U u, const std::string& text)
431 {
432 if (negative)
433 {
434 if (u > static_cast<U>(-(std::numeric_limits<T>::min)()))
435 {
436 throw argument_incorrect_type(text);
437 }
438 }
439 else
440 {
441 if (u > static_cast<U>((std::numeric_limits<T>::max)()))
442 {
443 throw argument_incorrect_type(text);
444 }
445 }
446 }
447 };
448
449 template <typename T>
450 struct SignedCheck<T, false>
451 {
452 template <typename U>
453 void
454 operator()(bool, U, const std::string&)
455 {
456 }
457 };
458
459 template <typename T, typename U>
460 void
461 check_signed_range(bool negative, U value, const std::string& text)
462 {
464 }
465 } // namespace detail
466
467 template <typename R, typename T>
468 R
469 checked_negate(T&& t, const std::string&, std::true_type)
470 {
471 // if we got to here, then `t` is a positive number that fits into
472 // `R`. So to avoid MSVC C4146, we first cast it to `R`.
473 // See https://github.com/jarro2783/cxxopts/issues/62 for more details.
474 return -static_cast<R>(t);
475 }
476
477 template <typename R, typename T>
478 T
479 checked_negate(T&&, const std::string& text, std::false_type)
480 {
481 throw argument_incorrect_type(text);
482 }
483
484 template <typename T>
485 void
486 integer_parser(const std::string& text, T& value)
487 {
488 std::smatch match;
489 std::regex_match(text, match, integer_pattern);
490
491 if (match.length() == 0)
492 {
493 throw argument_incorrect_type(text);
494 }
495
496 if (match.length(4) > 0)
497 {
498 value = 0;
499 return;
500 }
501
502 using US = typename std::make_unsigned<T>::type;
503
504 constexpr auto umax = (std::numeric_limits<US>::max)();
505 constexpr bool is_signed = std::numeric_limits<T>::is_signed;
506 const bool negative = match.length(1) > 0;
507 const uint8_t base = match.length(2) > 0 ? 16 : 10;
508
509 auto value_match = match[3];
510
511 US result = 0;
512
513 for (auto iter = value_match.first; iter != value_match.second; ++iter)
514 {
515 US digit = 0;
516
517 if (*iter >= '0' && *iter <= '9')
518 {
519 digit = *iter - '0';
520 }
521 else if (base == 16 && *iter >= 'a' && *iter <= 'f')
522 {
523 digit = *iter - 'a' + 10;
524 }
525 else if (base == 16 && *iter >= 'A' && *iter <= 'F')
526 {
527 digit = *iter - 'A' + 10;
528 }
529 else
530 {
531 throw argument_incorrect_type(text);
532 }
533
534 if (umax - digit < result * base)
535 {
536 throw argument_incorrect_type(text);
537 }
538
539 result = result * base + digit;
540 }
541
542 detail::check_signed_range<T>(negative, result, text);
543
544 if (negative)
545 {
546 value = checked_negate<T>(result, text, std::integral_constant<bool, is_signed>());
547 }
548 else
549 {
550 value = result;
551 }
552 }
553
554 template <typename T>
555 void
556 stringstream_parser(const std::string& text, T& value)
557 {
558 std::stringstream in(text);
559 in >> value;
560 if (!in)
561 {
562 throw argument_incorrect_type(text);
563 }
564 }
565
566 inline void
567 parse_value(const std::string& text, uint8_t& value)
568 {
569 integer_parser(text, value);
570 }
571
572 inline void
573 parse_value(const std::string& text, int8_t& value)
574 {
575 integer_parser(text, value);
576 }
577
578 inline void
579 parse_value(const std::string& text, uint16_t& value)
580 {
581 integer_parser(text, value);
582 }
583
584 inline void
585 parse_value(const std::string& text, int16_t& value)
586 {
587 integer_parser(text, value);
588 }
589
590 inline void
591 parse_value(const std::string& text, uint32_t& value)
592 {
593 integer_parser(text, value);
594 }
595
596 inline void
597 parse_value(const std::string& text, int32_t& value)
598 {
599 integer_parser(text, value);
600 }
601
602 inline void
603 parse_value(const std::string& text, uint64_t& value)
604 {
605 integer_parser(text, value);
606 }
607
608 inline void
609 parse_value(const std::string& text, int64_t& value)
610 {
611 integer_parser(text, value);
612 }
613
614 inline void
615 parse_value(const std::string& text, bool& value)
616 {
617 std::smatch result;
618 std::regex_match(text, result, truthy_pattern);
619
620 if (!result.empty())
621 {
622 value = true;
623 return;
624 }
625
626 std::regex_match(text, result, falsy_pattern);
627 if (!result.empty())
628 {
629 value = false;
630 return;
631 }
632
633 throw argument_incorrect_type(text);
634 }
635
636 inline void
637 parse_value(const std::string& text, std::string& value)
638 {
639 value = text;
640 }
641
642 // The fallback parser. It uses the stringstream parser to parse all types
643 // that have not been overloaded explicitly. It has to be placed in the
644 // source code before all other more specialized templates.
645 template <typename T>
646 void
647 parse_value(const std::string& text, T& value)
648 {
650 }
651
652 template <typename T>
653 void
654 parse_value(const std::string& text, std::vector<T>& value)
655 {
656 T v;
657 parse_value(text, v);
658 value.push_back(v);
659 }
660
661#ifdef CXXOPTS_HAS_OPTIONAL
662 template <typename T>
663 void
664 parse_value(const std::string& text, std::optional<T>& value)
665 {
666 T result;
667 parse_value(text, result);
668 value = std::move(result);
669 }
670#endif
671
672 template <typename T>
674 {
675 static constexpr bool value = false;
676 };
677
678 template <typename T>
679 struct type_is_container<std::vector<T>>
680 {
681 static constexpr bool value = true;
682 };
683
684 template <typename T>
685 class abstract_value : public Value
686 {
687 using Self = abstract_value<T>;
688
689 public:
690 abstract_value() : m_result(std::make_shared<T>()), m_store(m_result.get())
691 {
692 }
693
695 {
696 }
697
698 virtual ~abstract_value() = default;
699
701 {
702 if (rhs.m_result)
703 {
704 m_result = std::make_shared<T>();
705 m_store = m_result.get();
706 }
707 else
708 {
709 m_store = rhs.m_store;
710 }
711
712 m_default = rhs.m_default;
716 }
717
718 void
719 parse(const std::string& text) const
720 {
721 parse_value(text, *m_store);
722 }
723
724 bool
726 {
728 }
729
730 void
731 parse() const
732 {
734 }
735
736 bool
738 {
739 return m_default;
740 }
741
742 bool
744 {
745 return m_implicit;
746 }
747
748 std::shared_ptr<Value>
749 default_value(const std::string& value)
750 {
751 m_default = true;
753 return shared_from_this();
754 }
755
756 std::shared_ptr<Value>
757 implicit_value(const std::string& value)
758 {
759 m_implicit = true;
761 return shared_from_this();
762 }
763
764 std::string
766 {
767 return m_default_value;
768 }
769
770 std::string
772 {
773 return m_implicit_value;
774 }
775
776 bool
778 {
779 return std::is_same<T, bool>::value;
780 }
781
782 const T&
783 get() const
784 {
785 if (m_store == nullptr)
786 {
787 return *m_result;
788 }
789 else
790 {
791 return *m_store;
792 }
793 }
794
795 protected:
796 std::shared_ptr<T> m_result;
798
799 bool m_default = false;
800 bool m_implicit = false;
801
802 std::string m_default_value;
803 std::string m_implicit_value;
804 };
805
806 template <typename T>
808 {
809 public:
811
812 std::shared_ptr<Value>
813 clone() const
814 {
815 return std::make_shared<standard_value<T>>(*this);
816 }
817 };
818
819 template <>
820 class standard_value<bool> : public abstract_value<bool>
821 {
822 public:
823 ~standard_value() = default;
824
826 {
827 set_default_and_implicit();
828 }
829
831 {
832 set_default_and_implicit();
833 }
834
835 std::shared_ptr<Value>
836 clone() const
837 {
838 return std::make_shared<standard_value<bool>>(*this);
839 }
840
841 private:
842 void
843 set_default_and_implicit()
844 {
845 m_default = true;
846 m_default_value = "false";
847 m_implicit = true;
848 m_implicit_value = "true";
849 }
850 };
851 } // namespace values
852
853 template <typename T>
854 std::shared_ptr<Value>
856 {
857 return std::make_shared<values::standard_value<T>>();
858 }
859
860 template <typename T>
861 std::shared_ptr<Value>
863 {
864 return std::make_shared<values::standard_value<T>>(&t);
865 }
866
867 class OptionAdder;
868
870 {
871 public:
872 OptionDetails(const std::string& short_,
873 const std::string& long_,
874 const String& desc,
875 std::shared_ptr<const Value> val) :
876 m_short(short_), m_long(long_), m_desc(desc), m_value(val), m_count(0)
877 {
878 }
879
880 OptionDetails(const OptionDetails& rhs) : m_desc(rhs.m_desc), m_count(rhs.m_count)
881 {
882 m_value = rhs.m_value->clone();
883 }
884
885 OptionDetails(OptionDetails&& rhs) = default;
886
887 const String&
889 {
890 return m_desc;
891 }
892
893 const Value&
894 value() const
895 {
896 return *m_value;
897 }
898
899 std::shared_ptr<Value>
901 {
902 return m_value->clone();
903 }
904
905 const std::string&
907 {
908 return m_short;
909 }
910
911 const std::string&
912 long_name() const
913 {
914 return m_long;
915 }
916
917 private:
918 std::string m_short;
919 std::string m_long;
920 String m_desc;
921 std::shared_ptr<const Value> m_value;
922 int m_count;
923 };
924
926 {
927 std::string s;
928 std::string l;
931 std::string default_value;
933 std::string implicit_value;
934 std::string arg_help;
937 };
938
940 {
941 std::string name;
942 std::string description;
943 std::vector<HelpOptionDetails> options;
944 };
945
947 {
948 public:
949 void
950 parse(std::shared_ptr<const OptionDetails> details, const std::string& text)
951 {
952 ensure_value(details);
953 ++m_count;
954 m_value->parse(text);
955 }
956
957 void
958 parse_default(std::shared_ptr<const OptionDetails> details)
959 {
960 ensure_value(details);
961 m_value->parse();
962 }
963
964 size_t
965 count() const
966 {
967 return m_count;
968 }
969
970 template <typename T>
971 const T&
972 as() const
973 {
974 if (m_value == nullptr)
975 {
976 throw std::domain_error("No value");
977 }
978
979#ifdef CXXOPTS_NO_RTTI
980 return static_cast<const values::standard_value<T>&>(*m_value).get();
981#else
982 return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
983#endif
984 }
985
986 private:
987 void
988 ensure_value(std::shared_ptr<const OptionDetails> details)
989 {
990 if (m_value == nullptr)
991 {
992 m_value = details->make_storage();
993 }
994 }
995
996 std::shared_ptr<Value> m_value;
997 size_t m_count = 0;
998 };
999
1001 {
1002 public:
1003 KeyValue(std::string key_, std::string value_) :
1004 m_key(std::move(key_)), m_value(std::move(value_))
1005 {
1006 }
1007
1008 const std::string&
1009 key() const
1010 {
1011 return m_key;
1012 }
1013
1014 const std::string&
1015 value() const
1016 {
1017 return m_value;
1018 }
1019
1020 template <typename T>
1021 T
1022 as() const
1023 {
1024 T result;
1025 values::parse_value(m_value, result);
1026 return result;
1027 }
1028
1029 private:
1030 std::string m_key;
1031 std::string m_value;
1032 };
1033
1035 {
1036 public:
1038 const std::shared_ptr<std::unordered_map<std::string, std::shared_ptr<OptionDetails>>>,
1039 std::vector<std::string>,
1040 bool allow_unrecognised,
1041 int&,
1042 char**&);
1043
1044 size_t
1045 count(const std::string& o) const
1046 {
1047 auto iter = m_options->find(o);
1048 if (iter == m_options->end())
1049 {
1050 return 0;
1051 }
1052
1053 auto riter = m_results.find(iter->second);
1054
1055 return riter->second.count();
1056 }
1057
1058 const OptionValue&
1059 operator[](const std::string& option) const
1060 {
1061 auto iter = m_options->find(option);
1062
1063 if (iter == m_options->end())
1064 {
1066 }
1067
1068 auto riter = m_results.find(iter->second);
1069
1070 return riter->second;
1071 }
1072
1073 const std::vector<KeyValue>&
1075 {
1076 return m_sequential;
1077 }
1078
1079 private:
1080 void parse(int& argc, char**& argv);
1081
1082 void add_to_option(const std::string& option, const std::string& arg);
1083
1084 bool consume_positional(std::string a);
1085
1086 void parse_option(std::shared_ptr<OptionDetails> value,
1087 const std::string& name,
1088 const std::string& arg = "");
1089
1090 void parse_default(std::shared_ptr<OptionDetails> details);
1091
1092 void checked_parse_arg(int argc,
1093 char* argv[],
1094 int& current,
1095 std::shared_ptr<OptionDetails> value,
1096 const std::string& name);
1097
1098 const std::shared_ptr<std::unordered_map<std::string, std::shared_ptr<OptionDetails>>>
1099 m_options;
1100 std::vector<std::string> m_positional;
1101 std::vector<std::string>::iterator m_next_positional;
1102 std::unordered_set<std::string> m_positional_set;
1103 std::unordered_map<std::shared_ptr<OptionDetails>, OptionValue> m_results;
1104
1105 bool m_allow_unrecognised;
1106
1107 std::vector<KeyValue> m_sequential;
1108 };
1109
1111 {
1112 typedef std::unordered_map<std::string, std::shared_ptr<OptionDetails>> OptionMap;
1113
1114 public:
1115 Options(std::string program, std::string help_string = "") :
1116 m_program(std::move(program)),
1117 m_help_string(toLocalString(std::move(help_string))),
1118 m_custom_help("[OPTION...]"),
1119 m_positional_help("positional parameters"),
1120 m_show_positional(false),
1121 m_allow_unrecognised(false),
1122 m_options(std::make_shared<OptionMap>()),
1123 m_next_positional(m_positional.end())
1124 {
1125 }
1126
1127 Options&
1128 positional_help(std::string help_text)
1129 {
1130 m_positional_help = std::move(help_text);
1131 return *this;
1132 }
1133
1134 Options&
1135 custom_help(std::string help_text)
1136 {
1137 m_custom_help = std::move(help_text);
1138 return *this;
1139 }
1140
1141 Options&
1143 {
1144 m_show_positional = true;
1145 return *this;
1146 }
1147
1148 Options&
1150 {
1151 m_allow_unrecognised = true;
1152 return *this;
1153 }
1154
1155 ParseResult parse(int& argc, char**& argv);
1156
1157 OptionAdder add_options(std::string group = "");
1158
1159 void add_option(const std::string& group,
1160 const std::string& s,
1161 const std::string& l,
1162 std::string desc,
1163 std::shared_ptr<const Value> value,
1164 std::string arg_help);
1165
1166 //parse positional arguments into the given option
1167 void parse_positional(std::string option);
1168
1169 void parse_positional(std::vector<std::string> options);
1170
1171 void parse_positional(std::initializer_list<std::string> options);
1172
1173 template <typename Iterator>
1174 void
1175 parse_positional(Iterator begin, Iterator end)
1176 {
1177 parse_positional(std::vector<std::string>{begin, end});
1178 }
1179
1180 std::string help(const std::vector<std::string>& groups = {}) const;
1181
1182 const std::vector<std::string> groups() const;
1183
1184 const HelpGroupDetails& group_help(const std::string& group) const;
1185
1186 private:
1187 void add_one_option(const std::string& option, std::shared_ptr<OptionDetails> details);
1188
1189 String help_one_group(const std::string& group) const;
1190
1191 void generate_group_help(String& result, const std::vector<std::string>& groups) const;
1192
1193 void generate_all_groups_help(String& result) const;
1194
1195 std::string m_program;
1196 String m_help_string;
1197 std::string m_custom_help;
1198 std::string m_positional_help;
1199 bool m_show_positional;
1200 bool m_allow_unrecognised;
1201
1202 std::shared_ptr<OptionMap> m_options;
1203 std::vector<std::string> m_positional;
1204 std::vector<std::string>::iterator m_next_positional;
1205 std::unordered_set<std::string> m_positional_set;
1206
1207 //mapping from groups to help options
1208 std::map<std::string, HelpGroupDetails> m_help;
1209 };
1210
1212 {
1213 public:
1214 OptionAdder(Options& options, std::string group) :
1215 m_options(options), m_group(std::move(group))
1216 {
1217 }
1218
1219 OptionAdder& operator()(const std::string& opts,
1220 const std::string& desc,
1221 std::shared_ptr<const Value> value = ::cxxopts::value<bool>(),
1222 std::string arg_help = "");
1223
1224 private:
1225 Options& m_options;
1226 std::string m_group;
1227 };
1228
1229 namespace
1230 {
1231 constexpr int OPTION_LONGEST = 30;
1232 constexpr int OPTION_DESC_GAP = 2;
1233
1234 std::basic_regex<char>
1235 option_matcher("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
1236
1237 std::basic_regex<char>
1238 option_specifier("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
1239
1240 String
1241 format_option(const HelpOptionDetails& o)
1242 {
1243 auto& s = o.s;
1244 auto& l = o.l;
1245
1246 String result = " ";
1247
1248 if (s.size() > 0)
1249 {
1250 result += "-" + toLocalString(s) + ",";
1251 }
1252 else
1253 {
1254 result += " ";
1255 }
1256
1257 if (l.size() > 0)
1258 {
1259 result += " --" + toLocalString(l);
1260 }
1261
1262 auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg";
1263
1264 if (!o.is_boolean)
1265 {
1266 if (o.has_implicit)
1267 {
1268 result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
1269 }
1270 else
1271 {
1272 result += " " + arg;
1273 }
1274 }
1275
1276 return result;
1277 }
1278
1279 String
1280 format_description(const HelpOptionDetails& o, size_t start, size_t width)
1281 {
1282 auto desc = o.desc;
1283
1284 if (o.has_default && (!o.is_boolean || o.default_value != "false"))
1285 {
1286 desc += toLocalString(" (default: " + o.default_value + ")");
1287 }
1288
1289 String result;
1290
1291 auto current = std::begin(desc);
1292 auto startLine = current;
1293 auto lastSpace = current;
1294
1295 auto size = size_t{};
1296
1297 while (current != std::end(desc))
1298 {
1299 if (*current == ' ')
1300 {
1301 lastSpace = current;
1302 }
1303
1304 if (*current == '\n')
1305 {
1306 startLine = current + 1;
1307 lastSpace = startLine;
1308 }
1309 else if (size > width)
1310 {
1311 if (lastSpace == startLine)
1312 {
1313 stringAppend(result, startLine, current + 1);
1314 stringAppend(result, "\n");
1315 stringAppend(result, start, ' ');
1316 startLine = current + 1;
1317 lastSpace = startLine;
1318 }
1319 else
1320 {
1321 stringAppend(result, startLine, lastSpace);
1322 stringAppend(result, "\n");
1323 stringAppend(result, start, ' ');
1324 startLine = lastSpace + 1;
1325 }
1326 size = 0;
1327 }
1328 else
1329 {
1330 ++size;
1331 }
1332
1333 ++current;
1334 }
1335
1336 //append whatever is left
1337 stringAppend(result, startLine, current);
1338
1339 return result;
1340 }
1341 } // namespace
1342
1344 const std::shared_ptr<std::unordered_map<std::string, std::shared_ptr<OptionDetails>>>
1345 options,
1346 std::vector<std::string> positional,
1347 bool allow_unrecognised,
1348 int& argc,
1349 char**& argv) :
1350 m_options(options),
1351 m_positional(std::move(positional)),
1352 m_next_positional(m_positional.begin()),
1353 m_allow_unrecognised(allow_unrecognised)
1354 {
1355 parse(argc, argv);
1356 }
1357
1358 inline OptionAdder
1359 Options::add_options(std::string group)
1360 {
1361 return OptionAdder(*this, std::move(group));
1362 }
1363
1364 inline OptionAdder&
1365 OptionAdder::operator()(const std::string& opts,
1366 const std::string& desc,
1367 std::shared_ptr<const Value> value,
1368 std::string arg_help)
1369 {
1370 std::match_results<const char*> result;
1371 std::regex_match(opts.c_str(), result, option_specifier);
1372
1373 if (result.empty())
1374 {
1375 throw invalid_option_format_error(opts);
1376 }
1377
1378 const auto& short_match = result[2];
1379 const auto& long_match = result[3];
1380
1381 if (!short_match.length() && !long_match.length())
1382 {
1383 throw invalid_option_format_error(opts);
1384 }
1385 else if (long_match.length() == 1 && short_match.length())
1386 {
1387 throw invalid_option_format_error(opts);
1388 }
1389
1390 auto option_names =
1391 [](const std::sub_match<const char*>& short_, const std::sub_match<const char*>& long_)
1392 {
1393 if (long_.length() == 1)
1394 {
1395 return std::make_tuple(long_.str(), short_.str());
1396 }
1397 else
1398 {
1399 return std::make_tuple(short_.str(), long_.str());
1400 }
1401 }(short_match, long_match);
1402
1403 m_options.add_option(m_group,
1404 std::get<0>(option_names),
1405 std::get<1>(option_names),
1406 desc,
1407 value,
1408 std::move(arg_help));
1409
1410 return *this;
1411 }
1412
1413 inline void
1414 ParseResult::parse_default(std::shared_ptr<OptionDetails> details)
1415 {
1416 m_results[details].parse_default(details);
1417 }
1418
1419 inline void
1420 ParseResult::parse_option(std::shared_ptr<OptionDetails> value,
1421 const std::string& /*name*/,
1422 const std::string& arg)
1423 {
1424 auto& result = m_results[value];
1425 result.parse(value, arg);
1426
1427 m_sequential.emplace_back(value->long_name(), arg);
1428 }
1429
1430 inline void
1431 ParseResult::checked_parse_arg(int argc,
1432 char* argv[],
1433 int& current,
1434 std::shared_ptr<OptionDetails> value,
1435 const std::string& name)
1436 {
1437 if (current + 1 >= argc)
1438 {
1439 if (value->value().has_implicit())
1440 {
1441 parse_option(value, name, value->value().get_implicit_value());
1442 }
1443 else
1444 {
1445 throw missing_argument_exception(name);
1446 }
1447 }
1448 else
1449 {
1450 if (value->value().has_implicit())
1451 {
1452 parse_option(value, name, value->value().get_implicit_value());
1453 }
1454 else
1455 {
1456 parse_option(value, name, argv[current + 1]);
1457 ++current;
1458 }
1459 }
1460 }
1461
1462 inline void
1463 ParseResult::add_to_option(const std::string& option, const std::string& arg)
1464 {
1465 auto iter = m_options->find(option);
1466
1467 if (iter == m_options->end())
1468 {
1469 throw option_not_exists_exception(option);
1470 }
1471
1472 parse_option(iter->second, option, arg);
1473 }
1474
1475 inline bool
1476 ParseResult::consume_positional(std::string a)
1477 {
1478 while (m_next_positional != m_positional.end())
1479 {
1480 auto iter = m_options->find(*m_next_positional);
1481 if (iter != m_options->end())
1482 {
1483 auto& result = m_results[iter->second];
1484 if (!iter->second->value().is_container())
1485 {
1486 if (result.count() == 0)
1487 {
1488 add_to_option(*m_next_positional, a);
1489 ++m_next_positional;
1490 return true;
1491 }
1492 else
1493 {
1494 ++m_next_positional;
1495 continue;
1496 }
1497 }
1498 else
1499 {
1500 add_to_option(*m_next_positional, a);
1501 return true;
1502 }
1503 }
1504 ++m_next_positional;
1505 }
1506
1507 return false;
1508 }
1509
1510 inline void
1512 {
1513 parse_positional(std::vector<std::string>{std::move(option)});
1514 }
1515
1516 inline void
1517 Options::parse_positional(std::vector<std::string> options)
1518 {
1519 m_positional = std::move(options);
1520 m_next_positional = m_positional.begin();
1521
1522 m_positional_set.insert(m_positional.begin(), m_positional.end());
1523 }
1524
1525 inline void
1526 Options::parse_positional(std::initializer_list<std::string> options)
1527 {
1528 parse_positional(std::vector<std::string>(std::move(options)));
1529 }
1530
1531 inline ParseResult
1532 Options::parse(int& argc, char**& argv)
1533 {
1534 ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv);
1535 return result;
1536 }
1537
1538 inline void
1539 ParseResult::parse(int& argc, char**& argv)
1540 {
1541 int current = 1;
1542
1543 int nextKeep = 1;
1544
1545 bool consume_remaining = false;
1546
1547 while (current != argc)
1548 {
1549 if (strcmp(argv[current], "--") == 0)
1550 {
1551 consume_remaining = true;
1552 ++current;
1553 break;
1554 }
1555
1556 std::match_results<const char*> result;
1557 std::regex_match(argv[current], result, option_matcher);
1558
1559 if (result.empty())
1560 {
1561 //not a flag
1562
1563 // but if it starts with a `-`, then it's an error
1564 if (argv[current][0] == '-' && argv[current][1] != '\0')
1565 {
1566 throw option_syntax_exception(argv[current]);
1567 }
1568
1569 //if true is returned here then it was consumed, otherwise it is
1570 //ignored
1571 if (consume_positional(argv[current]))
1572 {
1573 }
1574 else
1575 {
1576 argv[nextKeep] = argv[current];
1577 ++nextKeep;
1578 }
1579 //if we return from here then it was parsed successfully, so continue
1580 }
1581 else
1582 {
1583 //short or long option?
1584 if (result[4].length() != 0)
1585 {
1586 const std::string& s = result[4];
1587
1588 for (std::size_t i = 0; i != s.size(); ++i)
1589 {
1590 std::string name(1, s[i]);
1591 auto iter = m_options->find(name);
1592
1593 if (iter == m_options->end())
1594 {
1595 if (m_allow_unrecognised)
1596 {
1597 continue;
1598 }
1599 else
1600 {
1601 //error
1602 throw option_not_exists_exception(name);
1603 }
1604 }
1605
1606 auto value = iter->second;
1607
1608 if (i + 1 == s.size())
1609 {
1610 //it must be the last argument
1611 checked_parse_arg(argc, argv, current, value, name);
1612 }
1613 else if (value->value().has_implicit())
1614 {
1615 parse_option(value, name, value->value().get_implicit_value());
1616 }
1617 else
1618 {
1619 //error
1620 throw option_requires_argument_exception(name);
1621 }
1622 }
1623 }
1624 else if (result[1].length() != 0)
1625 {
1626 const std::string& name = result[1];
1627
1628 auto iter = m_options->find(name);
1629
1630 if (iter == m_options->end())
1631 {
1632 if (m_allow_unrecognised)
1633 {
1634 // keep unrecognised options in argument list, skip to next argument
1635 argv[nextKeep] = argv[current];
1636 ++nextKeep;
1637 ++current;
1638 continue;
1639 }
1640 else
1641 {
1642 //error
1643 throw option_not_exists_exception(name);
1644 }
1645 }
1646
1647 auto opt = iter->second;
1648
1649 //equals provided for long option?
1650 if (result[2].length() != 0)
1651 {
1652 //parse the option given
1653
1654 parse_option(opt, name, result[3]);
1655 }
1656 else
1657 {
1658 //parse the next argument
1659 checked_parse_arg(argc, argv, current, opt, name);
1660 }
1661 }
1662 }
1663
1664 ++current;
1665 }
1666
1667 for (auto& opt : *m_options)
1668 {
1669 auto& detail = opt.second;
1670 auto& value = detail->value();
1671
1672 auto& store = m_results[detail];
1673
1674 if (!store.count() && value.has_default())
1675 {
1676 parse_default(detail);
1677 }
1678 }
1679
1680 if (consume_remaining)
1681 {
1682 while (current < argc)
1683 {
1684 if (!consume_positional(argv[current]))
1685 {
1686 break;
1687 }
1688 ++current;
1689 }
1690
1691 //adjust argv for any that couldn't be swallowed
1692 while (current != argc)
1693 {
1694 argv[nextKeep] = argv[current];
1695 ++nextKeep;
1696 ++current;
1697 }
1698 }
1699
1700 argc = nextKeep;
1701 }
1702
1703 inline void
1704 Options::add_option(const std::string& group,
1705 const std::string& s,
1706 const std::string& l,
1707 std::string desc,
1708 std::shared_ptr<const Value> value,
1709 std::string arg_help)
1710 {
1711 auto stringDesc = toLocalString(std::move(desc));
1712 auto option = std::make_shared<OptionDetails>(s, l, stringDesc, value);
1713
1714 if (s.size() > 0)
1715 {
1716 add_one_option(s, option);
1717 }
1718
1719 if (l.size() > 0)
1720 {
1721 add_one_option(l, option);
1722 }
1723
1724 //add the help details
1725 auto& options = m_help[group];
1726
1727 options.options.emplace_back(HelpOptionDetails{s,
1728 l,
1729 stringDesc,
1730 value->has_default(),
1731 value->get_default_value(),
1732 value->has_implicit(),
1733 value->get_implicit_value(),
1734 std::move(arg_help),
1735 value->is_container(),
1736 value->is_boolean()});
1737 }
1738
1739 inline void
1740 Options::add_one_option(const std::string& option, std::shared_ptr<OptionDetails> details)
1741 {
1742 auto in = m_options->emplace(option, details);
1743
1744 if (!in.second)
1745 {
1747 }
1748 }
1749
1750 inline String
1751 Options::help_one_group(const std::string& g) const
1752 {
1753 typedef std::vector<std::pair<String, String>> OptionHelp;
1754
1755 auto group = m_help.find(g);
1756 if (group == m_help.end())
1757 {
1758 return "";
1759 }
1760
1761 OptionHelp format;
1762
1763 size_t longest = 0;
1764
1765 String result;
1766
1767 if (!g.empty())
1768 {
1769 result += toLocalString(" " + g + " options:\n");
1770 }
1771
1772 for (const auto& o : group->second.options)
1773 {
1774 if (o.is_container && m_positional_set.find(o.l) != m_positional_set.end() &&
1775 !m_show_positional)
1776 {
1777 continue;
1778 }
1779
1780 auto s = format_option(o);
1781 longest = (std::max)(longest, stringLength(s));
1782 format.push_back(std::make_pair(s, String()));
1783 }
1784
1785 longest = (std::min)(longest, static_cast<size_t>(OPTION_LONGEST));
1786
1787 //widest allowed description
1788 auto allowed = size_t{76} - longest - OPTION_DESC_GAP;
1789
1790 auto fiter = format.begin();
1791 for (const auto& o : group->second.options)
1792 {
1793 if (o.is_container && m_positional_set.find(o.l) != m_positional_set.end() &&
1794 !m_show_positional)
1795 {
1796 continue;
1797 }
1798
1799 auto d = format_description(o, longest + OPTION_DESC_GAP, allowed);
1800
1801 result += fiter->first;
1802 if (stringLength(fiter->first) > longest)
1803 {
1804 result += '\n';
1805 result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' '));
1806 }
1807 else
1808 {
1809 result += toLocalString(
1810 std::string(longest + OPTION_DESC_GAP - stringLength(fiter->first), ' '));
1811 }
1812 result += d;
1813 result += '\n';
1814
1815 ++fiter;
1816 }
1817
1818 return result;
1819 }
1820
1821 inline void
1822 Options::generate_group_help(String& result, const std::vector<std::string>& print_groups) const
1823 {
1824 for (size_t i = 0; i != print_groups.size(); ++i)
1825 {
1826 const String& group_help_text = help_one_group(print_groups[i]);
1827 if (empty(group_help_text))
1828 {
1829 continue;
1830 }
1831 result += group_help_text;
1832 if (i < print_groups.size() - 1)
1833 {
1834 result += '\n';
1835 }
1836 }
1837 }
1838
1839 inline void
1840 Options::generate_all_groups_help(String& result) const
1841 {
1842 std::vector<std::string> all_groups;
1843 all_groups.reserve(m_help.size());
1844
1845 for (auto& group : m_help)
1846 {
1847 all_groups.push_back(group.first);
1848 }
1849
1850 generate_group_help(result, all_groups);
1851 }
1852
1853 inline std::string
1854 Options::help(const std::vector<std::string>& help_groups) const
1855 {
1856 String result = m_help_string + "\nUsage:\n " + toLocalString(m_program) + " " +
1857 toLocalString(m_custom_help);
1858
1859 if (m_positional.size() > 0 && m_positional_help.size() > 0)
1860 {
1861 result += " " + toLocalString(m_positional_help);
1862 }
1863
1864 result += "\n\n";
1865
1866 if (help_groups.size() == 0)
1867 {
1868 generate_all_groups_help(result);
1869 }
1870 else
1871 {
1872 generate_group_help(result, help_groups);
1873 }
1874
1875 return toUTF8String(result);
1876 }
1877
1878 inline const std::vector<std::string>
1880 {
1881 std::vector<std::string> g;
1882
1883 std::transform(m_help.begin(),
1884 m_help.end(),
1885 std::back_inserter(g),
1886 [](const std::map<std::string, HelpGroupDetails>::value_type& pair)
1887 { return pair.first; });
1888
1889 return g;
1890 }
1891
1892 inline const HelpGroupDetails&
1893 Options::group_help(const std::string& group) const
1894 {
1895 return m_help.at(group);
1896 }
1897
1898} // namespace cxxopts
1899
1900#endif //CXXOPTS_HPP_INCLUDED
armarx::Vector3IBase operator+(const armarx::Vector3IBase &lhs, const armarx::Vector3IBase &rhs)
#define option(type, fn)
constexpr T c
const std::string & value() const
Definition cxxopts.hpp:1015
const std::string & key() const
Definition cxxopts.hpp:1009
KeyValue(std::string key_, std::string value_)
Definition cxxopts.hpp:1003
OptionAdder(Options &options, std::string group)
Definition cxxopts.hpp:1214
OptionAdder & operator()(const std::string &opts, const std::string &desc, std::shared_ptr< const Value > value=::cxxopts::value< bool >(), std::string arg_help="")
Definition cxxopts.hpp:1365
OptionDetails(OptionDetails &&rhs)=default
std::shared_ptr< Value > make_storage() const
Definition cxxopts.hpp:900
OptionDetails(const OptionDetails &rhs)
Definition cxxopts.hpp:880
const String & description() const
Definition cxxopts.hpp:888
const std::string & short_name() const
Definition cxxopts.hpp:906
OptionDetails(const std::string &short_, const std::string &long_, const String &desc, std::shared_ptr< const Value > val)
Definition cxxopts.hpp:872
const std::string & long_name() const
Definition cxxopts.hpp:912
const Value & value() const
Definition cxxopts.hpp:894
virtual const char * what() const noexcept
Definition cxxopts.hpp:292
OptionException(const std::string &message)
Definition cxxopts.hpp:287
OptionParseException(const std::string &message)
Definition cxxopts.hpp:312
OptionSpecException(const std::string &message)
Definition cxxopts.hpp:304
size_t count() const
Definition cxxopts.hpp:965
void parse_default(std::shared_ptr< const OptionDetails > details)
Definition cxxopts.hpp:958
void parse(std::shared_ptr< const OptionDetails > details, const std::string &text)
Definition cxxopts.hpp:950
const T & as() const
Definition cxxopts.hpp:972
void parse_positional(std::string option)
Definition cxxopts.hpp:1511
const HelpGroupDetails & group_help(const std::string &group) const
Definition cxxopts.hpp:1893
Options(std::string program, std::string help_string="")
Definition cxxopts.hpp:1115
void parse_positional(Iterator begin, Iterator end)
Definition cxxopts.hpp:1175
Options & allow_unrecognised_options()
Definition cxxopts.hpp:1149
void add_option(const std::string &group, const std::string &s, const std::string &l, std::string desc, std::shared_ptr< const Value > value, std::string arg_help)
Definition cxxopts.hpp:1704
Options & positional_help(std::string help_text)
Definition cxxopts.hpp:1128
std::string help(const std::vector< std::string > &groups={}) const
Definition cxxopts.hpp:1854
const std::vector< std::string > groups() const
Definition cxxopts.hpp:1879
OptionAdder add_options(std::string group="")
Definition cxxopts.hpp:1359
Options & custom_help(std::string help_text)
Definition cxxopts.hpp:1135
ParseResult parse(int &argc, char **&argv)
Definition cxxopts.hpp:1532
Options & show_positional_help()
Definition cxxopts.hpp:1142
ParseResult(const std::shared_ptr< std::unordered_map< std::string, std::shared_ptr< OptionDetails > > >, std::vector< std::string >, bool allow_unrecognised, int &, char **&)
Definition cxxopts.hpp:1343
const OptionValue & operator[](const std::string &option) const
Definition cxxopts.hpp:1059
const std::vector< KeyValue > & arguments() const
Definition cxxopts.hpp:1074
size_t count(const std::string &o) const
Definition cxxopts.hpp:1045
virtual bool has_default() const =0
virtual void parse() const =0
virtual bool is_container() const =0
virtual bool is_boolean() const =0
virtual std::shared_ptr< Value > clone() const =0
virtual std::string get_default_value() const =0
virtual ~Value()=default
virtual std::shared_ptr< Value > default_value(const std::string &value)=0
virtual std::shared_ptr< Value > implicit_value(const std::string &value)=0
virtual bool has_implicit() const =0
virtual std::string get_implicit_value() const =0
virtual void parse(const std::string &text) const =0
argument_incorrect_type(const std::string &arg)
Definition cxxopts.hpp:395
invalid_option_format_error(const std::string &format)
Definition cxxopts.hpp:329
missing_argument_exception(const std::string &option)
Definition cxxopts.hpp:357
option_exists_error(const std::string &option)
Definition cxxopts.hpp:320
option_not_exists_exception(const std::string &option)
Definition cxxopts.hpp:348
option_not_has_argument_exception(const std::string &option, const std::string &arg)
Definition cxxopts.hpp:375
option_not_present_exception(const std::string &option)
Definition cxxopts.hpp:386
option_required_exception(const std::string &option)
Definition cxxopts.hpp:404
option_requires_argument_exception(const std::string &option)
Definition cxxopts.hpp:366
option_syntax_exception(const std::string &text)
Definition cxxopts.hpp:338
abstract_value(const abstract_value &rhs)
Definition cxxopts.hpp:700
void parse(const std::string &text) const
Definition cxxopts.hpp:719
virtual ~abstract_value()=default
std::shared_ptr< Value > default_value(const std::string &value)
Definition cxxopts.hpp:749
std::shared_ptr< Value > implicit_value(const std::string &value)
Definition cxxopts.hpp:757
std::shared_ptr< T > m_result
Definition cxxopts.hpp:796
std::string get_default_value() const
Definition cxxopts.hpp:765
std::string get_implicit_value() const
Definition cxxopts.hpp:771
std::shared_ptr< Value > clone() const
Definition cxxopts.hpp:836
std::shared_ptr< Value > clone() const
Definition cxxopts.hpp:813
#define CXXOPTS__VERSION_MAJOR
Definition cxxopts.hpp:46
#define CXXOPTS__VERSION_MINOR
Definition cxxopts.hpp:47
#define CXXOPTS__VERSION_PATCH
Definition cxxopts.hpp:48
bool operator==(const ReplicaObserver &lhs, const ReplicaObserver &rhs)
Definition Election.h:2558
bool operator!=(const IceStorm::Subscriber &, const IceStorm::Subscriber &)
void store(const mongocxx::database &db, const armem::wm::Memory &m)
double s(double t, double s0, double v0, double a0, double j)
Definition CtrlUtil.h:33
StreamPrinter< Fnc > operator*(StreamPrinterTag, Fnc &&f)
Definition LoggingUtil.h:48
void check_signed_range(bool negative, U value, const std::string &text)
Definition cxxopts.hpp:461
void stringstream_parser(const std::string &text, T &value)
Definition cxxopts.hpp:556
void parse_value(const std::string &text, uint8_t &value)
Definition cxxopts.hpp:567
R checked_negate(T &&t, const std::string &, std::true_type)
Definition cxxopts.hpp:469
void integer_parser(const std::string &text, T &value)
Definition cxxopts.hpp:486
T toLocalString(T &&t)
Definition cxxopts.hpp:196
std::shared_ptr< Value > value()
Definition cxxopts.hpp:855
std::string toUTF8String(T &&t)
Definition cxxopts.hpp:228
bool empty(const std::string &s)
Definition cxxopts.hpp:234
String & stringAppend(String &s, String a)
Definition cxxopts.hpp:208
size_t stringLength(const String &s)
Definition cxxopts.hpp:202
std::string String
Definition cxxopts.hpp:192
constexpr auto n() noexcept
std::vector< HelpOptionDetails > options
Definition cxxopts.hpp:943
void operator()(bool, U, const std::string &)
Definition cxxopts.hpp:454
void operator()(bool negative, U u, const std::string &text)
Definition cxxopts.hpp:430
static constexpr bool value
Definition cxxopts.hpp:675