Commit 513afbc6dcfe2952cb2ffab0dae2415b11bba2d0

Authored by Eyal Rozenberg
Committed by GitHub
1 parent 8d18c3ed

Fixes #340: namespace indentation unification (#350)

* Namespace no longer induce indentation
* Namespace opening brace now on same line as namespace name
* Namespace closing brace now has an empty line before it unless the namespace contents were short and with no empty lines
* Namespace closing brace now always followed by a comment with the closed namespace' name
Showing 1 changed file with 1584 additions and 1590 deletions
include/cxxopts.hpp
... ... @@ -79,15 +79,14 @@ THE SOFTWARE.
79 79 #define CXXOPTS_NULL_DEREF_IGNORE
80 80 #endif
81 81  
82   -namespace cxxopts
83   -{
84   - static constexpr struct {
85   - uint8_t major, minor, patch;
86   - } version = {
87   - CXXOPTS__VERSION_MAJOR,
88   - CXXOPTS__VERSION_MINOR,
89   - CXXOPTS__VERSION_PATCH
90   - };
  82 +namespace cxxopts {
  83 +static constexpr struct {
  84 + uint8_t major, minor, patch;
  85 +} version = {
  86 + CXXOPTS__VERSION_MAJOR,
  87 + CXXOPTS__VERSION_MINOR,
  88 + CXXOPTS__VERSION_PATCH
  89 +};
91 90 } // namespace cxxopts
92 91  
93 92 //when we ask cxxopts to use Unicode, help strings are processed using ICU,
... ... @@ -99,16 +98,15 @@ namespace cxxopts
99 98 #ifdef CXXOPTS_USE_UNICODE
100 99 #include <unicode/unistr.h>
101 100  
102   -namespace cxxopts
103   -{
104   - using String = icu::UnicodeString;
  101 +namespace cxxopts {
  102 +using String = icu::UnicodeString;
105 103  
106   - inline
107   - String
108   - toLocalString(std::string s)
109   - {
110   - return icu::UnicodeString::fromUTF8(std::move(s));
111   - }
  104 +inline
  105 +String
  106 +toLocalString(std::string s)
  107 +{
  108 + return icu::UnicodeString::fromUTF8(std::move(s));
  109 +}
112 110  
113 111 #if defined(__GNUC__)
114 112 // GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it:
... ... @@ -118,202 +116,201 @@ namespace cxxopts
118 116 #pragma GCC diagnostic ignored "-Weffc++"
119 117 // This will be ignored under other compilers like LLVM clang.
120 118 #endif
121   - class UnicodeStringIterator : public
122   - std::iterator<std::forward_iterator_tag, int32_t>
123   - {
124   - public:
125   -
126   - UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
127   - : s(string)
128   - , i(pos)
129   - {
130   - }
131   -
132   - value_type
133   - operator*() const
134   - {
135   - return s->char32At(i);
136   - }
137   -
138   - bool
139   - operator==(const UnicodeStringIterator& rhs) const
140   - {
141   - return s == rhs.s && i == rhs.i;
142   - }
143   -
144   - bool
145   - operator!=(const UnicodeStringIterator& rhs) const
146   - {
147   - return !(*this == rhs);
148   - }
149   -
150   - UnicodeStringIterator&
151   - operator++()
152   - {
153   - ++i;
154   - return *this;
155   - }
156   -
157   - UnicodeStringIterator
158   - operator+(int32_t v)
159   - {
160   - return UnicodeStringIterator(s, i + v);
161   - }
162   -
163   - private:
164   - const icu::UnicodeString* s;
165   - int32_t i;
166   - };
167   -#if defined(__GNUC__)
168   -#pragma GCC diagnostic pop
169   -#endif
  119 +class UnicodeStringIterator : public
  120 + std::iterator<std::forward_iterator_tag, int32_t>
  121 +{
  122 + public:
170 123  
171   - inline
172   - String&
173   - stringAppend(String&s, String a)
  124 + UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos)
  125 + : s(string)
  126 + , i(pos)
174 127 {
175   - return s.append(std::move(a));
176 128 }
177 129  
178   - inline
179   - String&
180   - stringAppend(String& s, size_t n, UChar32 c)
  130 + value_type
  131 + operator*() const
181 132 {
182   - for (size_t i = 0; i != n; ++i)
183   - {
184   - s.append(c);
185   - }
186   -
187   - return s;
  133 + return s->char32At(i);
188 134 }
189 135  
190   - template <typename Iterator>
191   - String&
192   - stringAppend(String& s, Iterator begin, Iterator end)
  136 + bool
  137 + operator==(const UnicodeStringIterator& rhs) const
193 138 {
194   - while (begin != end)
195   - {
196   - s.append(*begin);
197   - ++begin;
198   - }
199   -
200   - return s;
  139 + return s == rhs.s && i == rhs.i;
201 140 }
202 141  
203   - inline
204   - size_t
205   - stringLength(const String& s)
  142 + bool
  143 + operator!=(const UnicodeStringIterator& rhs) const
206 144 {
207   - return s.length();
  145 + return !(*this == rhs);
208 146 }
209 147  
210   - inline
211   - std::string
212   - toUTF8String(const String& s)
  148 + UnicodeStringIterator&
  149 + operator++()
213 150 {
214   - std::string result;
215   - s.toUTF8String(result);
216   -
217   - return result;
  151 + ++i;
  152 + return *this;
218 153 }
219 154  
220   - inline
221   - bool
222   - empty(const String& s)
  155 + UnicodeStringIterator
  156 + operator+(int32_t v)
223 157 {
224   - return s.isEmpty();
  158 + return UnicodeStringIterator(s, i + v);
225 159 }
  160 +
  161 + private:
  162 + const icu::UnicodeString* s;
  163 + int32_t i;
  164 +};
  165 +#if defined(__GNUC__)
  166 +#pragma GCC diagnostic pop
  167 +#endif
  168 +
  169 +inline
  170 +String&
  171 +stringAppend(String&s, String a)
  172 +{
  173 + return s.append(std::move(a));
226 174 }
227 175  
228   -namespace std
  176 +inline
  177 +String&
  178 +stringAppend(String& s, size_t n, UChar32 c)
229 179 {
230   - inline
231   - cxxopts::UnicodeStringIterator
232   - begin(const icu::UnicodeString& s)
  180 + for (size_t i = 0; i != n; ++i)
233 181 {
234   - return cxxopts::UnicodeStringIterator(&s, 0);
  182 + s.append(c);
235 183 }
236 184  
237   - inline
238   - cxxopts::UnicodeStringIterator
239   - end(const icu::UnicodeString& s)
  185 + return s;
  186 +}
  187 +
  188 +template <typename Iterator>
  189 +String&
  190 +stringAppend(String& s, Iterator begin, Iterator end)
  191 +{
  192 + while (begin != end)
240 193 {
241   - return cxxopts::UnicodeStringIterator(&s, s.length());
  194 + s.append(*begin);
  195 + ++begin;
242 196 }
  197 +
  198 + return s;
243 199 }
244 200  
  201 +inline
  202 +size_t
  203 +stringLength(const String& s)
  204 +{
  205 + return s.length();
  206 +}
  207 +
  208 +inline
  209 +std::string
  210 +toUTF8String(const String& s)
  211 +{
  212 + std::string result;
  213 + s.toUTF8String(result);
  214 +
  215 + return result;
  216 +}
  217 +
  218 +inline
  219 +bool
  220 +empty(const String& s)
  221 +{
  222 + return s.isEmpty();
  223 +}
  224 +
  225 +} // namespace cxxopts
  226 +
  227 +namespace std {
  228 +inline
  229 +cxxopts::UnicodeStringIterator
  230 +begin(const icu::UnicodeString& s)
  231 +{
  232 + return cxxopts::UnicodeStringIterator(&s, 0);
  233 +}
  234 +
  235 +inline
  236 +cxxopts::UnicodeStringIterator
  237 +end(const icu::UnicodeString& s)
  238 +{
  239 + return cxxopts::UnicodeStringIterator(&s, s.length());
  240 +}
  241 +
  242 +} // namespace std
  243 +
245 244 //ifdef CXXOPTS_USE_UNICODE
246 245 #else
247 246  
248   -namespace cxxopts
  247 +namespace cxxopts {
  248 +using String = std::string;
  249 +
  250 +template <typename T>
  251 +T
  252 +toLocalString(T&& t)
249 253 {
250   - using String = std::string;
  254 + return std::forward<T>(t);
  255 +}
251 256  
252   - template <typename T>
253   - T
254   - toLocalString(T&& t)
255   - {
256   - return std::forward<T>(t);
257   - }
  257 +inline
  258 +size_t
  259 +stringLength(const String& s)
  260 +{
  261 + return s.length();
  262 +}
258 263  
259   - inline
260   - size_t
261   - stringLength(const String& s)
262   - {
263   - return s.length();
264   - }
  264 +inline
  265 +String&
  266 +stringAppend(String&s, const String& a)
  267 +{
  268 + return s.append(a);
  269 +}
265 270  
266   - inline
267   - String&
268   - stringAppend(String&s, const String& a)
269   - {
270   - return s.append(a);
271   - }
  271 +inline
  272 +String&
  273 +stringAppend(String& s, size_t n, char c)
  274 +{
  275 + return s.append(n, c);
  276 +}
272 277  
273   - inline
274   - String&
275   - stringAppend(String& s, size_t n, char c)
276   - {
277   - return s.append(n, c);
278   - }
  278 +template <typename Iterator>
  279 +String&
  280 +stringAppend(String& s, Iterator begin, Iterator end)
  281 +{
  282 + return s.append(begin, end);
  283 +}
279 284  
280   - template <typename Iterator>
281   - String&
282   - stringAppend(String& s, Iterator begin, Iterator end)
283   - {
284   - return s.append(begin, end);
285   - }
  285 +template <typename T>
  286 +std::string
  287 +toUTF8String(T&& t)
  288 +{
  289 + return std::forward<T>(t);
  290 +}
286 291  
287   - template <typename T>
288   - std::string
289   - toUTF8String(T&& t)
290   - {
291   - return std::forward<T>(t);
292   - }
  292 +inline
  293 +bool
  294 +empty(const std::string& s)
  295 +{
  296 + return s.empty();
  297 +}
293 298  
294   - inline
295   - bool
296   - empty(const std::string& s)
297   - {
298   - return s.empty();
299   - }
300 299 } // namespace cxxopts
301 300  
302 301 //ifdef CXXOPTS_USE_UNICODE
303 302 #endif
304 303  
305   -namespace cxxopts
306   -{
307   - namespace
308   - {
  304 +namespace cxxopts {
  305 +namespace {
309 306 #ifdef _WIN32
310   - const std::string LQUOTE("\'");
311   - const std::string RQUOTE("\'");
  307 +const std::string LQUOTE("\'");
  308 +const std::string RQUOTE("\'");
312 309 #else
313   - const std::string LQUOTE("โ€˜");
314   - const std::string RQUOTE("โ€™");
  310 +const std::string LQUOTE("โ€˜");
  311 +const std::string RQUOTE("โ€™");
315 312 #endif
316   - } // namespace
  313 +} // namespace
317 314  
318 315 #if defined(__GNUC__)
319 316 // GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it:
... ... @@ -323,1764 +320,1761 @@ namespace cxxopts
323 320 #pragma GCC diagnostic ignored "-Weffc++"
324 321 // This will be ignored under other compilers like LLVM clang.
325 322 #endif
326   - class Value : public std::enable_shared_from_this<Value>
327   - {
328   - public:
  323 +class Value : public std::enable_shared_from_this<Value>
  324 +{
  325 + public:
329 326  
330   - virtual ~Value() = default;
  327 + virtual ~Value() = default;
331 328  
332   - virtual
333   - std::shared_ptr<Value>
334   - clone() const = 0;
  329 + virtual
  330 + std::shared_ptr<Value>
  331 + clone() const = 0;
335 332  
336   - virtual void
337   - parse(const std::string& text) const = 0;
  333 + virtual void
  334 + parse(const std::string& text) const = 0;
338 335  
339   - virtual void
340   - parse() const = 0;
  336 + virtual void
  337 + parse() const = 0;
341 338  
342   - virtual bool
343   - has_default() const = 0;
  339 + virtual bool
  340 + has_default() const = 0;
344 341  
345   - virtual bool
346   - is_container() const = 0;
  342 + virtual bool
  343 + is_container() const = 0;
347 344  
348   - virtual bool
349   - has_implicit() const = 0;
  345 + virtual bool
  346 + has_implicit() const = 0;
350 347  
351   - virtual std::string
352   - get_default_value() const = 0;
  348 + virtual std::string
  349 + get_default_value() const = 0;
353 350  
354   - virtual std::string
355   - get_implicit_value() const = 0;
  351 + virtual std::string
  352 + get_implicit_value() const = 0;
356 353  
357   - virtual std::shared_ptr<Value>
358   - default_value(const std::string& value) = 0;
  354 + virtual std::shared_ptr<Value>
  355 + default_value(const std::string& value) = 0;
359 356  
360   - virtual std::shared_ptr<Value>
361   - implicit_value(const std::string& value) = 0;
  357 + virtual std::shared_ptr<Value>
  358 + implicit_value(const std::string& value) = 0;
362 359  
363   - virtual std::shared_ptr<Value>
364   - no_implicit_value() = 0;
  360 + virtual std::shared_ptr<Value>
  361 + no_implicit_value() = 0;
365 362  
366   - virtual bool
367   - is_boolean() const = 0;
368   - };
  363 + virtual bool
  364 + is_boolean() const = 0;
  365 +};
369 366 #if defined(__GNUC__)
370 367 #pragma GCC diagnostic pop
371 368 #endif
372   - class OptionException : public std::exception
  369 +class OptionException : public std::exception
  370 +{
  371 + public:
  372 + explicit OptionException(std::string message)
  373 + : m_message(std::move(message))
373 374 {
374   - public:
375   - explicit OptionException(std::string message)
376   - : m_message(std::move(message))
377   - {
378   - }
379   -
380   - CXXOPTS_NODISCARD
381   - const char*
382   - what() const noexcept override
383   - {
384   - return m_message.c_str();
385   - }
386   -
387   - private:
388   - std::string m_message;
389   - };
  375 + }
390 376  
391   - class OptionSpecException : public OptionException
  377 + CXXOPTS_NODISCARD
  378 + const char*
  379 + what() const noexcept override
392 380 {
393   - public:
  381 + return m_message.c_str();
  382 + }
394 383  
395   - explicit OptionSpecException(const std::string& message)
396   - : OptionException(message)
397   - {
398   - }
399   - };
  384 + private:
  385 + std::string m_message;
  386 +};
400 387  
401   - class OptionParseException : public OptionException
402   - {
403   - public:
404   - explicit OptionParseException(const std::string& message)
405   - : OptionException(message)
406   - {
407   - }
408   - };
  388 +class OptionSpecException : public OptionException
  389 +{
  390 + public:
409 391  
410   - class option_exists_error : public OptionSpecException
  392 + explicit OptionSpecException(const std::string& message)
  393 + : OptionException(message)
411 394 {
412   - public:
413   - explicit option_exists_error(const std::string& option)
414   - : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists")
415   - {
416   - }
417   - };
  395 + }
  396 +};
