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,15 +79,14 @@ THE SOFTWARE.
79 #define CXXOPTS_NULL_DEREF_IGNORE 79 #define CXXOPTS_NULL_DEREF_IGNORE
80 #endif 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 } // namespace cxxopts 90 } // namespace cxxopts
92 91
93 //when we ask cxxopts to use Unicode, help strings are processed using ICU, 92 //when we ask cxxopts to use Unicode, help strings are processed using ICU,
@@ -99,16 +98,15 @@ namespace cxxopts @@ -99,16 +98,15 @@ namespace cxxopts
99 #ifdef CXXOPTS_USE_UNICODE 98 #ifdef CXXOPTS_USE_UNICODE
100 #include <unicode/unistr.h> 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 #if defined(__GNUC__) 111 #if defined(__GNUC__)
114 // GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: 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,202 +116,201 @@ namespace cxxopts
118 #pragma GCC diagnostic ignored "-Weffc++" 116 #pragma GCC diagnostic ignored "-Weffc++"
119 // This will be ignored under other compilers like LLVM clang. 117 // This will be ignored under other compilers like LLVM clang.
120 #endif 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 //ifdef CXXOPTS_USE_UNICODE 244 //ifdef CXXOPTS_USE_UNICODE
246 #else 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 } // namespace cxxopts 299 } // namespace cxxopts
301 300
302 //ifdef CXXOPTS_USE_UNICODE 301 //ifdef CXXOPTS_USE_UNICODE
303 #endif 302 #endif
304 303
305 -namespace cxxopts  
306 -{  
307 - namespace  
308 - { 304 +namespace cxxopts {
  305 +namespace {
309 #ifdef _WIN32 306 #ifdef _WIN32
310 - const std::string LQUOTE("\'");  
311 - const std::string RQUOTE("\'"); 307 +const std::string LQUOTE("\'");
  308 +const std::string RQUOTE("\'");
312 #else 309 #else
313 - const std::string LQUOTE("โ€˜");  
314 - const std::string RQUOTE("โ€™"); 310 +const std::string LQUOTE("โ€˜");
  311 +const std::string RQUOTE("โ€™");
315 #endif 312 #endif
316 - } // namespace 313 +} // namespace
317 314
318 #if defined(__GNUC__) 315 #if defined(__GNUC__)
319 // GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: 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,1764 +320,1761 @@ namespace cxxopts
323 #pragma GCC diagnostic ignored "-Weffc++" 320 #pragma GCC diagnostic ignored "-Weffc++"
324 // This will be ignored under other compilers like LLVM clang. 321 // This will be ignored under other compilers like LLVM clang.
325 #endif 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 #if defined(__GNUC__) 366 #if defined(__GNUC__)
370 #pragma GCC diagnostic pop 367 #pragma GCC diagnostic pop
371 #endif 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 #ifndef CXXOPTS_NO_EXCEPTIONS 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 #else 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 #endif 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 #ifdef CXXOPTS_NO_REGEX 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 #else // CXXOPTS_NO_REGEX 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 throw_or_mimic<argument_incorrect_type>(text); 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 std::shared_ptr<Value> 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 std::shared_ptr<Value> 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 #if defined(CXXOPTS_NULL_DEREF_IGNORE) 1360 #if defined(CXXOPTS_NULL_DEREF_IGNORE)
1366 #pragma GCC diagnostic push 1361 #pragma GCC diagnostic push
1367 #pragma GCC diagnostic ignored "-Wnull-dereference" 1362 #pragma GCC diagnostic ignored "-Wnull-dereference"
1368 #endif 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 #if defined(CXXOPTS_NULL_DEREF_IGNORE) 1372 #if defined(CXXOPTS_NULL_DEREF_IGNORE)
1378 #pragma GCC diagnostic pop 1373 #pragma GCC diagnostic pop
1379 #endif 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 #ifdef CXXOPTS_NO_RTTI 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 #else 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 #endif 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 else 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 previous = current; 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 inline 2079 inline
2086 void 2080 void