OGLplus  (0.59.0) a C++ wrapper for rendering APIs

program_args.hpp
Go to the documentation of this file.
1 #ifndef EAGINE_PROGRAM_ARGS_HPP
9 #define EAGINE_PROGRAM_ARGS_HPP
10 
11 #include "assert.hpp"
12 #include "from_string.hpp"
13 #include "integer_range.hpp"
14 #include "interface.hpp"
15 #include "memory/block.hpp"
16 #include "memory/span_algo.hpp"
17 #include "range_types.hpp"
18 #include "selector.hpp"
19 #include "span.hpp"
20 #include "string_span.hpp"
21 #include "type_identity.hpp"
22 #include "type_name.hpp"
23 #include "valid_if/in_list.hpp"
24 #include <memory>
25 #include <sstream>
26 #include <type_traits>
27 #include <utility>
28 #include <vector>
29 
30 namespace eagine {
31 //------------------------------------------------------------------------------
32 class program_args;
33 //------------------------------------------------------------------------------
42 public:
44  constexpr auto short_tag() const noexcept -> string_view {
45  return _short_tag;
46  }
47 
49  constexpr auto long_tag() const noexcept -> string_view {
50  return _long_tag;
51  }
52 
54  constexpr auto description() const noexcept -> string_view {
55  return _description;
56  }
57 
59  constexpr auto description(string_view help_str) noexcept -> auto& {
60  _description = help_str;
61  return *this;
62  }
63 
64 protected:
65  string_view _short_tag;
66  string_view _long_tag;
67  string_view _description;
68 
69  constexpr basic_program_parameter(
71  string_view long_tag) noexcept
72  : _short_tag(short_tag)
73  , _long_tag(long_tag) {}
74 };
75 //------------------------------------------------------------------------------
84 template <typename T>
86 public:
90 
95  T initial) noexcept
97  , _value{std::move(initial)} {}
98 
100  auto ref() noexcept -> T& {
101  return _value;
102  }
103 
106  auto has_valid_value() const noexcept -> bool {
107  return _is_valid(_value);
108  }
109 
110  auto log_invalid_value(std::ostream& log) const -> auto& {
111  log << "Invalid value of parameter " << long_tag() << ": ";
112  _log_invalid(_value, log);
113  return log << ". ";
114  }
115 
117  auto validate(std::ostream& log) const -> bool {
118  if(!has_valid_value()) {
119  log_invalid_value(log) << std::endl;
120  return false;
121  }
122  return true;
123  }
124 
126  auto value() const -> auto& {
127  return _get_value(_value);
128  }
129 
132  operator const T&() const noexcept {
133  return _value;
134  }
135 
136 private:
137  T _value{};
138 
139  template <typename X>
140  static auto _is_valid(const X&) noexcept -> bool {
141  return true;
142  }
143 
144  template <typename X, typename P, typename L>
145  static auto _is_valid(const valid_if<X, P, L>& vi) noexcept -> bool {
146  return vi.is_valid();
147  }
148 
149  template <typename X>
150  static void _log_invalid(const X&, const std::ostream&) noexcept {}
151 
152  template <typename X, typename P, typename L>
153  static void
154  _log_invalid(const valid_if<X, P, L>& vi, std::ostream& log) noexcept {
155  vi.log_invalid(log);
156  }
157 
158  template <typename X>
159  static auto _get_value(X& val) noexcept -> X& {
160  return val;
161  }
162 
163  template <typename X>
164  static auto _get_value(const X& val) noexcept -> const X& {
165  return val;
166  }
167 
168  template <typename X, typename P, typename L>
169  static auto _get_value(valid_if<X, P, L>& vi) -> X& {
170  return vi.value();
171  }
172 
173  template <typename X, typename P, typename L>
174  static auto _get_value(const valid_if<X, P, L>& vi) -> const X& {
175  return vi.value();
176  }
177 };
178 //------------------------------------------------------------------------------
186 template <>
188 public:
192 
193  void increment() noexcept {
194  ++_count;
195  }
196 
197  auto has_valid_value() const noexcept -> bool {
198  return true;
199  }
200 
201  auto log_invalid_value(std::ostream& log) const noexcept -> std::ostream& {
202  return log;
203  }
204 
205  auto validate(std::ostream&) const noexcept -> bool {
206  return true;
207  }
208 
209  auto value() const noexcept -> span_size_t {
210  return _count;
211  }
212 
213 private:
214  span_size_t _count{0};
215 };
216 
217 using program_option = program_parameter<void>;
218 //------------------------------------------------------------------------------
222 template <typename T>
224 public:
225  ~program_parameter_alias() noexcept = default;
228  auto operator=(const program_parameter_alias&) = delete;
229  auto operator=(program_parameter_alias&&) noexcept = delete;
230 
235  program_parameter<T>& that) noexcept
237  , _aliased(that) {}
238 
240  auto ref() noexcept -> auto& {
241  return _aliased.ref();
242  }
243 
245  auto value() const noexcept -> auto& {
246  return _aliased.value();
247  }
248 
251  operator const T&() const noexcept {
252  return static_cast<const T&>(_aliased);
253  }
254 
255 private:
256  program_parameter<T>& _aliased;
257 };
258 //------------------------------------------------------------------------------
259 class program_arg_iterator;
260 
265 class program_arg {
266 public:
268  constexpr program_arg() noexcept = default;
269 
270  program_arg(int argi, int argc, const char** argv) noexcept
271  : _argi(argi)
272  , _argc(argc)
273  , _argv(argv) {}
274 
277 
279  auto is_valid() const noexcept -> bool {
280  return (0 < _argi) && (_argi < _argc) && (_argv != nullptr) &&
281  (_argv[_argi] != nullptr);
282  }
283 
286  operator bool() const noexcept {
287  return is_valid();
288  }
289 
291  auto position() const noexcept {
292  return _argi;
293  }
294 
296  auto is_first() const noexcept -> bool {
297  return _argi == 1;
298  }
299 
301  auto is_last() const noexcept -> bool {
302  return _argi == _argc - 1;
303  }
304 
306  auto get() const noexcept -> value_type {
307  if(is_valid()) {
308  return value_type(_argv[_argi]);
309  }
310  return {};
311  }
312 
314  auto block() const noexcept -> memory::const_block {
315  return memory::as_bytes(get());
316  }
317 
319  auto get_string() const -> std::string {
320  return get().to_string();
321  }
322 
325  operator value_type() const noexcept {
326  return get();
327  }
328 
331  auto starts_with(string_view str) const noexcept {
332  return memory::starts_with(get(), str);
333  }
334 
337  auto ends_with(string_view str) const noexcept {
338  return memory::ends_with(get(), str);
339  }
340 
342  auto is_tag(string_view tag) const noexcept {
343  return are_equal(get(), tag);
344  }
345 
347  auto is_tag(string_view short_tag, string_view long_tag) const noexcept {
348  return are_equal(get(), short_tag) || are_equal(get(), long_tag);
349  }
350 
352  auto is_tag_param(const basic_program_parameter& param) const {
353  return is_tag(param.short_tag(), param.long_tag());
354  }
355 
357  auto is_help_arg() const noexcept {
358  return is_tag(string_view("-h"), string_view("--help"));
359  }
360 
363  auto next() const noexcept -> program_arg {
364  return {_argi + 1, _argc, _argv};
365  }
366 
369  auto prev() const noexcept -> program_arg {
370  return {_argi - 1, _argc, _argv};
371  }
372 
375  template <typename T, identifier_t V>
376  auto parse(T& dest, selector<V> sel, std::ostream& parse_log) const
377  -> bool {
378  if(is_valid()) {
379  T temp = dest;
380  if(_do_parse(temp, sel, parse_log)) {
381  dest = std::move(temp);
382  return true;
383  }
384  }
385  return false;
386  }
387 
390  template <typename T>
391  auto parse(T& dest, std::ostream& parse_log) const {
392  return parse(dest, default_selector, parse_log);
393  }
394 
397  template <typename T, identifier_t V>
398  auto parse_next(T& dest, selector<V> sel, std::ostream& parse_log) const {
399  return next().parse(dest, sel, parse_log);
400  }
401 
404  template <typename T>
405  auto parse_next(T& dest, std::ostream& parse_log) const {
406  return parse_next(dest, default_selector, parse_log);
407  }
408 
409  auto missing_handler(std::ostream& errorlog) {
410  return [&errorlog](string_view arg_tag) {
411  errorlog << "Missing value after '" << arg_tag << "'." << std::endl;
412  };
413  }
414 
415  auto invalid_handler(std::ostream& errorlog) {
416  return
417  [&errorlog](
418  string_view arg_tag, string_view arg_val, string_view log_str) {
419  errorlog << "Invalid value '" << arg_val << "' after '" << arg_tag
420  << "'. " << log_str << std::endl;
421  };
422  }
423 
424  template <typename T, typename MissingFunc, typename InvalidFunc>
425  auto do_consume_next(
426  T& dest,
427  MissingFunc handle_missing,
428  InvalidFunc handle_invalid) -> bool {
429  if(next()) {
430  std::stringstream parse_log;
431  if(parse_next(dest, parse_log)) {
432  *this = next();
433  return true;
434  } else {
435  handle_invalid(
436  get(), next().get(), string_view(parse_log.str()));
437  }
438  } else {
439  handle_missing(get());
440  }
441  return false;
442  }
443 
446  template <typename T>
447  auto consume_next(T& dest, std::ostream& errorlog) -> bool {
448  auto if_missing = missing_handler(errorlog);
449  auto if_invalid = invalid_handler(errorlog);
450  return do_consume_next(dest, if_missing, if_invalid);
451  }
452 
453  template <typename T, typename MissingFunc, typename InvalidFunc>
454  auto do_parse_param(
455  program_parameter<T>& param,
456  MissingFunc handle_missing,
457  InvalidFunc handle_invalid) -> bool {
458  if(is_tag_param(param)) {
459  return do_consume_next(param.ref(), handle_missing, handle_invalid);
460  }
461  return false;
462  }
463 
464  template <typename MissingFunc, typename InvalidFunc>
465  auto do_parse_param(
466  program_parameter<void>& param,
467  const MissingFunc&,
468  const InvalidFunc&) {
469  if(is_tag_param(param)) {
470  param.increment();
471  return true;
472  }
473  return false;
474  }
475 
478  template <typename T>
479  auto parse_param(program_parameter<T>& param, std::ostream& errorlog)
480  -> bool {
481  auto if_missing{missing_handler(errorlog)};
482  auto if_invalid{invalid_handler(errorlog)};
483  return do_parse_param(param, if_missing, if_invalid);
484  }
485 
486  template <typename T, typename MissingFunc, typename InvalidFunc>
487  auto do_consume_next(
488  T& dest,
489  span<const T> choices,
490  MissingFunc handle_missing,
491  InvalidFunc handle_invalid) {
492  valid_if_in_list<T, span<const T>> temp(T(), choices);
493  if(do_consume_next(temp, handle_missing, handle_invalid)) {
494  dest = temp.value();
495  return true;
496  }
497  return false;
498  }
499 
500  template <typename T, typename P, typename L, class MissingFunc, class InvalidFunc>
501  auto do_consume_next(
502  valid_if<T, P, L>& dest,
503  span<const T> choices,
504  MissingFunc handle_missing,
505  InvalidFunc handle_invalid) {
506  T temp = {};
507  if(do_consume_next(temp, choices, handle_missing, handle_invalid)) {
508  if(dest.is_valid(temp)) {
509  dest = std::move(temp);
510  return true;
511  }
512  }
513  return false;
514  }
515 
516  template <typename T, typename C>
517  auto consume_next(T& dest, span<const C> choices, std::ostream& errorlog)
518  -> bool {
519  auto if_missing{missing_handler(errorlog)};
520  auto if_invalid{invalid_handler(errorlog)};
521  return do_consume_next(dest, choices, if_missing, if_invalid);
522  }
523 
524  template <typename T, typename C, class MissingFunc, class InvalidFunc>
525  auto do_parse_param(
526  program_parameter<T>& param,
527  span<const C> choices,
528  MissingFunc handle_missing,
529  InvalidFunc handle_invalid) {
530  if(is_tag_param(param)) {
531  return do_consume_next(
532  param.ref(), choices, handle_missing, handle_invalid);
533  }
534  return false;
535  }
536 
537  template <typename T, typename C>
538  auto parse_param(
539  program_parameter<T>& param,
540  span<const C> choices,
541  std::ostream& errorlog) -> bool {
542  auto if_missing{missing_handler(errorlog)};
543  auto if_invalid{invalid_handler(errorlog)};
544  return do_parse_param(param, choices, if_missing, if_invalid);
545  }
546 
547  template <typename T, typename MissingFunc, typename InvalidFunc>
548  auto do_consume_next(
549  T& dest,
550  span<const string_view> symbols,
551  span<const T> translations,
552  MissingFunc handle_missing,
553  InvalidFunc handle_invalid) {
554  EAGINE_ASSERT(symbols.size() <= translations.size());
555 
556  string_view parsed;
557  if(do_consume_next(parsed, symbols, handle_missing, handle_invalid)) {
558  for(auto i : integer_range(symbols.size())) {
559  if(are_equal(parsed, symbols[i])) {
560  dest = translations[i];
561  return true;
562  }
563  }
564  }
565  return false;
566  }
567 
568  template <typename T, typename P, typename L, class MissingFunc, class InvalidFunc>
569  auto do_consume_next(
570  valid_if<T, P, L>& dest,
571  span<const string_view> symbols,
572  span<const T> translations,
573  MissingFunc handle_missing,
574  InvalidFunc handle_invalid) {
575  T temp{};
576  if(do_consume_next(
577  temp, symbols, translations, handle_missing, handle_invalid)) {
578  if(dest.is_valid(temp)) {
579  dest = std::move(temp);
580  return true;
581  }
582  }
583  return false;
584  }
585 
588  template <typename T, typename R>
590  T& dest,
591  span<const string_view> symbols,
592  span<const R> translations,
593  std::ostream& errorlog) -> bool {
594  auto if_missing{missing_handler(errorlog)};
595  auto if_invalid{invalid_handler(errorlog)};
596  return do_consume_next(
597  dest, symbols, translations, if_missing, if_invalid);
598  }
599 
600  template <typename T, typename R, class MissingFunc, class InvalidFunc>
601  auto do_parse_param(
602  program_parameter<T>& param,
603  span<const string_view> symbols,
604  span<const R> translations,
605  MissingFunc handle_missing,
606  InvalidFunc handle_invalid) {
607  if(is_tag_param(param)) {
608  return do_consume_next(
609  param.ref(),
610  symbols,
611  translations,
612  handle_missing,
613  handle_invalid);
614  }
615  return false;
616  }
617 
618  template <typename T, typename R>
619  auto parse_param(
620  program_parameter<T>& param,
621  span<const string_view> symbols,
622  span<const R> translations,
623  std::ostream& errorlog) -> bool {
624  auto if_missing{missing_handler(errorlog)};
625  auto if_invalid{invalid_handler(errorlog)};
626  return do_parse_param(
627  param, symbols, translations, if_missing, if_invalid);
628  }
629 
630  template <typename T, typename R, class MissingFunc, class InvalidFunc>
631  auto do_parse_param(
632  program_parameter_alias<T>& param,
633  span<const string_view> symbols,
634  span<const R> translations,
635  MissingFunc handle_missing,
636  InvalidFunc handle_invalid) {
637  if(is_tag_param(param)) {
638  return do_consume_next(
639  param.ref(),
640  symbols,
641  translations,
642  handle_missing,
643  handle_invalid);
644  }
645  return false;
646  }
647 
648  template <typename T, typename R>
649  auto parse_param(
650  program_parameter_alias<T>& param,
651  span<const string_view> symbols,
652  span<const R> translations,
653  std::ostream& errorlog) -> bool {
654  auto if_missing{missing_handler(errorlog)};
655  auto if_invalid{invalid_handler(errorlog)};
656  return do_parse_param(
657  param, symbols, translations, if_missing, if_invalid);
658  }
659 
661  auto operator==(const value_type& v) const noexcept {
662  return are_equal(get(), v);
663  }
664 
666  auto operator!=(const value_type& v) const noexcept {
667  return are_equal(get(), v);
668  }
669 
670 private:
671  int _argi{0};
672  int _argc{0};
673  const char** _argv{nullptr};
674 
675  friend class program_arg_iterator;
676  friend class program_args;
677 
678  template <typename T, identifier_t V>
679  auto _do_parse(T& dest, selector<V> sel, const std::ostream&) const noexcept
680  -> bool {
681  if(auto opt_val{from_string<T>(get(), sel)}) {
682  dest = std::move(extract(opt_val));
683  return true;
684  }
685  return false;
686  }
687 
688  template <identifier_t V>
689  auto _do_parse(string_view& dest, selector<V>, const std::ostream&)
690  const noexcept -> bool {
691  dest = get();
692  return true;
693  }
694 
695  template <identifier_t V>
696  auto _do_parse(std::string& dest, selector<V>, const std::ostream&) const
697  -> bool {
698  dest = get_string();
699  return true;
700  }
701 
702  template <typename T, typename P, typename L, identifier_t V>
703  auto _do_parse(
704  valid_if<T, P, L>& dest,
705  selector<V> sel,
706  std::ostream& parse_log) const -> bool {
707  T value{};
708  if(parse(value, sel, parse_log)) {
709  if(dest.is_valid(value)) {
710  dest = std::move(value);
711  return true;
712  } else {
713  dest.log_invalid(parse_log, value);
714  }
715  } else {
716  parse_log << "'" << get() << "' "
717  << "is not a valid `" << type_name<T>() << "` value";
718  }
719  return false;
720  }
721 
722  template <typename T, typename A, identifier_t V>
723  auto _do_parse(
724  std::vector<T, A>& dest,
725  selector<V> sel,
726  std::ostream& parse_log) const -> bool {
727  T value{};
728  if(parse(value, sel, parse_log)) {
729  dest.push_back(std::move(value));
730  return true;
731  }
732  return false;
733  }
734 };
735 //------------------------------------------------------------------------------
736 static inline auto extract(const program_arg& arg) noexcept {
737  return arg.get();
738 }
739 //------------------------------------------------------------------------------
740 static inline auto to_string(const program_arg& arg) {
741  return arg.get_string();
742 }
743 //------------------------------------------------------------------------------
744 static inline auto operator<<(std::ostream& out, const program_arg& arg)
745  -> std::ostream& {
746  return out << arg.get();
747 }
748 //------------------------------------------------------------------------------
752 
753 public:
754  program_arg_iterator(program_arg arg) noexcept
755  : _a{arg} {}
756 
759 
761  using difference_type = int;
762 
765 
767  using const_reference = const program_arg&;
768 
771 
773  using const_pointer = const program_arg*;
774 
776  using iterator_category = std::random_access_iterator_tag;
777 
779  friend auto operator==(const this_class& l, const this_class& r) noexcept {
780  return _cmp(l._a, r._a) == 0;
781  }
782 
784  friend auto operator!=(const this_class& l, const this_class& r) noexcept {
785  return _cmp(l._a, r._a) != 0;
786  }
787 
789  friend auto operator<(const this_class& l, const this_class& r) noexcept {
790  return _cmp(l._a, r._a) < 0;
791  }
792 
794  friend auto operator<=(const this_class& l, const this_class& r) noexcept {
795  return _cmp(l._a, r._a) <= 0;
796  }
797 
799  friend auto operator>(const this_class& l, const this_class& r) noexcept {
800  return _cmp(l._a, r._a) > 0;
801  }
802 
804  friend auto operator>=(const this_class& l, const this_class& r) noexcept {
805  return _cmp(l._a, r._a) >= 0;
806  }
807 
809  friend auto operator-(const this_class& l, const this_class& r) noexcept
810  -> difference_type {
811  return _cmp(l._a, r._a);
812  }
813 
815  auto operator++() noexcept -> this_class& {
816  ++_a._argi;
817  return *this;
818  }
819 
821  auto operator--() noexcept -> this_class& {
822  --_a._argi;
823  return *this;
824  }
825 
827  auto operator++(int) noexcept -> this_class {
828  this_class result{*this};
829  ++_a._argi;
830  return result;
831  }
832 
834  auto operator--(int) noexcept -> this_class {
835  this_class result{*this};
836  --_a._argi;
837  return result;
838  }
839 
841  auto operator+=(difference_type dist) noexcept -> this_class& {
842  _a._argi += dist;
843  return *this;
844  }
845 
847  auto operator-=(difference_type dist) noexcept -> this_class& {
848  _a._argi -= dist;
849  return *this;
850  }
851 
853  auto operator+(difference_type dist) noexcept -> this_class {
854  this_class result{*this};
855  result._a._argi += dist;
856  return result;
857  }
858 
860  auto operator-(difference_type dist) noexcept -> this_class {
861  this_class result{*this};
862  result._a._argi -= dist;
863  return result;
864  }
865 
867  auto operator*() noexcept -> reference {
868  return _a;
869  }
870 
872  auto operator*() const noexcept -> const_reference {
873  return _a;
874  }
875 
876 private:
877  static auto _cmp(const program_arg& l, const program_arg& r) noexcept
878  -> int {
879  EAGINE_ASSERT(l._argv == r._argv);
880  return l._argi - r._argi;
881  }
882 
883  program_arg _a{};
884 };
885 //------------------------------------------------------------------------------
886 class program_parameters {
887 private:
888  struct _intf : interface<_intf> {
889  virtual auto parse(program_arg&, std::ostream&) -> bool = 0;
890 
891  virtual auto has_valid_value() const -> bool = 0;
892  virtual auto validate(std::ostream&) const -> bool = 0;
893 
894  virtual auto short_tag() const -> string_view = 0;
895  virtual auto long_tag() const -> string_view = 0;
896  virtual auto description() const -> string_view = 0;
897  virtual auto placeholder() const -> string_view = 0;
898  };
899 
900  template <typename T>
901  struct _impl : _intf {
902  program_parameter<T>* _pparam;
903  string_view _plchldr;
904 
905  auto _param() noexcept -> auto& {
906  EAGINE_ASSERT(_pparam != nullptr);
907  return *_pparam;
908  }
909 
910  auto _param() const noexcept -> auto& {
911  EAGINE_ASSERT(_pparam != nullptr);
912  return *_pparam;
913  }
914 
915  template <typename X>
916  static auto _plchldr_name(type_identity<X>) noexcept -> string_view {
917  if(std::is_same_v<X, bool>) {
918  return {"BOOLEAN"};
919  }
920  if(std::is_same_v<X, string_view>) {
921  return {"STRING"};
922  }
923  if(std::is_integral_v<X>) {
924  return {"INTEGER"};
925  }
926  if(std::is_floating_point_v<X>) {
927  return {"FLOAT"};
928  }
929  // TODO: be more precise depending on X
930  return {"VALUE"};
931  }
932 
933  template <typename X, typename P, typename L>
934  static auto _plchldr_name(type_identity<valid_if<X, P, L>>) noexcept {
935  return _plchldr_name(type_identity<X>());
936  }
937 
938  template <typename X, typename A>
939  static auto _plchldr_name(type_identity<std::vector<X, A>>) noexcept {
940  return _plchldr_name(type_identity<X>());
941  }
942 
943  _impl(program_parameter<T>& param) noexcept
944  : _pparam{&param}
945  , _plchldr{_plchldr_name(type_identity<T>())} {}
946 
947  auto parse(program_arg& arg, std::ostream& log) -> bool override {
948  return arg.parse_param(_param(), log);
949  }
950 
951  auto has_valid_value() const -> bool override {
952  return _param().has_valid_value();
953  }
954 
955  auto validate(std::ostream& log) const -> bool override {
956  return _param().validate(log);
957  }
958 
959  auto short_tag() const -> string_view override {
960  return _param().short_tag();
961  }
962 
963  auto long_tag() const -> string_view override {
964  return _param().long_tag();
965  }
966 
967  auto description() const -> string_view override {
968  return _param().description();
969  }
970 
971  auto placeholder() const -> string_view override {
972  return _plchldr;
973  }
974  };
975 
976  std::vector<std::unique_ptr<_intf>> _params;
977 
978  static auto _insert(std::vector<std::unique_ptr<_intf>>& dest) noexcept
979  -> auto& {
980  return dest;
981  }
982 
983  template <typename... Intf>
984  static auto _insert(
985  std::vector<std::unique_ptr<_intf>>& dest,
986  std::unique_ptr<_intf>&& param,
987  std::unique_ptr<Intf>&&... params) noexcept -> auto& {
988  EAGINE_ASSERT(param != nullptr);
989  dest.push_back(std::move(param));
990  return _insert(dest, std::move(params)...);
991  }
992 
993  template <typename... Intf>
994  static auto _make(std::unique_ptr<Intf>&&... params) {
995  std::vector<std::unique_ptr<_intf>> result;
996  result.reserve(sizeof...(params));
997  return std::move(_insert(result, std::move(params)...));
998  }
999 
1000 public:
1001  template <typename... T>
1002  program_parameters(program_parameter<T>&... params)
1003  : _params(_make(std::unique_ptr<_intf>(new _impl<T>(params))...)) {}
1004 
1005  auto size() const noexcept -> span_size_t {
1006  return span_size(_params.size());
1007  }
1008 
1009  auto parse(program_arg& arg, std::ostream& log) -> bool {
1010  for(auto& param : _params) {
1011  EAGINE_ASSERT(param != nullptr);
1012  if(param->parse(arg, log)) {
1013  return true;
1014  }
1015  }
1016  return false;
1017  }
1018 
1019  auto validate(std::ostream& log) const -> bool {
1020  bool all_ok = true;
1021  for(const auto& param : _params) {
1022  EAGINE_ASSERT(param != nullptr);
1023  all_ok &= param->validate(log);
1024  }
1025  return all_ok;
1026  }
1027 
1028  auto print_usage(std::ostream& out, string_view command) -> std::ostream& {
1029  out << "Usage: " << command;
1030 
1031  span_size_t stag_maxl = 0;
1032  span_size_t ltag_maxl = 0;
1033 
1034  for(const auto& param : _params) {
1035  EAGINE_ASSERT(param != nullptr);
1036 
1037  out << " ";
1038 
1039  bool mandatory = !param->has_valid_value();
1040 
1041  out << (mandatory ? '<' : '[');
1042 
1043  out << param->short_tag() << "|" << param->long_tag();
1044  out << " " << param->placeholder();
1045 
1046  out << (mandatory ? '>' : ']');
1047 
1048  if(stag_maxl < param->short_tag().size()) {
1049  stag_maxl = param->short_tag().size();
1050  }
1051 
1052  if(ltag_maxl < param->long_tag().size()) {
1053  ltag_maxl = param->long_tag().size();
1054  }
1055  }
1056  out << std::endl;
1057  out << " Options:" << std::endl;
1058 
1059  span_size_t padl;
1060 
1061  for(const auto& param : _params) {
1062  padl = 4 + stag_maxl - param->short_tag().size();
1063  while(padl-- > 0) {
1064  out << " ";
1065  }
1066  out << param->short_tag() << "|";
1067 
1068  out << param->long_tag();
1069  padl = ltag_maxl - param->long_tag().size();
1070  while(padl-- > 0) {
1071  out << " ";
1072  }
1073  out << ": " << param->description() << std::endl;
1074  }
1075 
1076  return out;
1077  }
1078 };
1079 //------------------------------------------------------------------------------
1083 public:
1086  program_args() noexcept = default;
1087 
1089  program_args(span_size_t argn, char** args) noexcept
1090  : _argc(int(argn))
1091  , _argv(const_cast<const char**>(args)) {}
1092 
1094  program_args(span_size_t argn, const char** args) noexcept
1095  : _argc(int(argn))
1096  , _argv(args) {}
1097 
1100 
1102  using size_type = int;
1103 
1106 
1109 
1111  auto argc() const noexcept -> int {
1112  return _argc;
1113  }
1114 
1116  auto argv() const noexcept -> const char** {
1117  return _argv;
1118  }
1119 
1121  auto empty() const noexcept -> bool {
1122  return _argc <= 0;
1123  }
1124 
1126  auto none() const noexcept -> bool {
1127  return _argc <= 1;
1128  }
1129 
1131  auto size() const noexcept -> int {
1132  return _argc;
1133  }
1134 
1136  auto is_valid(const valid_index& pos) const noexcept -> bool {
1137  return pos.is_valid(*this) && (_argv != nullptr) &&
1138  (_argv[pos.value_or(-1, *this)] != nullptr);
1139  }
1140 
1143  auto get(const valid_index& pos) const noexcept -> value_type {
1144  EAGINE_ASSERT(is_valid(pos));
1145  return value_type(_argv[pos.value_anyway(*this)]);
1146  }
1147 
1150  auto operator[](const valid_index& pos) const noexcept -> value_type {
1151  return get(pos);
1152  }
1153 
1155  auto command() const noexcept -> value_type {
1156  return get(0);
1157  }
1158 
1160  auto first() const noexcept -> program_arg {
1161  return program_arg(1, _argc, _argv);
1162  }
1163 
1165  auto begin() const noexcept -> iterator {
1166  return {program_arg(1, _argc, _argv)};
1167  }
1168 
1170  auto end() const noexcept -> iterator {
1171  return {program_arg(_argc, _argc, _argv)};
1172  }
1173 
1175  auto find(string_view what) const noexcept -> program_arg {
1176  int i = 1;
1177  while(i < _argc) {
1178  if((_argv != nullptr) && (_argv[i] != nullptr)) {
1179  if(are_equal(string_view(_argv[i]), what)) {
1180  break;
1181  }
1182  }
1183  ++i;
1184  }
1185  return {i, _argc, _argv};
1186  }
1187 
1189  template <typename T>
1190  auto parse_param(program_parameter<T>& param, std::ostream& errlog) const
1191  -> bool {
1192  for(program_arg a = first(); a; a = a.next()) {
1193  if(a.parse_param(param, errlog)) {
1194  return true;
1195  }
1196  }
1197  return false;
1198  }
1199 
1200 private:
1201  int _argc{0};
1202  const char** _argv{nullptr};
1203 };
1204 //------------------------------------------------------------------------------
1205 } // namespace eagine
1206 
1207 #endif // EAGINE_PROGRAM_ARGS_HPP
value_type
Value tree value element data type enumeration.
Definition: interface.hpp:27
auto operator+(difference_type dist) noexcept -> this_class
Difference addition.
Definition: program_args.hpp:853
auto ends_with(string_view str) const noexcept
Indicates if this argument value ends with the specified string.
Definition: program_args.hpp:337
std::ptrdiff_t span_size_t
Signed span size type used by eagine.
Definition: types.hpp:36
static constexpr auto ends_with(basic_span< T1, P1, S1 > spn, basic_span< T2, P2, S2 > with) -> bool
Indicates if span spn ends with the content of with.
Definition: span_algo.hpp:187
basic_string_span< const char > string_view
Alias for const string views.
Definition: string_span.hpp:116
static constexpr auto as_bytes(basic_span< T, P, S > spn) noexcept -> basic_block< std::is_const_v< T >>
Converts a span into a basic_block.
Definition: block.hpp:39
static constexpr auto span_size(T v) noexcept
Converts argument to span size type.
Definition: types.hpp:59
auto is_tag(string_view tag) const noexcept
Indicates if this argument value is equal to the specified string.
Definition: program_args.hpp:342
auto is_help_arg() const noexcept
Indicates if this argument is a "show help" argument (like "--help").
Definition: program_args.hpp:357
auto consume_next(T &dest, span< const string_view > symbols, span< const R > translations, std::ostream &errorlog) -> bool
Tries to parse values into starting from the following argument.
Definition: program_args.hpp:589
Class template for pre-declared program parameter.
Definition: program_args.hpp:85
program_parameter(string_view short_tag, string_view long_tag, T initial) noexcept
Construction from short and long tag strings and the initial value.
Definition: program_args.hpp:92
auto operator[](const valid_index &pos) const noexcept -> value_type
Returns the command line argument value at the specified position.
Definition: program_args.hpp:1150
auto ref() noexcept -> auto &
Returns a reference to the value in the aliased program parameter.
Definition: program_args.hpp:240
Common code is placed in this namespace.
Definition: eagine.hpp:21
auto first() const noexcept -> program_arg
Returns first argument.
Definition: program_args.hpp:1160
program_args(span_size_t argn, char **args) noexcept
Construction from the length and pointer to the argument list.
Definition: program_args.hpp:1089
auto ref() noexcept -> T &
Returns a reference to the parameter value.
Definition: program_args.hpp:100
static constexpr auto extract(api_result_value< Result, api_result_validity::never > &) noexcept -> Result &
Overload of extract for api_result_value.
Definition: c_api_wrap.hpp:270
auto is_tag(string_view short_tag, string_view long_tag) const noexcept
Indicates if this argument value is one of the two specified strings.
Definition: program_args.hpp:347
basic_block< true > const_block
Alias for const byte memory span.
Definition: block.hpp:32
Primary template for conditionally valid values.
Definition: decl.hpp:49
auto empty() const noexcept -> bool
Indicates if the argument list is completely empty.
Definition: program_args.hpp:1121
auto argc() const noexcept -> int
Returns the number of arguments.
Definition: program_args.hpp:1111
auto block() const noexcept -> memory::const_block
Returns the value of this argument as a const memory block.
Definition: program_args.hpp:314
auto position() const noexcept
Returns the index of this argument.
Definition: program_args.hpp:291
auto find(string_view what) const noexcept -> program_arg
Finds and returns the argument with the specified value.
Definition: program_args.hpp:1175
auto begin() const noexcept -> iterator
Returns an iterator to the first argument (not the command name).
Definition: program_args.hpp:1165
auto parse(T &dest, selector< V > sel, std::ostream &parse_log) const -> bool
Tries to parse this argument's value into dest.
Definition: program_args.hpp:376
program_parameter_alias(string_view short_tag, string_view long_tag, program_parameter< T > &that) noexcept
Construction from alternative short and long tags and parameter reference.
Definition: program_args.hpp:232
auto get(const valid_index &pos) const noexcept -> value_type
Returns the command line argument value at the specified position.
Definition: program_args.hpp:1143
auto parse_param(program_parameter< T > &param, std::ostream &errlog) const -> bool
Parses the specified parameter, using errlog for error output.
Definition: program_args.hpp:1190
friend auto operator!=(const this_class &l, const this_class &r) noexcept
Nonequality comparison.
Definition: program_args.hpp:784
auto validate(std::ostream &log) const -> bool
Validate the current value, print potential error messages to log.
Definition: program_args.hpp:117
Alias (alternative tags) for another declared program parameter.
Definition: program_args.hpp:223
Template used to construct tag-types used mostly in tag-dispatching.
Definition: selector.hpp:21
auto operator*() noexcept -> reference
Dereference operator.
Definition: program_args.hpp:867
auto operator==(const value_type &v) const noexcept
Indicates if this argument's value is equal to the specified string.
Definition: program_args.hpp:661
int size_type
Alias for the element count type.
Definition: program_args.hpp:1102
constexpr auto description(string_view help_str) noexcept -> auto &
Specifies a human-readable description for this program parameter.
Definition: program_args.hpp:59
program_parameter(string_view short_tag, string_view long_tag) noexcept
Construction from short and long tag strings.
Definition: program_args.hpp:88
auto parse_next(T &dest, selector< V > sel, std::ostream &parse_log) const
Tries to parse the following argument's value into dest.
Definition: program_args.hpp:398
Class representing a single main function (command-line) argument.
Definition: program_args.hpp:265
auto operator++(int) noexcept -> this_class
Post-increment operator.
Definition: program_args.hpp:827
auto parse(T &dest, std::ostream &parse_log) const
Tries to parse this argument's value into dest.
Definition: program_args.hpp:391
auto value() const -> auto &
Returns the current parameter value.
Definition: program_args.hpp:126
std::random_access_iterator_tag iterator_category
Alias for iterator category.
Definition: program_args.hpp:776
auto get() const noexcept -> value_type
Returns the value of this argument if valid, an empty string view otherwise.
Definition: program_args.hpp:306
auto operator--(int) noexcept -> this_class
Post-decrement operator.
Definition: program_args.hpp:834
program_parameter(string_view short_tag, string_view long_tag) noexcept
Construction from the short and long tag strings.
Definition: program_args.hpp:190
auto parse_next(T &dest, std::ostream &parse_log) const
Tries to parse the following argument's value into dest.
Definition: program_args.hpp:405
friend auto operator>=(const this_class &l, const this_class &r) noexcept
Greater-equal comparison.
Definition: program_args.hpp:804
program_args(span_size_t argn, const char **args) noexcept
Construction from the length and const pointer to the argument list.
Definition: program_args.hpp:1094
auto operator++() noexcept -> this_class &
Pre-increment operator.
Definition: program_args.hpp:815
constexpr program_arg() noexcept=default
Default constructor.
auto operator*() const noexcept -> const_reference
Const dereference operator.
Definition: program_args.hpp:872
auto value() const noexcept -> auto &
Returns the value in the aliased program parameter.
Definition: program_args.hpp:245
friend auto operator==(const this_class &l, const this_class &r) noexcept
Equality comparison.
Definition: program_args.hpp:779
auto operator--() noexcept -> this_class &
Pre-decrement operator.
Definition: program_args.hpp:821
string_view value_type
Alias for the argument value type.
Definition: program_args.hpp:276
friend auto operator<(const this_class &l, const this_class &r) noexcept
Less-than comparison.
Definition: program_args.hpp:789
auto parse_param(program_parameter< T > &param, std::ostream &errorlog) -> bool
Tries to parse the specified parameter starting from this argument.
Definition: program_args.hpp:479
auto operator-=(difference_type dist) noexcept -> this_class &
Decrement operator.
Definition: program_args.hpp:847
Class wrapping the main function arguments, providing a convenient API.
Definition: program_args.hpp:1082
auto starts_with(string_view str) const noexcept
Indicates if this argument value starts with the specified string.
Definition: program_args.hpp:331
Base class for pre-declared program parameter.
Definition: program_args.hpp:41
int difference_type
Alias for difference type.
Definition: program_args.hpp:761
constexpr auto short_tag() const noexcept -> string_view
Get the short tag string for this parameter.
Definition: program_args.hpp:44
auto has_valid_value() const noexcept -> bool
Indicates if the current value is valid.
Definition: program_args.hpp:106
auto is_tag_param(const basic_program_parameter &param) const
Indicates if this argument value is equal to the one declared in param.
Definition: program_args.hpp:352
auto end() const noexcept -> iterator
Returns an iterator past the last argument.
Definition: program_args.hpp:1170
auto is_last() const noexcept -> bool
Indicates if this is the last command-line argument.
Definition: program_args.hpp:301
auto operator!=(const value_type &v) const noexcept
Indicates if this argument's value is different than the specified string.
Definition: program_args.hpp:666
friend auto operator<=(const this_class &l, const this_class &r) noexcept
Less-equal comparison.
Definition: program_args.hpp:794
friend auto operator-(const this_class &l, const this_class &r) noexcept -> difference_type
Difference.
Definition: program_args.hpp:809
auto consume_next(T &dest, std::ostream &errorlog) -> bool
Tries to parse the following argument's value into dest.
Definition: program_args.hpp:447
auto operator-(difference_type dist) noexcept -> this_class
Difference subtraction.
Definition: program_args.hpp:860
integer_range(B, E) -> integer_range< std::common_type_t< B, E >>
Deduction guide for integer_range.
auto is_valid(const valid_index &pos) const noexcept -> bool
Tests if the specified index references a command line argument.
Definition: program_args.hpp:1136
auto argv() const noexcept -> const char **
Returns a pointer to tha list of argument C-strings.
Definition: program_args.hpp:1116
auto none() const noexcept -> bool
Indicates if the argument list does not contain any arguments.
Definition: program_args.hpp:1126
auto command() const noexcept -> value_type
Returns the command name.
Definition: program_args.hpp:1155
static constexpr auto starts_with(basic_span< T1, P1, S1 > spn, basic_span< T2, P2, S2 > with) -> bool
Indicates if span spn starts with the content of with.
Definition: span_algo.hpp:170
auto next() const noexcept -> program_arg
Returns the argument following this one.
Definition: program_args.hpp:363
auto is_valid() const noexcept -> bool
Indicates if the arguments is valid.
Definition: program_args.hpp:279
constexpr auto long_tag() const noexcept -> string_view
Get the long tag string for this parameter.
Definition: program_args.hpp:49
auto is_first() const noexcept -> bool
Indicates if this is the first command-line argument.
Definition: program_args.hpp:296
friend auto operator>(const this_class &l, const this_class &r) noexcept
Greater-than comparison.
Definition: program_args.hpp:799
static auto operator<<(std::ostream &out, const identifier_name< M > &n) -> std::ostream &
Operator for writing identifier_name into output streams.
Definition: identifier.hpp:159
auto get_string() const -> std::string
Returns the value of this argument as a standard string.
Definition: program_args.hpp:319
constexpr auto description() const noexcept -> string_view
Returns a human-readable description for this program parameter.
Definition: program_args.hpp:54
auto prev() const noexcept -> program_arg
Returns the argument preceding this one.
Definition: program_args.hpp:369
Iterator type over program_arg instances.
Definition: program_args.hpp:750
Basic template for conditionally-valid values.
Definition: base.hpp:86
auto size() const noexcept -> int
Returns the count of arguments (counting in the command name)
Definition: program_args.hpp:1131
constexpr const default_selector_t default_selector
The default overload selector constant.
Definition: selector.hpp:34
auto operator+=(difference_type dist) noexcept -> this_class &
Increment operator.
Definition: program_args.hpp:841

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).