418 397  
419   - class invalid_option_format_error : public OptionSpecException
  398 +class OptionParseException : public OptionException
  399 +{
  400 + public:
  401 + explicit OptionParseException(const std::string& message)
  402 + : OptionException(message)
420 403 {
421   - public:
422   - explicit invalid_option_format_error(const std::string& format)
423   - : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE)
424   - {
425   - }
426   - };
  404 + }
  405 +};
427 406  
428   - class option_syntax_exception : public OptionParseException {
429   - public:
430   - explicit option_syntax_exception(const std::string& text)
431   - : OptionParseException("Argument " + LQUOTE + text + RQUOTE +
432   - " starts with a - but has incorrect syntax")
433   - {
434   - }
435   - };
  407 +class option_exists_error : public OptionSpecException
  408 +{
  409 + public:
  410 + explicit option_exists_error(const std::string& option)
  411 + : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists")
  412 + {
  413 + }
  414 +};
436 415  
437   - class option_not_exists_exception : public OptionParseException
  416 +class invalid_option_format_error : public OptionSpecException
  417 +{
  418 + public:
  419 + explicit invalid_option_format_error(const std::string& format)
  420 + : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE)
438 421 {
439   - public:
440   - explicit option_not_exists_exception(const std::string& option)
441   - : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist")
442   - {
443   - }
444   - };
  422 + }
  423 +};
445 424  
446   - class missing_argument_exception : public OptionParseException
  425 +class option_syntax_exception : public OptionParseException {
  426 + public:
  427 + explicit option_syntax_exception(const std::string& text)
  428 + : OptionParseException("Argument " + LQUOTE + text + RQUOTE +
  429 + " starts with a - but has incorrect syntax")
447 430 {
448   - public:
449   - explicit missing_argument_exception(const std::string& option)
450   - : OptionParseException(
451   - "Option " + LQUOTE + option + RQUOTE + " is missing an argument"
452   - )
453   - {
454   - }
455   - };
  431 + }
  432 +};
456 433  
457   - class option_requires_argument_exception : public OptionParseException
  434 +class option_not_exists_exception : public OptionParseException
  435 +{
  436 + public:
  437 + explicit option_not_exists_exception(const std::string& option)
  438 + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist")
458 439 {
459   - public:
460   - explicit option_requires_argument_exception(const std::string& option)
461   - : OptionParseException(
462   - "Option " + LQUOTE + option + RQUOTE + " requires an argument"
463   - )
464   - {
465   - }
466   - };
  440 + }
  441 +};
467 442  
468   - class option_not_has_argument_exception : public OptionParseException
  443 +class missing_argument_exception : public OptionParseException
  444 +{
  445 + public:
  446 + explicit missing_argument_exception(const std::string& option)
  447 + : OptionParseException(
  448 + "Option " + LQUOTE + option + RQUOTE + " is missing an argument"
  449 + )
469 450 {
470   - public:
471   - option_not_has_argument_exception
472   - (
473   - const std::string& option,
474   - const std::string& arg
  451 + }
  452 +};
  453 +
  454 +class option_requires_argument_exception : public OptionParseException
  455 +{
  456 + public:
  457 + explicit option_requires_argument_exception(const std::string& option)
  458 + : OptionParseException(
  459 + "Option " + LQUOTE + option + RQUOTE + " requires an argument"
475 460 )
476   - : OptionParseException(
477   - "Option " + LQUOTE + option + RQUOTE +
478   - " does not take an argument, but argument " +
479   - LQUOTE + arg + RQUOTE + " given"
480   - )
481   - {
482   - }
483   - };
  461 + {
  462 + }
  463 +};
484 464  
485   - class option_not_present_exception : public OptionParseException
  465 +class option_not_has_argument_exception : public OptionParseException
  466 +{
  467 + public:
  468 + option_not_has_argument_exception
  469 + (
  470 + const std::string& option,
  471 + const std::string& arg
  472 + )
  473 + : OptionParseException(
  474 + "Option " + LQUOTE + option + RQUOTE +
  475 + " does not take an argument, but argument " +
  476 + LQUOTE + arg + RQUOTE + " given"
  477 + )
486 478 {
487   - public:
488   - explicit option_not_present_exception(const std::string& option)
489   - : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present")
490   - {
491   - }
492   - };
  479 + }
  480 +};
493 481  
494   - class option_has_no_value_exception : public OptionException
  482 +class option_not_present_exception : public OptionParseException
  483 +{
  484 + public:
  485 + explicit option_not_present_exception(const std::string& option)
  486 + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present")
495 487 {
496   - public:
497   - explicit option_has_no_value_exception(const std::string& option)
498   - : OptionException(
499   - !option.empty() ?
500   - ("Option " + LQUOTE + option + RQUOTE + " has no value") :
501   - "Option has no value")
502   - {
503   - }
504   - };
  488 + }
  489 +};
505 490  
506   - class argument_incorrect_type : public OptionParseException
  491 +class option_has_no_value_exception : public OptionException
  492 +{
  493 + public:
  494 + explicit option_has_no_value_exception(const std::string& option)
  495 + : OptionException(
  496 + !option.empty() ?
  497 + ("Option " + LQUOTE + option + RQUOTE + " has no value") :
  498 + "Option has no value")
507 499 {
508   - public:
509   - explicit argument_incorrect_type
510   - (
511   - const std::string& arg
512   - )
513   - : OptionParseException(
514   - "Argument " + LQUOTE + arg + RQUOTE + " failed to parse"
515   - )
516   - {
517   - }
518   - };
  500 + }
  501 +};
519 502  
520   - class option_required_exception : public OptionParseException
  503 +class argument_incorrect_type : public OptionParseException
  504 +{
  505 + public:
  506 + explicit argument_incorrect_type
  507 + (
  508 + const std::string& arg
  509 + )
  510 + : OptionParseException(
  511 + "Argument " + LQUOTE + arg + RQUOTE + " failed to parse"
  512 + )
521 513 {
522   - public:
523   - explicit option_required_exception(const std::string& option)
524   - : OptionParseException(
525   - "Option " + LQUOTE + option + RQUOTE + " is required but not present"
526   - )
527   - {
528   - }
529   - };
  514 + }
  515 +};
530 516  
531   - template <typename T>
532   - void throw_or_mimic(const std::string& text)
  517 +class option_required_exception : public OptionParseException
  518 +{
  519 + public:
  520 + explicit option_required_exception(const std::string& option)
  521 + : OptionParseException(
  522 + "Option " + LQUOTE + option + RQUOTE + " is required but not present"
  523 + )
533 524 {
534   - static_assert(std::is_base_of<std::exception, T>::value,
535   - "throw_or_mimic only works on std::exception and "
536   - "deriving classes");
  525 + }
  526 +};
  527 +
  528 +template <typename T>
  529 +void throw_or_mimic(const std::string& text)
  530 +{
  531 + static_assert(std::is_base_of<std::exception, T>::value,
  532 + "throw_or_mimic only works on std::exception and "
  533 + "deriving classes");
537 534  
538 535 #ifndef CXXOPTS_NO_EXCEPTIONS
539   - // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw
540   - throw T{text};
  536 + // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw
  537 + throw T{text};
541 538 #else
542   - // Otherwise manually instantiate the exception, print what() to stderr,
543   - // and exit
544   - T exception{text};
545   - std::cerr << exception.what() << std::endl;
546   - std::exit(EXIT_FAILURE);
  539 + // Otherwise manually instantiate the exception, print what() to stderr,
  540 + // and exit
  541 + T exception{text};
  542 + std::cerr << exception.what() << std::endl;
  543 + std::exit(EXIT_FAILURE);
547 544 #endif
548   - }
  545 +}
549 546  
550   - namespace values
551   - {
552   - namespace parser_tool
553   - {
554   - struct IntegerDesc
555   - {
556   - std::string negative = "";
557   - std::string base = "";
558   - std::string value = "";
559   - };
560   - struct ArguDesc {
561   - std::string arg_name = "";
562   - bool grouping = false;
563   - bool set_value = false;
564   - std::string value = "";
565   - };
  547 +namespace values {
  548 +namespace parser_tool {
  549 +struct IntegerDesc
  550 +{
  551 + std::string negative = "";
  552 + std::string base = "";
  553 + std::string value = "";
  554 +};
  555 +struct ArguDesc {
  556 + std::string arg_name = "";
  557 + bool grouping = false;
  558 + bool set_value = false;
  559 + std::string value = "";
  560 +};
566 561 #ifdef CXXOPTS_NO_REGEX
567   - inline IntegerDesc SplitInteger(const std::string &text)
568   - {
569   - if (text.empty())
570   - {
571   - throw_or_mimic<argument_incorrect_type>(text);
572   - }
573   - IntegerDesc desc;
574   - const char *pdata = text.c_str();
575   - if (*pdata == '-')
576   - {
577   - pdata += 1;
578   - desc.negative = "-";
579   - }
580   - if (strncmp(pdata, "0x", 2) == 0)
581   - {
582   - pdata += 2;
583   - desc.base = "0x";
584   - }
585   - if (*pdata != '\0')
586   - {
587   - desc.value = std::string(pdata);
588   - }
589   - else
590   - {
591   - throw_or_mimic<argument_incorrect_type>(text);
592   - }
593   - return desc;
594   - }
  562 +inline IntegerDesc SplitInteger(const std::string &text)
  563 +{
  564 + if (text.empty())
  565 + {
  566 + throw_or_mimic<argument_incorrect_type>(text);
  567 + }
  568 + IntegerDesc desc;
  569 + const char *pdata = text.c_str();
  570 + if (*pdata == '-')
  571 + {
  572 + pdata += 1;
  573 + desc.negative = "-";
  574 + }
  575 + if (strncmp(pdata, "0x", 2) == 0)
  576 + {
  577 + pdata += 2;
  578 + desc.base = "0x";
  579 + }
  580 + if (*pdata != '\0')
  581 + {
  582 + desc.value = std::string(pdata);
  583 + }
  584 + else
  585 + {
  586 + throw_or_mimic<argument_incorrect_type>(text);
  587 + }
  588 + return desc;
  589 +}
595 590  
596   - inline bool IsTrueText(const std::string &text)
597   - {
598   - const char *pdata = text.c_str();
599   - if (*pdata == 't' || *pdata == 'T')
600   - {
601   - pdata += 1;
602   - if (strncmp(pdata, "rue\0", 4) == 0)
603   - {
604   - return true;
605   - }
606   - }
607   - else if (strncmp(pdata, "1\0", 2) == 0)
608   - {
609   - return true;
610   - }
611   - return false;
612   - }
  591 +inline bool IsTrueText(const std::string &text)
  592 +{
  593 + const char *pdata = text.c_str();
  594 + if (*pdata == 't' || *pdata == 'T')
  595 + {
  596 + pdata += 1;
  597 + if (strncmp(pdata, "rue\0", 4) == 0)
  598 + {
  599 + return true;
  600 + }
  601 + }
  602 + else if (strncmp(pdata, "1\0", 2) == 0)
  603 + {
  604 + return true;
  605 + }
  606 + return false;
  607 +}
613 608  
614   - inline bool IsFalseText(const std::string &text)
615   - {
616   - const char *pdata = text.c_str();
617   - if (*pdata == 'f' || *pdata == 'F')
618   - {
619   - pdata += 1;
620   - if (strncmp(pdata, "alse\0", 5) == 0)
621   - {
622   - return true;
623   - }
624   - }
625   - else if (strncmp(pdata, "0\0", 2) == 0)
626   - {
627   - return true;
628   - }
629   - return false;
630   - }
  609 +inline bool IsFalseText(const std::string &text)
  610 +{
  611 + const char *pdata = text.c_str();
  612 + if (*pdata == 'f' || *pdata == 'F')
  613 + {
  614 + pdata += 1;
  615 + if (strncmp(pdata, "alse\0", 5) == 0)
  616 + {
  617 + return true;
  618 + }
  619 + }
  620 + else if (strncmp(pdata, "0\0", 2) == 0)
  621 + {
  622 + return true;
  623 + }
  624 + return false;
  625 +}
  626 +
  627 +inline std::pair<std::string, std::string> SplitSwitchDef(const std::string &text)
  628 +{
  629 + std::string short_sw, long_sw;
  630 + const char *pdata = text.c_str();
  631 + if (isalnum(*pdata) && *(pdata + 1) == ',') {
  632 + short_sw = std::string(1, *pdata);
  633 + pdata += 2;
  634 + }
  635 + while (*pdata == ' ') { pdata += 1; }
  636 + if (isalnum(*pdata)) {
  637 + const char *store = pdata;
  638 + pdata += 1;
  639 + while (isalnum(*pdata) || *pdata == '-' || *pdata == '_') {
  640 + pdata += 1;
  641 + }
  642 + if (*pdata == '\0') {
  643 + long_sw = std::string(store, pdata - store);
  644 + } else {
  645 + throw_or_mimic<invalid_option_format_error>(text);
  646 + }
  647 + }
  648 + return std::pair<std::string, std::string>(short_sw, long_sw);
  649 +}
631 650  
632   - inline std::pair<std::string, std::string> SplitSwitchDef(const std::string &text)
  651 +inline ArguDesc ParseArgument(const char *arg, bool &matched)
  652 +{
  653 + ArguDesc argu_desc;
  654 + const char *pdata = arg;
  655 + matched = false;
  656 + if (strncmp(pdata, "--", 2) == 0)
  657 + {
  658 + pdata += 2;
  659 + if (isalnum(*pdata))
  660 + {
  661 + argu_desc.arg_name.push_back(*pdata);
  662 + pdata += 1;
  663 + while (isalnum(*pdata) || *pdata == '-' || *pdata == '_')
633 664 {
634   - std::string short_sw, long_sw;
635   - const char *pdata = text.c_str();
636   - if (isalnum(*pdata) && *(pdata + 1) == ',') {
637   - short_sw = std::string(1, *pdata);
638   - pdata += 2;
639   - }
640   - while (*pdata == ' ') { pdata += 1; }
641   - if (isalnum(*pdata)) {
642   - const char *store = pdata;
643   - pdata += 1;
644   - while (isalnum(*pdata) || *pdata == '-' || *pdata == '_') {
645   - pdata += 1;
646   - }
647   - if (*pdata == '\0') {
648   - long_sw = std::string(store, pdata - store);
649   - } else {
650   - throw_or_mimic<invalid_option_format_error>(text);
651   - }
652   - }
653   - return std::pair<std::string, std::string>(short_sw, long_sw);
  665 + argu_desc.arg_name.push_back(*pdata);
  666 + pdata += 1;
654 667 }
655   -
656   - inline ArguDesc ParseArgument(const char *arg, bool &matched)
  668 + if (argu_desc.arg_name.length() > 1)
657 669 {
658   - ArguDesc argu_desc;
659   - const char *pdata = arg;
660   - matched = false;
661   - if (strncmp(pdata, "--", 2) == 0)
  670 + if (*pdata == '=')
662 671 {
663   - pdata += 2;
664   - if (isalnum(*pdata))
  672 + argu_desc.set_value = true;
  673 + pdata += 1;
  674 + if (*pdata != '\0')
665 675 {
666   - argu_desc.arg_name.push_back(*pdata);
667   - pdata += 1;
668   - while (isalnum(*pdata) || *pdata == '-' || *pdata == '_')
669   - {
670   - argu_desc.arg_name.push_back(*pdata);
671   - pdata += 1;
672   - }
673   - if (argu_desc.arg_name.length() > 1)
674   - {
675   - if (*pdata == '=')
676   - {
677   - argu_desc.set_value = true;
678   - pdata += 1;
679   - if (*pdata != '\0')
680   - {
681   - argu_desc.value = std::string(pdata);
682   - }
683   - matched = true;
684   - }
685   - else if (*pdata == '\0')
686   - {
687   - matched = true;
688   - }
689   - }
  676 + argu_desc.value = std::string(pdata);
690 677 }
  678 + matched = true;
691 679 }
692   - else if (strncmp(pdata, "-", 1) == 0)
  680 + else if (*pdata == '\0')
693 681 {
694   - pdata += 1;
695   - argu_desc.grouping = true;
696   - while (isalnum(*pdata))
697   - {
698   - argu_desc.arg_name.push_back(*pdata);
699   - pdata += 1;
700   - }
701   - matched = !argu_desc.arg_name.empty() && *pdata == '\0';
  682 + matched = true;
702 683 }
703   - return argu_desc;
704 684 }
  685 + }
  686 + }
  687 + else if (strncmp(pdata, "-", 1) == 0)
  688 + {
  689 + pdata += 1;
  690 + argu_desc.grouping = true;
  691 + while (isalnum(*pdata))
  692 + {
  693 + argu_desc.arg_name.push_back(*pdata);
  694 + pdata += 1;
  695 + }
  696 + matched = !argu_desc.arg_name.empty() && *pdata == '\0';
  697 + }
  698 + return argu_desc;
  699 +}
705 700  
706 701 #else // CXXOPTS_NO_REGEX
707 702  
708   - namespace
709   - {
  703 +namespace {
710 704  
711   - std::basic_regex<char> integer_pattern
712   - ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
713   - std::basic_regex<char> truthy_pattern
714   - ("(t|T)(rue)?|1");
715   - std::basic_regex<char> falsy_pattern
716   - ("(f|F)(alse)?|0");
  705 +std::basic_regex<char> integer_pattern
  706 + ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)");
  707 +std::basic_regex<char> truthy_pattern
  708 + ("(t|T)(rue)?|1");
  709 +std::basic_regex<char> falsy_pattern
  710 + ("(f|F)(alse)?|0");
717 711  
718   - std::basic_regex<char> option_matcher
719   - ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
720   - std::basic_regex<char> option_specifier
721   - ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
  712 +std::basic_regex<char> option_matcher
  713 + ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)");
  714 +std::basic_regex<char> option_specifier
  715 + ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?");
722 716  
723   - } // namespace
  717 +} // namespace
724 718  
725   - inline IntegerDesc SplitInteger(const std::string &text)
726   - {
727   - std::smatch match;
728   - std::regex_match(text, match, integer_pattern);
  719 +inline IntegerDesc SplitInteger(const std::string &text)
  720 +{
  721 + std::smatch match;
  722 + std::regex_match(text, match, integer_pattern);
729 723  
730   - if (match.length() == 0)
731   - {
732   - throw_or_mimic<argument_incorrect_type>(text);
733   - }
  724 + if (match.length() == 0)
  725 + {
  726 + throw_or_mimic<argument_incorrect_type>(text);
  727 + }
734 728  
735   - IntegerDesc desc;
736   - desc.negative = match[1];
737   - desc.base = match[2];
738   - desc.value = match[3];
  729 + IntegerDesc desc;
  730 + desc.negative = match[1];
  731 + desc.base = match[2];
  732 + desc.value = match[3];
739 733  
740   - if (match.length(4) > 0)
741   - {
742   - desc.base = match[5];
743   - desc.value = "0";
744   - return desc;
745   - }
  734 + if (match.length(4) > 0)
  735 + {
  736 + desc.base = match[5];
  737 + desc.value = "0";
  738 + return desc;
  739 + }
746 740  
747   - return desc;
748   - }
  741 + return desc;
749 742  
750   - inline bool IsTrueText(const std::string &text)
751   - {
752   - std::smatch result;
753   - std::regex_match(text, result, truthy_pattern);
754   - return !result.empty();
755   - }
  743 +}
756 744  
757   - inline bool IsFalseText(const std::string &text)
758   - {
759   - std::smatch result;
760   - std::regex_match(text, result, falsy_pattern);
761   - return !result.empty();
762   - }
  745 +inline bool IsTrueText(const std::string &text)
  746 +{
  747 + std::smatch result;
  748 + std::regex_match(text, result, truthy_pattern);
  749 + return !result.empty();
  750 +}
763 751  
764   - inline std::pair<std::string, std::string> SplitSwitchDef(const std::string &text)
765   - {
766   - std::match_results<const char*> result;
767   - std::regex_match(text.c_str(), result, option_specifier);
768   - if (result.empty())
769   - {
770   - throw_or_mimic<invalid_option_format_error>(text);
771   - }
  752 +inline bool IsFalseText(const std::string &text)
  753 +{
  754 + std::smatch result;
  755 + std::regex_match(text, result, falsy_pattern);
  756 + return !result.empty();
  757 +}
772 758  
773   - const std::string& short_sw = result[2];
774   - const std::string& long_sw = result[3];
  759 +inline std::pair<std::string, std::string> SplitSwitchDef(const std::string &text)
  760 +{
  761 + std::match_results<const char*> result;
  762 + std::regex_match(text.c_str(), result, option_specifier);
  763 + if (result.empty())
  764 + {
  765 + throw_or_mimic<invalid_option_format_error>(text);
  766 + }
775 767  
776   - return std::pair<std::string, std::string>(short_sw, long_sw);
777   - }
  768 + const std::string& short_sw = result[2];
  769 + const std::string& long_sw = result[3];
778 770  
779   - inline ArguDesc ParseArgument(const char *arg, bool &matched)
780   - {
781   - std::match_results<const char*> result;
782   - std::regex_match(arg, result, option_matcher);
783   - matched = !result.empty();
784   -
785   - ArguDesc argu_desc;
786   - if (matched) {
787   - argu_desc.arg_name = result[1].str();
788   - argu_desc.set_value = result[2].length() > 0;
789   - argu_desc.value = result[3].str();
790   - if (result[4].length() > 0)
791   - {
792   - argu_desc.grouping = true;
793   - argu_desc.arg_name = result[4].str();
794   - }
795   - }
  771 + return std::pair<std::string, std::string>(short_sw, long_sw);
  772 +}
796 773  
797   - return argu_desc;
798   - }
  774 +inline ArguDesc ParseArgument(const char *arg, bool &matched)
  775 +{
  776 + std::match_results<const char*> result;
  777 + std::regex_match(arg, result, option_matcher);
  778 + matched = !result.empty();
799 779  
800   -#endif // CXXOPTS_NO_REGEX
801   -#undef CXXOPTS_NO_REGEX
  780 + ArguDesc argu_desc;
  781 + if (matched) {
  782 + argu_desc.arg_name = result[1].str();
  783 + argu_desc.set_value = result[2].length() > 0;
  784 + argu_desc.value = result[3].str();
  785 + if (result[4].length() > 0)
  786 + {
  787 + argu_desc.grouping = true;
  788 + argu_desc.arg_name = result[4].str();
  789 + }
802 790 }
803 791  
804   - namespace detail
805   - {
806   - template <typename T, bool B>
807   - struct SignedCheck;
  792 + return argu_desc;
  793 +}
808 794  
809   - template <typename T>
810   - struct SignedCheck<T, true>
811   - {
812   - template <typename U>
813   - void
814   - operator()(bool negative, U u, const std::string& text)
815   - {
816   - if (negative)
817   - {
818   - if (u > static_cast<U>((std::numeric_limits<T>::min)()))
819   - {
820   - throw_or_mimic<argument_incorrect_type>(text);
821   - }
822   - }
823   - else
824   - {
825   - if (u > static_cast<U>((std::numeric_limits<T>::max)()))
826   - {
827   - throw_or_mimic<argument_incorrect_type>(text);
828   - }
829   - }
830   - }
831   - };
  795 +#endif // CXXOPTS_NO_REGEX
  796 +#undef CXXOPTS_NO_REGEX
  797 +} // namespace parser_tool
832 798  
833   - template <typename T>
834   - struct SignedCheck<T, false>
835   - {
836   - template <typename U>
837   - void
838   - operator()(bool, U, const std::string&) const {}
839   - };
840   -
841   - template <typename T, typename U>
842   - void
843   - check_signed_range(bool negative, U value, const std::string& text)
844   - {
845   - SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text);
846   - }
847   - } // namespace detail
  799 +namespace detail {
  800 +template <typename T, bool B>
  801 +struct SignedCheck;
848 802  
849   - template <typename R, typename T>
850   - void
851   - checked_negate(R& r, T&& t, const std::string&, std::true_type)
  803 +template <typename T>
  804 +struct SignedCheck<T, true>
  805 +{
  806 + template <typename U>
  807 + void
  808 + operator()(bool negative, U u, const std::string& text)
  809 + {
  810 + if (negative)
852 811 {
853   - // if we got to here, then `t` is a positive number that fits into
854   - // `R`. So to avoid MSVC C4146, we first cast it to `R`.
855   - // See https://github.com/jarro2783/cxxopts/issues/62 for more details.
856   - r = static_cast<R>(-static_cast<R>(t-1)-1);
  812 + if (u > static_cast<U>((std::numeric_limits<T>::min)()))
  813 + {
  814 + throw_or_mimic<argument_incorrect_type>(text);
  815 + }
857 816 }
858   -
859   - template <typename R, typename T>
860   - void
861   - checked_negate(R&, T&&, const std::string& text, std::false_type)
  817 + else
862 818 {
863   - throw_or_mimic<argument_incorrect_type>(text);
  819 + if (u > static_cast<U>((std::numeric_limits<T>::max)()))
  820 + {
  821 + throw_or_mimic<argument_incorrect_type>(text);
  822 + }
864 823 }
  824 + }
  825 +};
865 826  
866   - template <typename T>
867   - void
868   - integer_parser(const std::string& text, T& value)
869   - {
870   - parser_tool::IntegerDesc int_desc = parser_tool::SplitInteger(text);
  827 +template <typename T>
  828 +struct SignedCheck<T, false>
  829 +{
  830 + template <typename U>
  831 + void
  832 + operator()(bool, U, const std::string&) const {}
  833 +};
871 834  
872   - using US = typename std::make_unsigned<T>::type;
873   - constexpr bool is_signed = std::numeric_limits<T>::is_signed;
  835 +template <typename T, typename U>
  836 +void
  837 +check_signed_range(bool negative, U value, const std::string& text)
  838 +{
  839 + SignedCheck<T, std::numeric_limits<T>::is_signed>()(negative, value, text);
  840 +}
874 841  
875   - const bool negative = int_desc.negative.length() > 0;
876   - const uint8_t base = int_desc.base.length() > 0 ? 16 : 10;
877   - const std::string & value_match = int_desc.value;
  842 +} // namespace detail
878 843  
879   - US result = 0;
  844 +template <typename R, typename T>
  845 +void
  846 +checked_negate(R& r, T&& t, const std::string&, std::true_type)
  847 +{
  848 + // if we got to here, then `t` is a positive number that fits into
  849 + // `R`. So to avoid MSVC C4146, we first cast it to `R`.
  850 + // See https://github.com/jarro2783/cxxopts/issues/62 for more details.
  851 + r = static_cast<R>(-static_cast<R>(t-1)-1);
  852 +}
880 853  
881   - for (char ch : value_match)
882   - {
883   - US digit = 0;
  854 +template <typename R, typename T>
  855 +void
  856 +checked_negate(R&, T&&, const std::string& text, std::false_type)
  857 +{
  858 + throw_or_mimic<argument_incorrect_type>(text);
  859 +}
884 860  
885   - if (ch >= '0' && ch <= '9')
886   - {
887   - digit = static_cast<US>(ch - '0');
888   - }
889   - else if (base == 16 && ch >= 'a' && ch <= 'f')
890   - {
891   - digit = static_cast<US>(ch - 'a' + 10);
892   - }
893   - else if (base == 16 && ch >= 'A' && ch <= 'F')
894   - {
895   - digit = static_cast<US>(ch - 'A' + 10);
896   - }
897   - else
898   - {
899   - throw_or_mimic<argument_incorrect_type>(text);
900   - }
  861 +template <typename T>
  862 +void
  863 +integer_parser(const std::string& text, T& value)
  864 +{
  865 + parser_tool::IntegerDesc int_desc = parser_tool::SplitInteger(text);
901 866  
902   - const US next = static_cast<US>(result * base + digit);
903   - if (result > next)
904   - {
905   - throw_or_mimic<argument_incorrect_type>(text);
906   - }
  867 + using US = typename std::make_unsigned<T>::type;
  868 + constexpr bool is_signed = std::numeric_limits<T>::is_signed;
907 869  
908   - result = next;
909   - }
  870 + const bool negative = int_desc.negative.length() > 0;
  871 + const uint8_t base = int_desc.base.length() > 0 ? 16 : 10;
  872 + const std::string & value_match = int_desc.value;
910 873  
911   - detail::check_signed_range<T>(negative, result, text);
  874 + US result = 0;
912 875  
913   - if (negative)
914   - {
915   - checked_negate<T>(value, result, text, std::integral_constant<bool, is_signed>());
916   - }
917   - else
918   - {
919   - value = static_cast<T>(result);
920   - }
921   - }
  876 + for (char ch : value_match)
  877 + {
  878 + US digit = 0;
922 879  
923   - template <typename T>
924   - void stringstream_parser(const std::string& text, T& value)
  880 + if (ch >= '0' && ch <= '9')
925 881 {
926   - std::stringstream in(text);
927   - in >> value;
928   - if (!in) {
929   - throw_or_mimic<argument_incorrect_type>(text);
930   - }
  882 + digit = static_cast<US>(ch - '0');
931 883 }
932   -
933   - template <typename T,
934   - typename std::enable_if<std::is_integral<T>::value>::type* = nullptr
935   - >
936   - void parse_value(const std::string& text, T& value)
  884 + else if (base == 16 && ch >= 'a' && ch <= 'f')
937 885 {
938   - integer_parser(text, value);
  886 + digit = static_cast<US>(ch - 'a' + 10);
939 887 }
940   -
941   - inline
942   - void
943   - parse_value(const std::string& text, bool& value)
  888 + else if (base == 16 && ch >= 'A' && ch <= 'F')
  889 + {
  890 + digit = static_cast<US>(ch - 'A' + 10);
  891 + }
  892 + else
944 893 {
945   - if (parser_tool::IsTrueText(text))
946   - {
947   - value = true;
948   - return;
949   - }
950   -
951   - if (parser_tool::IsFalseText(text))
952   - {
953   - value = false;
954   - return;
955   - }
956   -
957 894 throw_or_mimic<argument_incorrect_type>(text);
958 895 }
959 896  
960   - inline
961   - void
962   - parse_value(const std::string& text, std::string& value)
  897 + const US next = static_cast<US>(result * base + digit);
  898 + if (result > next)
963 899 {
964   - value = text;
  900 + throw_or_mimic<argument_incorrect_type>(text);
965 901 }
966 902  
967   - // The fallback parser. It uses the stringstream parser to parse all types
968   - // that have not been overloaded explicitly. It has to be placed in the
969   - // source code before all other more specialized templates.
970   - template <typename T,
971   - typename std::enable_if<!std::is_integral<T>::value>::type* = nullptr
972   - >
973   - void
974   - parse_value(const std::string& text, T& value) {
975   - stringstream_parser(text, value);
976   - }
  903 + result = next;
  904 + }
977 905  
978   - template <typename T>
979   - void
980   - parse_value(const std::string& text, std::vector<T>& value)
981   - {
982   - if (text.empty()) {
983   - T v;
984   - parse_value(text, v);
985   - value.emplace_back(std::move(v));
986   - return;
987   - }
988   - std::stringstream in(text);
989   - std::string token;
990   - while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
991   - T v;
992   - parse_value(token, v);
993   - value.emplace_back(std::move(v));
994   - }
995   - }
  906 + detail::check_signed_range<T>(negative, result, text);
996 907  
997   -#ifdef CXXOPTS_HAS_OPTIONAL
998   - template <typename T>
999   - void
1000   - parse_value(const std::string& text, std::optional<T>& value)
1001   - {
1002   - T result;
1003   - parse_value(text, result);
1004   - value = std::move(result);
1005   - }
1006   -#endif
  908 + if (negative)
  909 + {
  910 + checked_negate<T>(value, result, text, std::integral_constant<bool, is_signed>());
  911 + }
  912 + else
  913 + {
  914 + value = static_cast<T>(result);
  915 + }
  916 +}
1007 917  
1008   - inline
1009   - void parse_value(const std::string& text, char& c)
1010   - {
1011   - if (text.length() != 1)
1012   - {
1013   - throw_or_mimic<argument_incorrect_type>(text);
1014   - }
  918 +template <typename T>
  919 +void stringstream_parser(const std::string& text, T& value)
  920 +{
  921 + std::stringstream in(text);
  922 + in >> value;
  923 + if (!in) {
  924 + throw_or_mimic<argument_incorrect_type>(text);
  925 + }
  926 +}
1015 927  
1016   - c = text[0];
1017   - }
  928 +template <typename T,
  929 + typename std::enable_if<std::is_integral<T>::value>::type* = nullptr
  930 + >
  931 +void parse_value(const std::string& text, T& value)
  932 +{
  933 + integer_parser(text, value);
  934 +}
1018 935  
1019   - template <typename T>
1020   - struct type_is_container
1021   - {
1022   - static constexpr bool value = false;
1023   - };
  936 +inline
  937 +void
  938 +parse_value(const std::string& text, bool& value)
  939 +{
  940 + if (parser_tool::IsTrueText(text))
  941 + {
  942 + value = true;
  943 + return;
  944 + }
1024 945  
1025   - template <typename T>
1026   - struct type_is_container<std::vector<T>>
1027   - {
1028   - static constexpr bool value = true;
1029   - };
  946 + if (parser_tool::IsFalseText(text))
  947 + {
  948 + value = false;
  949 + return;
  950 + }
1030 951  
1031   - template <typename T>
1032   - class abstract_value : public Value
1033   - {
1034   - using Self = abstract_value<T>;
  952 + throw_or_mimic<argument_incorrect_type>(text);
  953 +}
1035 954  
1036   - public:
1037   - abstract_value()
1038   - : m_result(std::make_shared<T>())
1039   - , m_store(m_result.get())
1040   - {
1041   - }
  955 +inline
  956 +void
  957 +parse_value(const std::string& text, std::string& value)
  958 +{
  959 + value = text;
  960 +}
1042 961  
1043   - explicit abstract_value(T* t)
1044   - : m_store(t)
1045   - {
1046   - }
  962 +// The fallback parser. It uses the stringstream parser to parse all types
  963 +// that have not been overloaded explicitly. It has to be placed in the
  964 +// source code before all other more specialized templates.
  965 +template <typename T,
  966 + typename std::enable_if<!std::is_integral<T>::value>::type* = nullptr
  967 + >
  968 +void
  969 +parse_value(const std::string& text, T& value) {
  970 + stringstream_parser(text, value);
  971 +}
1047 972  
1048   - ~abstract_value() override = default;
  973 +template <typename T>
  974 +void
  975 +parse_value(const std::string& text, std::vector<T>& value)
  976 +{
  977 + if (text.empty()) {
  978 + T v;
  979 + parse_value(text, v);
  980 + value.emplace_back(std::move(v));
  981 + return;
  982 + }
  983 + std::stringstream in(text);
  984 + std::string token;
  985 + while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) {
  986 + T v;
  987 + parse_value(token, v);
  988 + value.emplace_back(std::move(v));
  989 + }
  990 +}
1049 991  
1050   - abstract_value& operator=(const abstract_value&) = default;
  992 +#ifdef CXXOPTS_HAS_OPTIONAL
  993 +template <typename T>
  994 +void
  995 +parse_value(const std::string& text, std::optional<T>& value)
  996 +{
  997 + T result;
  998 + parse_value(text, result);
  999 + value = std::move(result);
  1000 +}
  1001 +#endif
1051 1002  
1052   - abstract_value(const abstract_value& rhs)
1053   - {
1054   - if (rhs.m_result)
1055   - {
1056   - m_result = std::make_shared<T>();
1057   - m_store = m_result.get();
1058   - }
1059   - else
1060   - {
1061   - m_store = rhs.m_store;
1062   - }
  1003 +inline
  1004 +void parse_value(const std::string& text, char& c)
  1005 +{
  1006 + if (text.length() != 1)
  1007 + {
  1008 + throw_or_mimic<argument_incorrect_type>(text);
  1009 + }
1063 1010  
1064   - m_default = rhs.m_default;
1065   - m_implicit = rhs.m_implicit;
1066   - m_default_value = rhs.m_default_value;
1067   - m_implicit_value = rhs.m_implicit_value;
1068   - }
  1011 + c = text[0];
  1012 +}
1069 1013  
1070   - void
1071   - parse(const std::string& text) const override
1072   - {
1073   - parse_value(text, *m_store);
1074   - }
  1014 +template <typename T>
  1015 +struct type_is_container
  1016 +{
  1017 + static constexpr bool value = false;
  1018 +};
1075 1019  
1076   - bool
1077   - is_container() const override
1078   - {
1079   - return type_is_container<T>::value;
1080   - }
  1020 +template <typename T>
  1021 +struct type_is_container<std::vector<T>>
  1022 +{
  1023 + static constexpr bool value = true;
  1024 +};
1081 1025  
1082   - void
1083   - parse() const override
1084   - {
1085   - parse_value(m_default_value, *m_store);
1086   - }
  1026 +template <typename T>
  1027 +class abstract_value : public Value
  1028 +{
  1029 + using Self = abstract_value<T>;
1087 1030  
1088   - bool
1089   - has_default() const override
1090   - {
1091   - return m_default;
1092   - }
  1031 + public:
  1032 + abstract_value()
  1033 + : m_result(std::make_shared<T>())
  1034 + , m_store(m_result.get())
  1035 + {
  1036 + }
1093 1037  
1094   - bool
1095   - has_implicit() const override
1096   - {
1097   - return m_implicit;
1098   - }
  1038 + explicit abstract_value(T* t)
  1039 + : m_store(t)
  1040 + {
  1041 + }
1099 1042  
1100   - std::shared_ptr<Value>
1101   - default_value(const std::string& value) override
1102   - {
1103   - m_default = true;
1104   - m_default_value = value;
1105   - return shared_from_this();
1106   - }
  1043 + ~abstract_value() override = default;
1107 1044  
1108   - std::shared_ptr<Value>
1109   - implicit_value(const std::string& value) override
1110   - {
1111   - m_implicit = true;
1112   - m_implicit_value = value;
1113   - return shared_from_this();
1114   - }
  1045 + abstract_value& operator=(const abstract_value&) = default;
1115 1046  
1116   - std::shared_ptr<Value>
1117   - no_implicit_value() override
1118   - {
1119   - m_implicit = false;
1120   - return shared_from_this();
1121   - }
  1047 + abstract_value(const abstract_value& rhs)
  1048 + {
  1049 + if (rhs.m_result)
  1050 + {
  1051 + m_result = std::make_shared<T>();
  1052 + m_store = m_result.get();
  1053 + }
  1054 + else
  1055 + {
  1056 + m_store = rhs.m_store;
  1057 + }
1122 1058  
1123   - std::string
1124   - get_default_value() const override
1125   - {
1126   - return m_default_value;
1127   - }
  1059 + m_default = rhs.m_default;
  1060 + m_implicit = rhs.m_implicit;
  1061 + m_default_value = rhs.m_default_value;
  1062 + m_implicit_value = rhs.m_implicit_value;
  1063 + }
1128 1064  
1129   - std::string
1130   - get_implicit_value() const override
1131   - {
1132   - return m_implicit_value;
1133   - }
  1065 + void
  1066 + parse(const std::string& text) const override
  1067 + {
  1068 + parse_value(text, *m_store);
  1069 + }
1134 1070  
1135   - bool
1136   - is_boolean() const override
1137   - {
1138   - return std::is_same<T, bool>::value;
1139   - }
  1071 + bool
  1072 + is_container() const override
  1073 + {
  1074 + return type_is_container<T>::value;
  1075 + }
1140 1076  
1141   - const T&
1142   - get() const
1143   - {
1144   - if (m_store == nullptr)
1145   - {
1146   - return *m_result;
1147   - }
1148   - return *m_store;
1149   - }
  1077 + void
  1078 + parse() const override
  1079 + {
  1080 + parse_value(m_default_value, *m_store);
  1081 + }
1150 1082  
1151   - protected:
1152   - std::shared_ptr<T> m_result{};
1153   - T* m_store{};
  1083 + bool
  1084 + has_default() const override
  1085 + {
  1086 + return m_default;
  1087 + }
1154 1088  
1155   - bool m_default = false;
1156   - bool m_implicit = false;
  1089 + bool
  1090 + has_implicit() const override
  1091 + {
  1092 + return m_implicit;
  1093 + }
1157 1094  
1158   - std::string m_default_value{};
1159   - std::string m_implicit_value{};
1160   - };
  1095 + std::shared_ptr<Value>
  1096 + default_value(const std::string& value) override
  1097 + {
  1098 + m_default = true;
  1099 + m_default_value = value;
  1100 + return shared_from_this();
  1101 + }
1161 1102  
1162   - template <typename T>
1163   - class standard_value : public abstract_value<T>
1164   - {
1165   - public:
1166   - using abstract_value<T>::abstract_value;
  1103 + std::shared_ptr<Value>
  1104 + implicit_value(const std::string& value) override
  1105 + {
  1106 + m_implicit = true;
  1107 + m_implicit_value = value;
  1108 + return shared_from_this();
  1109 + }
1167 1110  
1168   - CXXOPTS_NODISCARD
1169   - std::shared_ptr<Value>
1170   - clone() const override
1171   - {
1172   - return std::make_shared<standard_value<T>>(*this);
1173   - }
1174   - };
  1111 + std::shared_ptr<Value>
  1112 + no_implicit_value() override
  1113 + {
  1114 + m_implicit = false;
  1115 + return shared_from_this();
  1116 + }
1175 1117  
1176   - template <>
1177   - class standard_value<bool> : public abstract_value<bool>
1178   - {
1179   - public:
1180   - ~standard_value() override = default;
  1118 + std::string
  1119 + get_default_value() const override
  1120 + {
  1121 + return m_default_value;
  1122 + }
1181 1123  
1182   - standard_value()
1183   - {
1184   - set_default_and_implicit();
1185   - }
  1124 + std::string
  1125 + get_implicit_value() const override
  1126 + {
  1127 + return m_implicit_value;
  1128 + }
1186 1129  
1187   - explicit standard_value(bool* b)
1188   - : abstract_value(b)
1189   - {
1190   - set_default_and_implicit();
1191   - }
  1130 + bool
  1131 + is_boolean() const override
  1132 + {
  1133 + return std::is_same<T, bool>::value;
  1134 + }
1192 1135  
1193   - std::shared_ptr<Value>
1194   - clone() const override
1195   - {
1196   - return std::make_shared<standard_value<bool>>(*this);
1197   - }
  1136 + const T&
  1137 + get() const
  1138 + {
  1139 + if (m_store == nullptr)
  1140 + {
  1141 + return *m_result;
  1142 + }
  1143 + return *m_store;
  1144 + }
1198 1145  
1199   - private:
  1146 + protected:
  1147 + std::shared_ptr<T> m_result{};
  1148 + T* m_store{};
1200 1149  
1201   - void
1202   - set_default_and_implicit()
1203   - {
1204   - m_default = true;
1205   - m_default_value = "false";
1206   - m_implicit = true;
1207   - m_implicit_value = "true";
1208   - }
1209   - };
1210   - } // namespace values
  1150 + bool m_default = false;
  1151 + bool m_implicit = false;
1211 1152  
1212   - template <typename T>
  1153 + std::string m_default_value{};
  1154 + std::string m_implicit_value{};
  1155 +};
  1156 +
  1157 +template <typename T>
  1158 +class standard_value : public abstract_value<T>
  1159 +{
  1160 + public:
  1161 + using abstract_value<T>::abstract_value;
  1162 +
  1163 + CXXOPTS_NODISCARD
1213 1164 std::shared_ptr<Value>
1214   - value()
  1165 + clone() const override
1215 1166 {
1216   - return std::make_shared<values::standard_value<T>>();
  1167 + return std::make_shared<standard_value<T>>(*this);
  1168 + }
  1169 +};
  1170 +
  1171 +template <>
  1172 +class standard_value<bool> : public abstract_value<bool>
  1173 +{
  1174 + public:
  1175 + ~standard_value() override = default;
  1176 +
  1177 + standard_value()
  1178 + {
  1179 + set_default_and_implicit();
  1180 + }
  1181 +
  1182 + explicit standard_value(bool* b)
  1183 + : abstract_value(b)
  1184 + {
  1185 + set_default_and_implicit();
1217 1186 }
1218 1187  
1219   - template <typename T>
1220 1188 std::shared_ptr<Value>
1221   - value(T& t)
  1189 + clone() const override
1222 1190 {
1223   - return std::make_shared<values::standard_value<T>>(&t);
  1191 + return std::make_shared<standard_value<bool>>(*this);
1224 1192 }
1225 1193  
1226   - class OptionAdder;
  1194 + private:
1227 1195  
1228   - class OptionDetails
  1196 + void
  1197 + set_default_and_implicit()
1229 1198 {
1230   - public:
1231   - OptionDetails
1232   - (
1233   - std::string short_,
1234   - std::string long_,
1235   - String desc,
1236   - std::shared_ptr<const Value> val
1237   - )
1238   - : m_short(std::move(short_))
1239   - , m_long(std::move(long_))
1240   - , m_desc(std::move(desc))
1241   - , m_value(std::move(val))
1242   - , m_count(0)
1243   - {
1244   - m_hash = std::hash<std::string>{}(m_long + m_short);
1245   - }
  1199 + m_default = true;
  1200 + m_default_value = "false";
  1201 + m_implicit = true;
  1202 + m_implicit_value = "true";
  1203 + }
  1204 +};
  1205 +} // namespace values
1246 1206  
1247   - OptionDetails(const OptionDetails& rhs)
1248   - : m_desc(rhs.m_desc)
1249   - , m_value(rhs.m_value->clone())
1250   - , m_count(rhs.m_count)
1251   - {
1252   - }
  1207 +template <typename T>
  1208 +std::shared_ptr<Value>
  1209 +value()
  1210 +{
  1211 + return std::make_shared<values::standard_value<T>>();
  1212 +}
1253 1213  
1254   - OptionDetails(OptionDetails&& rhs) = default;
  1214 +template <typename T>
  1215 +std::shared_ptr<Value>
  1216 +value(T& t)
  1217 +{
  1218 + return std::make_shared<values::standard_value<T>>(&t);
  1219 +}
1255 1220  
1256   - CXXOPTS_NODISCARD
1257   - const String&
1258   - description() const
1259   - {
1260   - return m_desc;
1261   - }
  1221 +class OptionAdder;
1262 1222  
1263   - CXXOPTS_NODISCARD
1264   - const Value&
1265   - value() const {
1266   - return *m_value;
1267   - }
  1223 +class OptionDetails
  1224 +{
  1225 + public:
  1226 + OptionDetails
  1227 + (
  1228 + std::string short_,
  1229 + std::string long_,
  1230 + String desc,
  1231 + std::shared_ptr<const Value> val
  1232 + )
  1233 + : m_short(std::move(short_))
  1234 + , m_long(std::move(long_))
  1235 + , m_desc(std::move(desc))
  1236 + , m_value(std::move(val))
  1237 + , m_count(0)
  1238 + {
  1239 + m_hash = std::hash<std::string>{}(m_long + m_short);
  1240 + }
1268 1241  
1269   - CXXOPTS_NODISCARD
1270   - std::shared_ptr<Value>
1271   - make_storage() const
1272   - {
1273   - return m_value->clone();
1274   - }
  1242 + OptionDetails(const OptionDetails& rhs)
  1243 + : m_desc(rhs.m_desc)
  1244 + , m_value(rhs.m_value->clone())
  1245 + , m_count(rhs.m_count)
  1246 + {
  1247 + }
1275 1248  
1276   - CXXOPTS_NODISCARD
1277   - const std::string&
1278   - short_name() const
1279   - {
1280   - return m_short;
1281   - }
  1249 + OptionDetails(OptionDetails&& rhs) = default;
1282 1250  
1283   - CXXOPTS_NODISCARD
1284   - const std::string&
1285   - long_name() const
1286   - {
1287   - return m_long;
1288   - }
  1251 + CXXOPTS_NODISCARD
  1252 + const String&
  1253 + description() const
  1254 + {
  1255 + return m_desc;
  1256 + }
1289 1257  
1290   - CXXOPTS_NODISCARD
1291   - const std::string&
1292   - essential_name() const
1293   - {
1294   - return m_long.empty() ? m_short : m_long;
1295   - }
  1258 + CXXOPTS_NODISCARD
  1259 + const Value&
  1260 + value() const {
  1261 + return *m_value;
  1262 + }
1296 1263  
1297   - size_t
1298   - hash() const
1299   - {
1300   - return m_hash;
1301   - }
  1264 + CXXOPTS_NODISCARD
  1265 + std::shared_ptr<Value>
  1266 + make_storage() const
  1267 + {
  1268 + return m_value->clone();
  1269 + }
1302 1270  
1303   - private:
1304   - std::string m_short{};
1305   - std::string m_long{};
1306   - String m_desc{};
1307   - std::shared_ptr<const Value> m_value{};
1308   - int m_count;
  1271 + CXXOPTS_NODISCARD
  1272 + const std::string&
  1273 + short_name() const
  1274 + {
  1275 + return m_short;
  1276 + }
1309 1277  
1310   - size_t m_hash{};
1311   - };
  1278 + CXXOPTS_NODISCARD
  1279 + const std::string&
  1280 + long_name() const
  1281 + {
  1282 + return m_long;
  1283 + }
1312 1284  
1313   - struct HelpOptionDetails
1314   - {
1315   - std::string s;
1316   - std::string l;
1317   - String desc;
1318   - bool has_default;
1319   - std::string default_value;
1320   - bool has_implicit;
1321   - std::string implicit_value;
1322   - std::string arg_help;
1323   - bool is_container;
1324   - bool is_boolean;
1325   - };
  1285 + CXXOPTS_NODISCARD
  1286 + const std::string&
  1287 + essential_name() const
  1288 + {
  1289 + return m_long.empty() ? m_short : m_long;
  1290 + }
1326 1291  
1327   - struct HelpGroupDetails
  1292 + size_t
  1293 + hash() const
1328 1294 {
1329   - std::string name{};
1330   - std::string description{};
1331   - std::vector<HelpOptionDetails> options{};
1332   - };
  1295 + return m_hash;
  1296 + }
  1297 +
  1298 + private:
  1299 + std::string m_short{};
  1300 + std::string m_long{};
  1301 + String m_desc{};
  1302 + std::shared_ptr<const Value> m_value{};
  1303 + int m_count;
  1304 +
  1305 + size_t m_hash{};
  1306 +};
  1307 +
  1308 +struct HelpOptionDetails
  1309 +{
  1310 + std::string s;
  1311 + std::string l;
  1312 + String desc;
  1313 + bool has_default;
  1314 + std::string default_value;
  1315 + bool has_implicit;
  1316 + std::string implicit_value;
  1317 + std::string arg_help;
  1318 + bool is_container;
  1319 + bool is_boolean;
  1320 +};
  1321 +
  1322 +struct HelpGroupDetails
  1323 +{
  1324 + std::string name{};
  1325 + std::string description{};
  1326 + std::vector<HelpOptionDetails> options{};
  1327 +};
1333 1328  
1334   - class OptionValue
  1329 +class OptionValue
  1330 +{
  1331 + public:
  1332 + void
  1333 + parse
  1334 + (
  1335 + const std::shared_ptr<const OptionDetails>& details,
  1336 + const std::string& text
  1337 + )
1335 1338 {
1336   - public:
1337   - void
1338   - parse
1339   - (
1340   - const std::shared_ptr<const OptionDetails>& details,
1341   - const std::string& text
1342   - )
1343   - {
1344   - ensure_value(details);
1345   - ++m_count;
1346   - m_value->parse(text);
1347   - m_long_name = &details->long_name();
1348   - }
  1339 + ensure_value(details);
  1340 + ++m_count;
  1341 + m_value->parse(text);
  1342 + m_long_name = &details->long_name();
  1343 + }
1349 1344  
1350   - void
1351   - parse_default(const std::shared_ptr<const OptionDetails>& details)
1352   - {
1353   - ensure_value(details);
1354   - m_default = true;
1355   - m_long_name = &details->long_name();
1356   - m_value->parse();
1357   - }
  1345 + void
  1346 + parse_default(const std::shared_ptr<const OptionDetails>& details)
  1347 + {
  1348 + ensure_value(details);
  1349 + m_default = true;
  1350 + m_long_name = &details->long_name();
  1351 + m_value->parse();
  1352 + }
1358 1353  
1359   - void
1360   - parse_no_value(const std::shared_ptr<const OptionDetails>& details)
1361   - {
1362   - m_long_name = &details->long_name();
1363   - }
  1354 + void
  1355 + parse_no_value(const std::shared_ptr<const OptionDetails>& details)
  1356 + {
  1357 + m_long_name = &details->long_name();
  1358 + }
1364 1359  
1365 1360 #if defined(CXXOPTS_NULL_DEREF_IGNORE)
1366 1361 #pragma GCC diagnostic push
1367 1362 #pragma GCC diagnostic ignored "-Wnull-dereference"
1368 1363 #endif
1369 1364  
1370   - CXXOPTS_NODISCARD
1371   - size_t
1372   - count() const noexcept
1373   - {
1374   - return m_count;
1375   - }
  1365 + CXXOPTS_NODISCARD
  1366 + size_t
  1367 + count() const noexcept
  1368 + {
  1369 + return m_count;
  1370 + }
1376 1371  
1377 1372 #if defined(CXXOPTS_NULL_DEREF_IGNORE)
1378 1373 #pragma GCC diagnostic pop
1379 1374 #endif
1380 1375  
1381   - // TODO: maybe default options should count towards the number of arguments
1382   - CXXOPTS_NODISCARD
1383   - bool
1384   - has_default() const noexcept
1385   - {
1386   - return m_default;
1387   - }
  1376 + // TODO: maybe default options should count towards the number of arguments
  1377 + CXXOPTS_NODISCARD
  1378 + bool
  1379 + has_default() const noexcept
  1380 + {
  1381 + return m_default;
  1382 + }
1388 1383  
1389   - template <typename T>
1390   - const T&
1391   - as() const
1392   - {
1393   - if (m_value == nullptr) {
1394   - throw_or_mimic<option_has_no_value_exception>(
1395   - m_long_name == nullptr ? "" : *m_long_name);
1396   - }
  1384 + template <typename T>
  1385 + const T&
  1386 + as() const
  1387 + {
  1388 + if (m_value == nullptr) {
  1389 + throw_or_mimic<option_has_no_value_exception>(
  1390 + m_long_name == nullptr ? "" : *m_long_name);
  1391 + }
1397 1392  
1398 1393 #ifdef CXXOPTS_NO_RTTI
1399   - return static_cast<const values::standard_value<T>&>(*m_value).get();
  1394 + return static_cast<const values::standard_value<T>&>(*m_value).get();
1400 1395 #else
1401   - return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
  1396 + return dynamic_cast<const values::standard_value<T>&>(*m_value).get();
1402 1397 #endif
1403   - }
1404   -
1405   - private:
1406   - void
1407   - ensure_value(const std::shared_ptr<const OptionDetails>& details)
1408   - {
1409   - if (m_value == nullptr)
1410   - {
1411   - m_value = details->make_storage();
1412   - }
1413   - }
1414   -
1415   -
1416   - const std::string* m_long_name = nullptr;
1417   - // Holding this pointer is safe, since OptionValue's only exist in key-value pairs,
1418   - // where the key has the string we point to.
1419   - std::shared_ptr<Value> m_value{};
1420   - size_t m_count = 0;
1421   - bool m_default = false;
1422   - };
  1398 + }
1423 1399  
1424   - class KeyValue
  1400 + private:
  1401 + void
  1402 + ensure_value(const std::shared_ptr<const OptionDetails>& details)
1425 1403 {
1426   - public:
1427   - KeyValue(std::string key_, std::string value_)
1428   - : m_key(std::move(key_))
1429   - , m_value(std::move(value_))
1430   - {
1431   - }
1432   -
1433   - CXXOPTS_NODISCARD
1434   - const std::string&
1435   - key() const
  1404 + if (m_value == nullptr)
1436 1405 {
1437   - return m_key;
  1406 + m_value = details->make_storage();
1438 1407 }
  1408 + }
1439 1409  
1440   - CXXOPTS_NODISCARD
1441   - const std::string&
1442   - value() const
1443   - {
1444   - return m_value;
1445   - }
1446 1410  
1447   - template <typename T>
1448   - T
1449   - as() const
1450   - {
1451   - T result;
1452   - values::parse_value(m_value, result);
1453   - return result;
1454   - }
  1411 + const std::string* m_long_name = nullptr;
  1412 + // Holding this pointer is safe, since OptionValue's only exist in key-value pairs,
  1413 + // where the key has the string we point to.
  1414 + std::shared_ptr<Value> m_value{};
  1415 + size_t m_count = 0;
  1416 + bool m_default = false;
  1417 +};
1455 1418  
1456   - private:
1457   - std::string m_key;
1458   - std::string m_value;
1459   - };
  1419 +class KeyValue
  1420 +{
  1421 + public:
  1422 + KeyValue(std::string key_, std::string value_)
  1423 + : m_key(std::move(key_))
  1424 + , m_value(std::move(value_))
  1425 + {
  1426 + }
1460 1427  
1461   - using ParsedHashMap = std::unordered_map<size_t, OptionValue>;
1462   - using NameHashMap = std::unordered_map<std::string, size_t>;
  1428 + CXXOPTS_NODISCARD
  1429 + const std::string&
  1430 + key() const
  1431 + {
  1432 + return m_key;
  1433 + }
1463 1434  
1464   - class ParseResult
  1435 + CXXOPTS_NODISCARD
  1436 + const std::string&
  1437 + value() const
1465 1438 {
1466   - public:
1467   - class Iterator
1468   - {
1469   - public:
1470   - using iterator_category = std::forward_iterator_tag;
1471   - using value_type = KeyValue;
1472   - using difference_type = void;
1473   - using pointer = const KeyValue*;
1474   - using reference = const KeyValue&;
1475   -
1476   - Iterator() = default;
1477   - Iterator(const Iterator&) = default;
1478   -
1479   - Iterator(const ParseResult *pr, bool end=false)
1480   - : m_pr(pr)
1481   - , m_iter(end? pr->m_defaults.end(): pr->m_sequential.begin())
1482   - {
1483   - }
  1439 + return m_value;
  1440 + }
1484 1441  
1485   - Iterator& operator++()
1486   - {
1487   - ++m_iter;
1488   - if(m_iter == m_pr->m_sequential.end())
1489   - {
1490   - m_iter = m_pr->m_defaults.begin();
1491   - return *this;
1492   - }
1493   - return *this;
1494   - }
  1442 + template <typename T>
  1443 + T
  1444 + as() const
  1445 + {
  1446 + T result;
  1447 + values::parse_value(m_value, result);
  1448 + return result;
  1449 + }
1495 1450  
1496   - Iterator operator++(int)
1497   - {
1498   - Iterator retval = *this;
1499   - ++(*this);
1500   - return retval;
1501   - }
  1451 + private:
  1452 + std::string m_key;
  1453 + std::string m_value;
  1454 +};
1502 1455  
1503   - bool operator==(const Iterator& other) const
1504   - {
1505   - return m_iter == other.m_iter;
1506   - }
  1456 +using ParsedHashMap = std::unordered_map<size_t, OptionValue>;
  1457 +using NameHashMap = std::unordered_map<std::string, size_t>;
1507 1458  
1508   - bool operator!=(const Iterator& other) const
1509   - {
1510   - return !(*this == other);
1511   - }
  1459 +class ParseResult
  1460 +{
  1461 + public:
  1462 + class Iterator
  1463 + {
  1464 + public:
  1465 + using iterator_category = std::forward_iterator_tag;
  1466 + using value_type = KeyValue;
  1467 + using difference_type = void;
  1468 + using pointer = const KeyValue*;
  1469 + using reference = const KeyValue&;
1512 1470  
1513   - const KeyValue& operator*()
1514   - {
1515   - return *m_iter;
1516   - }
  1471 + Iterator() = default;
  1472 + Iterator(const Iterator&) = default;
  1473 +
  1474 + Iterator(const ParseResult *pr, bool end=false)
  1475 + : m_pr(pr)
  1476 + , m_iter(end? pr->m_defaults.end(): pr->m_sequential.begin())
  1477 + {
  1478 + }
1517 1479  
1518   - const KeyValue* operator->()
  1480 + Iterator& operator++()
  1481 + {
  1482 + ++m_iter;
  1483 + if(m_iter == m_pr->m_sequential.end())
1519 1484 {
1520   - return m_iter.operator->();
  1485 + m_iter = m_pr->m_defaults.begin();
  1486 + return *this;
1521 1487 }
  1488 + return *this;
  1489 + }
1522 1490  
1523   - private:
1524   - const ParseResult* m_pr;
1525   - std::vector<KeyValue>::const_iterator m_iter;
1526   - };
1527   -
1528   - ParseResult() = default;
1529   - ParseResult(const ParseResult&) = default;
1530   -
1531   - ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<KeyValue> sequential,
1532   - std::vector<KeyValue> default_opts, std::vector<std::string>&& unmatched_args)
1533   - : m_keys(std::move(keys))
1534   - , m_values(std::move(values))
1535   - , m_sequential(std::move(sequential))
1536   - , m_defaults(std::move(default_opts))
1537   - , m_unmatched(std::move(unmatched_args))
  1491 + Iterator operator++(int)
1538 1492 {
  1493 + Iterator retval = *this;
  1494 + ++(*this);
  1495 + return retval;
1539 1496 }
1540 1497  
1541   - ParseResult& operator=(ParseResult&&) = default;
1542   - ParseResult& operator=(const ParseResult&) = default;
1543   -
1544   - Iterator
1545   - begin() const
  1498 + bool operator==(const Iterator& other) const
1546 1499 {
1547   - return Iterator(this);
  1500 + return m_iter == other.m_iter;
1548 1501 }
1549 1502  
1550   - Iterator
1551   - end() const
  1503 + bool operator!=(const Iterator& other) const
1552 1504 {
1553   - return Iterator(this, true);
  1505 + return !(*this == other);
1554 1506 }
1555 1507  
1556   - size_t
1557   - count(const std::string& o) const
  1508 + const KeyValue& operator*()
1558 1509 {
1559   - auto iter = m_keys.find(o);
1560   - if (iter == m_keys.end())
1561   - {
1562   - return 0;
1563   - }
1564   -
1565   - auto viter = m_values.find(iter->second);
1566   -
1567   - if (viter == m_values.end())
1568   - {
1569   - return 0;
1570   - }
1571   -
1572   - return viter->second.count();
  1510 + return *m_iter;
1573 1511 }
1574 1512  
1575   - const OptionValue&
1576   - operator[](const std::string& option) const
  1513 + const KeyValue* operator->()
1577 1514 {
1578   - auto iter = m_keys.find(option);
  1515 + return m_iter.operator->();
  1516 + }
1579 1517  
1580   - if (iter == m_keys.end())
1581   - {
1582   - throw_or_mimic<option_not_present_exception>(option);
1583   - }
  1518 + private:
  1519 + const ParseResult* m_pr;
  1520 + std::vector<KeyValue>::const_iterator m_iter;
  1521 + };
1584 1522  
1585   - auto viter = m_values.find(iter->second);
  1523 + ParseResult() = default;
  1524 + ParseResult(const ParseResult&) = default;
1586 1525  
1587   - if (viter == m_values.end())
1588   - {
1589   - throw_or_mimic<option_not_present_exception>(option);
1590   - }
  1526 + ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector<KeyValue> sequential,
  1527 + std::vector<KeyValue> default_opts, std::vector<std::string>&& unmatched_args)
  1528 + : m_keys(std::move(keys))
  1529 + , m_values(std::move(values))
  1530 + , m_sequential(std::move(sequential))
  1531 + , m_defaults(std::move(default_opts))
  1532 + , m_unmatched(std::move(unmatched_args))
  1533 + {
  1534 + }
1591 1535  
1592   - return viter->second;
1593   - }
  1536 + ParseResult& operator=(ParseResult&&) = default;
  1537 + ParseResult& operator=(const ParseResult&) = default;
1594 1538  
1595   - const std::vector<KeyValue>&
1596   - arguments() const
  1539 + Iterator
  1540 + begin() const
  1541 + {
  1542 + return Iterator(this);
  1543 + }
  1544 +
  1545 + Iterator
  1546 + end() const
  1547 + {
  1548 + return Iterator(this, true);
  1549 + }
  1550 +
  1551 + size_t
  1552 + count(const std::string& o) const
  1553 + {
  1554 + auto iter = m_keys.find(o);
  1555 + if (iter == m_keys.end())
1597 1556 {
1598   - return m_sequential;
  1557 + return 0;
1599 1558 }
1600 1559  
1601   - const std::vector<std::string>&
1602   - unmatched() const
  1560 + auto viter = m_values.find(iter->second);
  1561 +
  1562 + if (viter == m_values.end())
1603 1563 {
1604   - return m_unmatched;
  1564 + return 0;
1605 1565 }
1606 1566  
1607   - const std::vector<KeyValue>&
1608   - defaults() const
  1567 + return viter->second.count();
  1568 + }
  1569 +
  1570 + const OptionValue&
  1571 + operator[](const std::string& option) const
  1572 + {
  1573 + auto iter = m_keys.find(option);
  1574 +
  1575 + if (iter == m_keys.end())
1609 1576 {
1610   - return m_defaults;
  1577 + throw_or_mimic<option_not_present_exception>(option);
1611 1578 }
1612 1579  
1613   - const std::string
1614   - arguments_string() const
  1580 + auto viter = m_values.find(iter->second);
  1581 +
  1582 + if (viter == m_values.end())
1615 1583 {
1616   - std::string result;
1617   - for(const auto& kv: m_sequential)
1618   - {
1619   - result += kv.key() + " = " + kv.value() + "\n";
1620   - }
1621   - for(const auto& kv: m_defaults)
1622   - {
1623   - result += kv.key() + " = " + kv.value() + " " + "(default)" + "\n";
1624   - }
1625   - return result;
  1584 + throw_or_mimic<option_not_present_exception>(option);
1626 1585 }
1627 1586  
1628   - private:
1629   - NameHashMap m_keys{};
1630   - ParsedHashMap m_values{};
1631   - std::vector<KeyValue> m_sequential{};
1632   - std::vector<KeyValue> m_defaults{};
1633   - std::vector<std::string> m_unmatched{};
1634   - };
  1587 + return viter->second;
  1588 + }
1635 1589  
1636   - struct Option
  1590 + const std::vector<KeyValue>&
  1591 + arguments() const
1637 1592 {
1638   - Option
1639   - (
1640   - std::string opts,
1641   - std::string desc,
1642   - std::shared_ptr<const Value> value = ::cxxopts::value<bool>(),
1643   - std::string arg_help = ""
1644   - )
1645   - : opts_(std::move(opts))
1646   - , desc_(std::move(desc))
1647   - , value_(std::move(value))
1648   - , arg_help_(std::move(arg_help))
1649   - {
1650   - }
  1593 + return m_sequential;
  1594 + }
1651 1595  
1652   - std::string opts_;
1653   - std::string desc_;
1654   - std::shared_ptr<const Value> value_;
1655   - std::string arg_help_;
1656   - };
  1596 + const std::vector<std::string>&
  1597 + unmatched() const
  1598 + {
  1599 + return m_unmatched;
  1600 + }
1657 1601  
1658   - using OptionMap = std::unordered_map<std::string, std::shared_ptr<OptionDetails>>;
1659   - using PositionalList = std::vector<std::string>;
1660   - using PositionalListIterator = PositionalList::const_iterator;
  1602 + const std::vector<KeyValue>&
  1603 + defaults() const
  1604 + {
  1605 + return m_defaults;
  1606 + }
1661 1607  
1662   - class OptionParser
  1608 + const std::string
  1609 + arguments_string() const
1663 1610 {
1664   - public:
1665   - OptionParser(const OptionMap& options, const PositionalList& positional, bool allow_unrecognised)
1666   - : m_options(options)
1667   - , m_positional(positional)
1668   - , m_allow_unrecognised(allow_unrecognised)
  1611 + std::string result;
  1612 + for(const auto& kv: m_sequential)
1669 1613 {
  1614 + result += kv.key() + " = " + kv.value() + "\n";
1670 1615 }
  1616 + for(const auto& kv: m_defaults)
  1617 + {
  1618 + result += kv.key() + " = " + kv.value() + " " + "(default)" + "\n";
  1619 + }
  1620 + return result;
  1621 + }
1671 1622  
1672   - ParseResult
1673   - parse(int argc, const char* const* argv);
  1623 + private:
  1624 + NameHashMap m_keys{};
  1625 + ParsedHashMap m_values{};
  1626 + std::vector<KeyValue> m_sequential{};
  1627 + std::vector<KeyValue> m_defaults{};
  1628 + std::vector<std::string> m_unmatched{};
  1629 +};
1674 1630  
1675   - bool
1676   - consume_positional(const std::string& a, PositionalListIterator& next);
  1631 +struct Option
  1632 +{
  1633 + Option
  1634 + (
  1635 + std::string opts,
  1636 + std::string desc,
  1637 + std::shared_ptr<const Value> value = ::cxxopts::value<bool>(),
  1638 + std::string arg_help = ""
  1639 + )
  1640 + : opts_(std::move(opts))
  1641 + , desc_(std::move(desc))
  1642 + , value_(std::move(value))
  1643 + , arg_help_(std::move(arg_help))
  1644 + {
  1645 + }
1677 1646  
1678   - void
1679   - checked_parse_arg
1680   - (
1681   - int argc,
1682   - const char* const* argv,
1683   - int& current,
1684   - const std::shared_ptr<OptionDetails>& value,
1685   - const std::string& name
1686   - );
  1647 + std::string opts_;
  1648 + std::string desc_;
  1649 + std::shared_ptr<const Value> value_;
  1650 + std::string arg_help_;
  1651 +};
1687 1652  
1688   - void
1689   - add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg);
  1653 +using OptionMap = std::unordered_map<std::string, std::shared_ptr<OptionDetails>>;
  1654 +using PositionalList = std::vector<std::string>;
  1655 +using PositionalListIterator = PositionalList::const_iterator;
1690 1656  
1691   - void
1692   - parse_option
1693   - (
1694   - const std::shared_ptr<OptionDetails>& value,
1695   - const std::string& name,
1696   - const std::string& arg = ""
1697   - );
  1657 +class OptionParser
  1658 +{
  1659 + public:
  1660 + OptionParser(const OptionMap& options, const PositionalList& positional, bool allow_unrecognised)
  1661 + : m_options(options)
  1662 + , m_positional(positional)
  1663 + , m_allow_unrecognised(allow_unrecognised)
  1664 + {
  1665 + }
1698 1666  
1699   - void
1700   - parse_default(const std::shared_ptr<OptionDetails>& details);
  1667 + ParseResult
  1668 + parse(int argc, const char* const* argv);
1701 1669  
1702   - void
1703   - parse_no_value(const std::shared_ptr<OptionDetails>& details);
  1670 + bool
  1671 + consume_positional(const std::string& a, PositionalListIterator& next);
1704 1672  
1705   - private:
  1673 + void
  1674 + checked_parse_arg
  1675 + (
  1676 + int argc,
  1677 + const char* const* argv,
  1678 + int& current,
  1679 + const std::shared_ptr<OptionDetails>& value,
  1680 + const std::string& name
  1681 + );
1706 1682  
1707   - void finalise_aliases();
  1683 + void
  1684 + add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg);
1708 1685  
1709   - const OptionMap& m_options;
1710   - const PositionalList& m_positional;
  1686 + void
  1687 + parse_option
  1688 + (
  1689 + const std::shared_ptr<OptionDetails>& value,
  1690 + const std::string& name,
  1691 + const std::string& arg = ""
  1692 + );
1711 1693  
1712   - std::vector<KeyValue> m_sequential{};
1713   - std::vector<KeyValue> m_defaults{};
1714   - bool m_allow_unrecognised;
  1694 + void
  1695 + parse_default(const std::shared_ptr<OptionDetails>& details);
1715 1696  
1716   - ParsedHashMap m_parsed{};
1717   - NameHashMap m_keys{};
1718   - };
  1697 + void
  1698 + parse_no_value(const std::shared_ptr<OptionDetails>& details);
  1699 +
  1700 + private:
  1701 +
  1702 + void finalise_aliases();
  1703 +
  1704 + const OptionMap& m_options;
  1705 + const PositionalList& m_positional;
  1706 +
  1707 + std::vector<KeyValue> m_sequential{};
  1708 + std::vector<KeyValue> m_defaults{};
  1709 + bool m_allow_unrecognised;
  1710 +
  1711 + ParsedHashMap m_parsed{};
  1712 + NameHashMap m_keys{};
  1713 +};
1719 1714  
1720   - class Options
  1715 +class Options
  1716 +{
  1717 + public:
  1718 +
  1719 + explicit Options(std::string program, std::string help_string = "")
  1720 + : m_program(std::move(program))
  1721 + , m_help_string(toLocalString(std::move(help_string)))
  1722 + , m_custom_help("[OPTION...]")
  1723 + , m_positional_help("positional parameters")
  1724 + , m_show_positional(false)
  1725 + , m_allow_unrecognised(false)
  1726 + , m_width(76)
  1727 + , m_tab_expansion(false)
  1728 + , m_options(std::make_shared<OptionMap>())
1721 1729 {
1722   - public:
  1730 + }
1723 1731  
1724   - explicit Options(std::string program, std::string help_string = "")
1725   - : m_program(std::move(program))
1726   - , m_help_string(toLocalString(std::move(help_string)))
1727   - , m_custom_help("[OPTION...]")
1728   - , m_positional_help("positional parameters")
1729   - , m_show_positional(false)
1730   - , m_allow_unrecognised(false)
1731   - , m_width(76)
1732   - , m_tab_expansion(false)
1733   - , m_options(std::make_shared<OptionMap>())
1734   - {
1735   - }
  1732 + Options&
  1733 + positional_help(std::string help_text)
  1734 + {
  1735 + m_positional_help = std::move(help_text);
  1736 + return *this;
  1737 + }
1736 1738  
1737   - Options&
1738   - positional_help(std::string help_text)
1739   - {
1740   - m_positional_help = std::move(help_text);
1741   - return *this;
1742   - }
  1739 + Options&
  1740 + custom_help(std::string help_text)
  1741 + {
  1742 + m_custom_help = std::move(help_text);
  1743 + return *this;
  1744 + }
1743 1745  
1744   - Options&
1745   - custom_help(std::string help_text)
1746   - {
1747   - m_custom_help = std::move(help_text);
1748   - return *this;
1749   - }
  1746 + Options&
  1747 + show_positional_help()
  1748 + {
  1749 + m_show_positional = true;
  1750 + return *this;
  1751 + }
1750 1752  
1751   - Options&
1752   - show_positional_help()
1753   - {
1754   - m_show_positional = true;
1755   - return *this;
1756   - }
  1753 + Options&
  1754 + allow_unrecognised_options()
  1755 + {
  1756 + m_allow_unrecognised = true;
  1757 + return *this;
  1758 + }
1757 1759  
1758   - Options&
1759   - allow_unrecognised_options()
1760   - {
1761   - m_allow_unrecognised = true;
1762   - return *this;
1763   - }
  1760 + Options&
  1761 + set_width(size_t width)
  1762 + {
  1763 + m_width = width;
  1764 + return *this;
  1765 + }
1764 1766  
1765   - Options&
1766   - set_width(size_t width)
1767   - {
1768   - m_width = width;
1769   - return *this;
1770   - }
  1767 + Options&
  1768 + set_tab_expansion(bool expansion=true)
  1769 + {
  1770 + m_tab_expansion = expansion;
  1771 + return *this;
  1772 + }
1771 1773  
1772   - Options&
1773   - set_tab_expansion(bool expansion=true)
1774   - {
1775   - m_tab_expansion = expansion;
1776   - return *this;
1777   - }
  1774 + ParseResult
  1775 + parse(int argc, const char* const* argv);
1778 1776  
1779   - ParseResult
1780   - parse(int argc, const char* const* argv);
1781   -
1782   - OptionAdder
1783   - add_options(std::string group = "");
1784   -
1785   - void
1786   - add_options
1787   - (
1788   - const std::string& group,
1789   - std::initializer_list<Option> options
1790   - );
1791   -
1792   - void
1793   - add_option
1794   - (
1795   - const std::string& group,
1796   - const Option& option
1797   - );
1798   -
1799   - void
1800   - add_option
1801   - (
1802   - const std::string& group,
1803   - const std::string& s,
1804   - const std::string& l,
1805   - std::string desc,
1806   - const std::shared_ptr<const Value>& value,
1807   - std::string arg_help
1808   - );
1809   -
1810   - //parse positional arguments into the given option
1811   - void
1812   - parse_positional(std::string option);
1813   -
1814   - void
1815   - parse_positional(std::vector<std::string> options);
1816   -
1817   - void
1818   - parse_positional(std::initializer_list<std::string> options);
1819   -
1820   - template <typename Iterator>
1821   - void
1822   - parse_positional(Iterator begin, Iterator end) {
1823   - parse_positional(std::vector<std::string>{begin, end});
1824   - }
  1777 + OptionAdder
  1778 + add_options(std::string group = "");
  1779 +
  1780 + void
  1781 + add_options
  1782 + (
  1783 + const std::string& group,
  1784 + std::initializer_list<Option> options
  1785 + );
  1786 +
  1787 + void
  1788 + add_option
  1789 + (
  1790 + const std::string& group,
  1791 + const Option& option
  1792 + );
1825 1793  
1826   - std::string
1827   - help(const std::vector<std::string>& groups = {}) const;
  1794 + void
  1795 + add_option
  1796 + (
  1797 + const std::string& group,
  1798 + const std::string& s,
  1799 + const std::string& l,
  1800 + std::string desc,
  1801 + const std::shared_ptr<const Value>& value,
  1802 + std::string arg_help
  1803 + );
1828 1804  
1829   - std::vector<std::string>
1830   - groups() const;
  1805 + //parse positional arguments into the given option
  1806 + void
  1807 + parse_positional(std::string option);
1831 1808  
1832   - const HelpGroupDetails&
1833   - group_help(const std::string& group) const;
  1809 + void
  1810 + parse_positional(std::vector<std::string> options);
1834 1811  
1835   - const std::string& program() const
1836   - {
1837   - return m_program;
1838   - }
  1812 + void
  1813 + parse_positional(std::initializer_list<std::string> options);
1839 1814  
1840   - private:
  1815 + template <typename Iterator>
  1816 + void
  1817 + parse_positional(Iterator begin, Iterator end) {
  1818 + parse_positional(std::vector<std::string>{begin, end});
  1819 + }
1841 1820  
1842   - void
1843   - add_one_option
1844   - (
1845   - const std::string& option,
1846   - const std::shared_ptr<OptionDetails>& details
1847   - );
1848   -
1849   - String
1850   - help_one_group(const std::string& group) const;
1851   -
1852   - void
1853   - generate_group_help
1854   - (
1855   - String& result,
1856   - const std::vector<std::string>& groups
1857   - ) const;
1858   -
1859   - void
1860   - generate_all_groups_help(String& result) const;
1861   -
1862   - std::string m_program{};
1863   - String m_help_string{};
1864   - std::string m_custom_help{};
1865   - std::string m_positional_help{};
1866   - bool m_show_positional;
1867   - bool m_allow_unrecognised;
1868   - size_t m_width;
1869   - bool m_tab_expansion;
1870   -
1871   - std::shared_ptr<OptionMap> m_options;
1872   - std::vector<std::string> m_positional{};
1873   - std::unordered_set<std::string> m_positional_set{};
1874   -
1875   - //mapping from groups to help options
1876   - std::map<std::string, HelpGroupDetails> m_help{};
1877   - };
  1821 + std::string
  1822 + help(const std::vector<std::string>& groups = {}) const;
  1823 +
  1824 + std::vector<std::string>
  1825 + groups() const;
1878 1826  
1879   - class OptionAdder
  1827 + const HelpGroupDetails&
  1828 + group_help(const std::string& group) const;
  1829 +
  1830 + const std::string& program() const
1880 1831 {
1881   - public:
  1832 + return m_program;
  1833 + }
1882 1834  
1883   - OptionAdder(Options& options, std::string group)
1884   - : m_options(options), m_group(std::move(group))
1885   - {
1886   - }
  1835 + private:
1887 1836  
1888   - OptionAdder&
1889   - operator()
1890   - (
1891   - const std::string& opts,
1892   - const std::string& desc,
1893   - const std::shared_ptr<const Value>& value
1894   - = ::cxxopts::value<bool>(),
1895   - std::string arg_help = ""
1896   - );
  1837 + void
  1838 + add_one_option
  1839 + (
  1840 + const std::string& option,
  1841 + const std::shared_ptr<OptionDetails>& details
  1842 + );
1897 1843  
1898   - private:
1899   - Options& m_options;
1900   - std::string m_group;
1901   - };
  1844 + String
  1845 + help_one_group(const std::string& group) const;
  1846 +
  1847 + void
  1848 + generate_group_help
  1849 + (
  1850 + String& result,
  1851 + const std::vector<std::string>& groups
  1852 + ) const;
  1853 +
  1854 + void
  1855 + generate_all_groups_help(String& result) const;
  1856 +
  1857 + std::string m_program{};
  1858 + String m_help_string{};
  1859 + std::string m_custom_help{};
  1860 + std::string m_positional_help{};
  1861 + bool m_show_positional;
  1862 + bool m_allow_unrecognised;
  1863 + size_t m_width;
  1864 + bool m_tab_expansion;
  1865 +
  1866 + std::shared_ptr<OptionMap> m_options;
  1867 + std::vector<std::string> m_positional{};
  1868 + std::unordered_set<std::string> m_positional_set{};
  1869 +
  1870 + //mapping from groups to help options
  1871 + std::map<std::string, HelpGroupDetails> m_help{};
  1872 +};
  1873 +
  1874 +class OptionAdder
  1875 +{
  1876 + public:
1902 1877  
1903   - namespace
  1878 + OptionAdder(Options& options, std::string group)
  1879 + : m_options(options), m_group(std::move(group))
1904 1880 {
1905   - constexpr size_t OPTION_LONGEST = 30;
1906   - constexpr size_t OPTION_DESC_GAP = 2;
  1881 + }
1907 1882  
1908   - String
1909   - format_option
1910   - (
1911   - const HelpOptionDetails& o
1912   - )
  1883 + OptionAdder&
  1884 + operator()
  1885 + (
  1886 + const std::string& opts,
  1887 + const std::string& desc,
  1888 + const std::shared_ptr<const Value>& value
  1889 + = ::cxxopts::value<bool>(),
  1890 + std::string arg_help = ""
  1891 + );
  1892 +
  1893 + private:
  1894 + Options& m_options;
  1895 + std::string m_group;
  1896 +};
  1897 +
  1898 +namespace {
  1899 + constexpr size_t OPTION_LONGEST = 30;
  1900 + constexpr size_t OPTION_DESC_GAP = 2;
  1901 +
  1902 + String
  1903 + format_option
  1904 + (
  1905 + const HelpOptionDetails& o
  1906 + )
  1907 + {
  1908 + const auto& s = o.s;
  1909 + const auto& l = o.l;
  1910 +
  1911 + String result = " ";
  1912 +
  1913 + if (!s.empty())
  1914 + {
  1915 + result += "-" + toLocalString(s);
  1916 + if (!l.empty())
  1917 + {
  1918 + result += ",";
  1919 + }
  1920 + }
  1921 + else
1913 1922 {
1914   - const auto& s = o.s;
1915   - const auto& l = o.l;
  1923 + result += " ";
  1924 + }
  1925 +
  1926 + if (!l.empty())
  1927 + {
  1928 + result += " --" + toLocalString(l);
  1929 + }
1916 1930  
1917   - String result = " ";
  1931 + auto arg = !o.arg_help.empty() ? toLocalString(o.arg_help) : "arg";
1918 1932  
1919   - if (!s.empty())
  1933 + if (!o.is_boolean)
  1934 + {
  1935 + if (o.has_implicit)
1920 1936 {
1921   - result += "-" + toLocalString(s);
1922   - if (!l.empty())
1923   - {
1924   - result += ",";
1925   - }
  1937 + result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
1926 1938 }
1927 1939 else
1928 1940 {
1929   - result += " ";
  1941 + result += " " + arg;
1930 1942 }
  1943 + }
1931 1944  
1932   - if (!l.empty())
1933   - {
1934   - result += " --" + toLocalString(l);
1935   - }
  1945 + return result;
  1946 + }
1936 1947  
1937   - auto arg = !o.arg_help.empty() ? toLocalString(o.arg_help) : "arg";
  1948 + String
  1949 + format_description
  1950 + (
  1951 + const HelpOptionDetails& o,
  1952 + size_t start,
  1953 + size_t allowed,
  1954 + bool tab_expansion
  1955 + )
  1956 + {
  1957 + auto desc = o.desc;
1938 1958  
1939   - if (!o.is_boolean)
  1959 + if (o.has_default && (!o.is_boolean || o.default_value != "false"))
  1960 + {
  1961 + if(!o.default_value.empty())
1940 1962 {
1941   - if (o.has_implicit)
1942   - {
1943   - result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]";
1944   - }
1945   - else
1946   - {
1947   - result += " " + arg;
1948   - }
  1963 + desc += toLocalString(" (default: " + o.default_value + ")");
  1964 + }
  1965 + else
  1966 + {
  1967 + desc += toLocalString(" (default: \"\")");
1949 1968 }
1950   -
1951   - return result;
1952 1969 }
1953 1970  
1954   - String
1955   - format_description
1956   - (
1957   - const HelpOptionDetails& o,
1958   - size_t start,
1959   - size_t allowed,
1960   - bool tab_expansion
1961   - )
1962   - {
1963   - auto desc = o.desc;
  1971 + String result;
1964 1972  
1965   - if (o.has_default && (!o.is_boolean || o.default_value != "false"))
  1973 + if (tab_expansion)
  1974 + {
  1975 + String desc2;
  1976 + auto size = size_t{ 0 };
  1977 + for (auto c = std::begin(desc); c != std::end(desc); ++c)
1966 1978 {
1967   - if(!o.default_value.empty())
  1979 + if (*c == '\n')
1968 1980 {
1969   - desc += toLocalString(" (default: " + o.default_value + ")");
  1981 + desc2 += *c;
  1982 + size = 0;
1970 1983 }
1971   - else
  1984 + else if (*c == '\t')
1972 1985 {
1973   - desc += toLocalString(" (default: \"\")");
  1986 + auto skip = 8 - size % 8;
  1987 + stringAppend(desc2, skip, ' ');
  1988 + size += skip;
1974 1989 }
1975   - }
1976   -
1977   - String result;
1978   -
1979   - if (tab_expansion)
1980   - {
1981   - String desc2;
1982   - auto size = size_t{ 0 };
1983   - for (auto c = std::begin(desc); c != std::end(desc); ++c)
  1990 + else
1984 1991 {
1985   - if (*c == '\n')
1986   - {
1987   - desc2 += *c;
1988   - size = 0;
1989   - }
1990   - else if (*c == '\t')
1991   - {
1992   - auto skip = 8 - size % 8;
1993   - stringAppend(desc2, skip, ' ');
1994   - size += skip;
1995   - }
1996   - else
1997   - {
1998   - desc2 += *c;
1999   - ++size;
2000   - }
  1992 + desc2 += *c;
  1993 + ++size;
2001 1994 }
2002   - desc = desc2;
2003 1995 }
  1996 + desc = desc2;
  1997 + }
  1998 +
  1999 + desc += " ";
2004 2000  
2005   - desc += " ";
  2001 + auto current = std::begin(desc);
  2002 + auto previous = current;
  2003 + auto startLine = current;
  2004 + auto lastSpace = current;
2006 2005  
2007   - auto current = std::begin(desc);
2008   - auto previous = current;
2009   - auto startLine = current;
2010   - auto lastSpace = current;
  2006 + auto size = size_t{};
2011 2007  
2012   - auto size = size_t{};
  2008 + bool appendNewLine;
  2009 + bool onlyWhiteSpace = true;
2013 2010  
2014   - bool appendNewLine;
2015   - bool onlyWhiteSpace = true;
  2011 + while (current != std::end(desc))
  2012 + {
  2013 + appendNewLine = false;
2016 2014  
2017   - while (current != std::end(desc))
  2015 + if (std::isblank(*previous))
2018 2016 {
2019   - appendNewLine = false;
  2017 + lastSpace = current;
  2018 + }
2020 2019  
2021   - if (std::isblank(*previous))
2022   - {
2023   - lastSpace = current;
2024   - }
  2020 + if (!std::isblank(*current))
  2021 + {
  2022 + onlyWhiteSpace = false;
  2023 + }
2025 2024  
2026   - if (!std::isblank(*current))
2027   - {
2028   - onlyWhiteSpace = false;
2029   - }
  2025 + while (*current == '\n')
  2026 + {
  2027 + previous = current;
  2028 + ++current;
  2029 + appendNewLine = true;
  2030 + }
2030 2031  
2031   - while (*current == '\n')
  2032 + if (!appendNewLine && size >= allowed)
  2033 + {
  2034 + if (lastSpace != startLine)
2032 2035 {
  2036 + current = lastSpace;
2033 2037 previous = current;
2034   - ++current;
2035   - appendNewLine = true;
2036 2038 }
  2039 + appendNewLine = true;
  2040 + }
2037 2041  
2038   - if (!appendNewLine && size >= allowed)
2039   - {
2040   - if (lastSpace != startLine)
2041   - {
2042   - current = lastSpace;
2043   - previous = current;
2044   - }
2045   - appendNewLine = true;
2046   - }
  2042 + if (appendNewLine)
  2043 + {
  2044 + stringAppend(result, startLine, current);
  2045 + startLine = current;
  2046 + lastSpace = current;
2047 2047  
2048   - if (appendNewLine)
  2048 + if (*previous != '\n')
2049 2049 {
2050   - stringAppend(result, startLine, current);
2051   - startLine = current;
2052   - lastSpace = current;
2053   -
2054   - if (*previous != '\n')
2055   - {
2056   - stringAppend(result, "\n");
2057   - }
2058   -
2059   - stringAppend(result, start, ' ');
  2050 + stringAppend(result, "\n");
  2051 + }
2060 2052  
2061   - if (*previous != '\n')
2062   - {
2063   - stringAppend(result, lastSpace, current);
2064   - }
  2053 + stringAppend(result, start, ' ');
2065 2054  
2066   - onlyWhiteSpace = true;
2067   - size = 0;
  2055 + if (*previous != '\n')
  2056 + {
  2057 + stringAppend(result, lastSpace, current);
2068 2058 }
2069 2059  
2070   - previous = current;
2071   - ++current;
2072   - ++size;
  2060 + onlyWhiteSpace = true;
  2061 + size = 0;
2073 2062 }
2074 2063  
2075   - //append whatever is left but ignore whitespace
2076   - if (!onlyWhiteSpace)
2077   - {
2078   - stringAppend(result, startLine, previous);
2079   - }
  2064 + previous = current;
  2065 + ++current;
  2066 + ++size;
  2067 + }
2080 2068  
2081   - return result;
  2069 + //append whatever is left but ignore whitespace
  2070 + if (!onlyWhiteSpace)
  2071 + {
  2072 + stringAppend(result, startLine, previous);
2082 2073 }
2083   - } // namespace
  2074 +
  2075 + return result;
  2076 + }
  2077 +} // namespace
2084 2078  
2085 2079 inline
2086 2080 void
... ...