9 #ifndef LARDATAALG_UTILITIES_MULTIPLECHOICESELECTION_H 10 #define LARDATAALG_UTILITIES_MULTIPLECHOICESELECTION_H 23 #include <type_traits> 30 template <
typename... Strings>
32 std::conjunction_v<std::is_convertible<Strings, std::string>...>;
38 static bool equal(std::string
const& a, std::string
const& b);
41 static bool less(std::string
const& a, std::string
const& b);
44 static bool cmp_lower(
unsigned char a,
unsigned char b);
45 static bool eq_lower(
unsigned char a,
unsigned char b);
50 template <
typename Comparer>
52 bool operator()(std::string
const& a, std::string
const& b)
const;
56 template <
typename Value,
typename =
void>
71 template <
typename Choices>
81 template <
typename... Aliases>
85 template <
typename... Aliases>
86 std::enable_if_t<AllConvertibleToStrings_v<Aliases...>,
Option_t&> addAlias(
88 Aliases... moreAliases);
91 bool match(std::string
const& label)
const;
97 std::string
name()
const {
return labels().front(); }
100 std::vector<std::string>
const&
labels()
const {
return fLabels; }
103 operator std::string()
const {
return name(); }
112 std::string value_as_string()
const;
115 std::string value_as_string(std::string
const& defValue)
const;
118 std::string
dump()
const;
133 static std::optional<std::string> value_as_string(
Choices_t value);
136 static std::string value_as_string(
Choices_t value, std::string
const& defValue);
142 static bool equal(std::string
const& a, std::string
const& b)
144 return Comparer_t::equal(a, b);
171 virtual const char*
what() const noexcept
override {
return s.c_str(); }
181 std::string
const&
label()
const {
return s; }
189 std::string
const&
label()
const {
return s; }
211 template <
typename Choices>
234 template <
typename... Options>
244 std::size_t
size()
const;
265 template <
typename... Aliases>
277 template <
typename... Aliases>
293 template <
typename... Aliases>
302 bool hasOption(std::string
const& label)
const;
305 bool hasOption(
Option_t const& option)
const;
330 Option_t const&
get(std::string
const& label)
const;
339 Option_t const& parse(std::string
const& label)
const;
349 std::string optionListString(std::string
const& sep =
", ")
const;
352 std::string optionListDump(std::string
const&
indent, std::string
const& firstIndent)
const;
369 std::map<std::string, std::size_t, details::SorterFrom<details::CaseInsensitiveComparer>>;
391 void recordLabel(std::string&& label, std::size_t index);
396 template <
typename... Aliases>
398 recordLabels(std::size_t index, std::string alias, Aliases... moreAliases);
401 void unregisterLabel(std::string
const& label);
413 std::size_t findOptionIndex(std::string
const& label)
const;
416 static constexpr
auto npos = std::numeric_limits<std::size_t>::max();
428 template <
typename Choices>
430 bool operator==(MultipleChoiceSelectionOption_t<Choices>
const& option, Choices
const value);
431 template <
typename Choices>
432 bool operator==(Choices
const value, MultipleChoiceSelectionOption_t<Choices>
const& option);
436 template <
typename Choices>
438 bool operator!=(MultipleChoiceSelectionOption_t<Choices>
const& option, Choices
const value);
439 template <
typename Choices>
440 bool operator!=(Choices
const value, MultipleChoiceSelectionOption_t<Choices>
const& option);
444 template <
typename Choices>
446 bool operator==(MultipleChoiceSelectionOption_t<Choices>
const& option, std::string
const& label);
447 template <
typename Choices>
448 bool operator==(std::string
const& label, MultipleChoiceSelectionOption_t<Choices>
const& option);
452 template <
typename Choices>
454 bool operator!=(MultipleChoiceSelectionOption_t<Choices>
const& option, std::string
const& label);
455 template <
typename Choices>
456 bool operator!=(std::string
const& label, MultipleChoiceSelectionOption_t<Choices>
const& option);
463 template <
typename Choices>
465 MultipleChoiceSelectionOption_t<Choices>
const& option);
475 template <
typename B1,
typename E1,
typename B2,
typename E2,
typename Comp>
480 if (b2 == e2)
return false;
482 if (
less(*b1, *b2))
return true;
483 if (
less(*b2, *b1))
return false;
492 std::string
const& b)
494 return std::equal(a.begin(), a.end(), b.begin(), b.end(),
eq_lower);
500 return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(),
cmp_lower);
506 return std::tolower(a) < std::tolower(b);
512 return std::tolower(a) == std::tolower(b);
516 template <
typename Comparer>
518 std::string
const& b)
const 520 return Comparer::less(a, b);
526 template <
typename Value,
typename >
528 static constexpr
bool can_convert =
false;
530 template <
typename T>
531 static std::optional<std::string>
convert(T
const&)
538 template <
typename Value>
540 static constexpr
bool can_convert =
true;
542 template <
typename T>
545 return {
std::to_string(
static_cast<std::underlying_type_t<T>
>(value))};
550 template <
typename Value>
552 std::enable_if_t<std::is_convertible_v<Value, std::string> ||
553 std::is_constructible_v<std::string, Value>>> {
554 static constexpr
bool can_convert =
true;
555 template <
typename T>
558 return {std::string{value}};
563 template <
typename Value>
564 struct ValueToString<Value,
std::void_t<decltype(std::to_string(std::declval<Value>()))>> {
565 static constexpr
bool can_convert =
true;
566 template <
typename T>
578 template <
typename Choices>
579 template <
typename... Aliases>
586 fLabels.reserve(1U +
sizeof...(aliases));
587 addAlias(std::move(name), std::move(aliases)...);
591 template <
typename Choices>
592 template <
typename... Aliases>
594 Aliases... moreAliases)
597 fLabels.push_back(std::move(alias));
598 if constexpr (
sizeof...(moreAliases) > 0)
599 return addAlias(std::move(moreAliases)...);
605 template <
typename Choices>
608 return std::find_if(
fLabels.begin(),
fLabels.end(), [&label](std::string
const& alias) {
609 return equal(label, alias);
614 template <
typename Choices>
616 std::string
const& defValue)
const 622 template <
typename Choices>
629 template <
typename Choices>
637 template <
typename Choices>
640 std::string
const& defValue)
646 template <
typename Choices>
650 auto const lend =
fLabels.end();
655 if (valueStr != *iLabel) {
660 if (++iLabel != lend) {
661 s +=
" (aliases: \"";
664 while (++iLabel != lend) {
676 template <
typename Choices>
683 template <
typename Choices>
687 return option ==
value;
691 template <
typename Choices>
698 template <
typename Choices>
702 return option !=
value;
706 template <
typename Choices>
708 std::string
const& label)
710 return option.
match(label);
713 template <
typename Choices>
717 return option == label;
721 template <
typename Choices>
723 std::string
const& label)
725 return !option.
match(label);
728 template <
typename Choices>
732 return option != label;
736 template <
typename Choices>
740 out << option.
name();
747 template <
typename Choices>
748 template <
typename... Options>
750 std::initializer_list<Option_t> options)
753 addOption(std::move(option));
757 template <
typename Choices>
760 return fOptions.size();
764 template <
typename Choices>
767 return fOptions.empty();
771 template <
typename Choices>
772 template <
typename... Aliases>
775 Aliases... aliases) ->
Option_t const&
777 return addOption({
value, std::move(label), std::move(aliases)...});
781 template <
typename Choices>
782 template <
typename... Aliases>
786 std::size_t
const index = findOptionIndex(
value);
788 recordLabels(index, aliases...);
789 return fOptions[index].addAlias(std::move(aliases)...);
793 template <
typename Choices>
794 template <
typename... Aliases>
798 return addAlias(option.value(), std::move(aliases)...);
802 template <
typename Choices>
805 return findOption(value) != fOptions.end();
809 template <
typename Choices>
812 return fLabelToOptionIndex.find(label) != fLabelToOptionIndex.end();
816 template <
typename Choices>
819 return hasOption(option.
value());
823 template <
typename Choices>
826 auto const iOption = findOption(
value);
827 if (iOption == fOptions.end())
833 template <
typename Choices>
836 auto const iLabelIndexPair = fLabelToOptionIndex.find(label);
837 if (iLabelIndexPair == fLabelToOptionIndex.end()) {
throw UnknownOptionError(label); }
838 assert(iLabelIndexPair->second < fOptions.size());
839 return fOptions[iLabelIndexPair->second];
843 template <
typename Choices>
851 template <
typename Choices>
853 std::string
const& sep )
const 857 auto iOption = fOptions.begin();
858 auto const oend = fOptions.end();
860 if (iOption == oend)
return "<no options>"s;
862 std::string s{*iOption};
863 while (++iOption != oend) {
871 template <
typename Choices>
873 std::string
const&
indent,
874 std::string
const& firstIndent)
const 878 auto iOption = fOptions.begin();
879 auto const oend = fOptions.end();
881 if (iOption == oend)
return firstIndent +
"<no options>\n"s;
883 std::string s{firstIndent};
884 s += iOption->dump();
886 while (++iOption != oend) {
888 s += iOption->dump();
895 template <
typename Choices>
898 std::size_t
const newOptionIndex =
size();
900 fOptions.push_back(std::move(option));
901 Option_t const& newOption = fOptions.back();
903 for (
auto iLabel =
labels.begin(); iLabel !=
labels.end(); ++iLabel) {
905 recordLabel(std::string{*iLabel}, newOptionIndex);
913 for (
auto iNewLabel =
labels.begin(); iNewLabel != iLabel; ++iNewLabel)
914 unregisterLabel(*iNewLabel);
928 template <
typename Choices>
932 auto const iOption = fLabelToOptionIndex.lower_bound(label);
939 if ((iOption != fLabelToOptionIndex.end()) &&
940 !OptionLabelMap_t::key_compare()(label, iOption->first)) {
945 fLabelToOptionIndex.emplace_hint(iOption, std::move(label), index);
950 template <
typename Choices>
951 template <
typename... Aliases>
954 Aliases... moreAliases)
958 recordLabel(std::move(alias), index);
959 if constexpr (
sizeof...(moreAliases) > 0U) recordLabels(index, std::move(moreAliases)...);
962 unregisterLabel(alias);
968 template <
typename Choices>
971 fLabelToOptionIndex.erase(label);
975 template <
typename Choices>
979 auto const matchValue = [
value](
Option_t const& option) {
return option.value() ==
value; };
980 return std::find_if(fOptions.begin(), fOptions.end(), matchValue);
984 template <
typename Choices>
988 auto const matchValue = [
value](
Option_t const& option) {
return option.value() ==
value; };
989 return std::find_if(fOptions.begin(), fOptions.end(), matchValue);
993 template <
typename Choices>
996 auto const d =
static_cast<std::size_t
>(std::distance(fOptions.begin(), findOption(value)));
997 return (
d >=
size()) ? npos :
d;
1001 template <
typename Choices>
1004 auto const iOption = fLabelToOptionIndex.find(label);
1005 return (iOption == fLabelToOptionIndex.end()) ? npos : iOption->second;
1012 #endif // LARDATAALG_UTILITIES_MULTIPLECHOICESELECTION_H Request for unknown option.
std::string const & label() const
std::enable_if_t< details::AllConvertibleToStrings_v< Aliases... >, Option_t const & > addAlias(Choices_t value, Aliases...aliases)
Adds aliases to an existing option.
bool my_lexicographical_compare(B1 b1, E1 e1, B2 b2, E2 e2, Comp less)
Namespace for general, non-LArSoft-specific utilities.
bool hasOption(Choices_t value) const
Returns whether the selector has an option with the specified value.
static std::optional< std::string > convert(T const &value)
std::vector< std::string > const & labels() const
Returns an iterable object with all the labels of the option.
std::enable_if_t< AllConvertibleToStrings_v< Aliases... >, Option_t & > addAlias(std::string alias, Aliases...moreAliases)
Adds aliases.
static std::optional< std::string > convert(T const &)
Option_t const & parse(std::string const &label) const
Returns the option matching the specified label.
bool operator==(Option_t const &option) const
Returns whether the two options are the same (same value and name).
static bool cmp_lower(unsigned char a, unsigned char b)
std::string optionListString(std::string const &sep=", ") const
Returns a string with the (main) name of all options.
void recordLabel(std::string &&label, std::size_t index)
Base class of util::MultipleChoiceSelection with basics independent of the option type...
Choices Choices_t
Type of the underlying choice.
std::vector< Option_t > OptionList_t
Type of collection of options.
std::ostream & operator<<(std::ostream &out, MultipleChoiceSelectionOption_t< Choices > const &option)
Prints an option into a stream.
std::map< std::string, std::size_t, details::SorterFrom< details::CaseInsensitiveComparer >> OptionLabelMap_t
Type of label index (associative container: label to option index).
bool operator!=(Option_t const &option) const
Returns whether the two options are not the same.
Class representing one of the available options to be selected.
Choices_t fValue
The value associated to the option.
std::vector< std::string > fLabels
All the labels.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
static bool eq_lower(unsigned char a, unsigned char b)
OptionAlreadyExistsError()
MultipleChoiceSelectionOption_t(Choices_t value, std::string name, Aliases...aliases)
Constructor: assigns value, name and aliases.
Option_t const & get(Choices_t value) const
Returns the specified option.
std::string optionListDump(std::string const &indent="") const
Returns a string with all the options, one per line.
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
static std::optional< std::string > convert(T const &value)
std::string indent(std::size_t const i)
OptionLabelMap_t fLabelToOptionIndex
Map from labels to option index in fOptions.
MultipleChoiceSelection()=default
std::string value_as_string() const
void unregisterLabel(std::string const &label)
Removes the specified label from the register.
Option_t const & addOption(Choices_t value, std::string label, Aliases...aliases)
Adds a new option to the selector.
static std::optional< std::string > convert(T const &value)
std::string name() const
Returns the name of the option (i.e. the main label).
Collection of utilities for dumping data on screen.
static bool equal(std::string const &a, std::string const &b)
bool operator()(std::string const &a, std::string const &b) const
UnknownOptionError(std::string const &label)
constexpr auto AllConvertibleToStrings_v
OptionList_t::const_iterator findOption(Choices_t value) const
Returns an iterator to the option with label, or npos if none.
std::string dump() const
Returns in a string the name and all the aliases.
OptionList_t fOptions
The list of registered objects.
bool empty() const
Returns whether there is no available option.
std::string optionListDump(std::string const &indent, std::string const &firstIndent) const
Returns a string with all the options, one per line.
static bool less(std::string const &a, std::string const &b)
Returns whether a is lexicographically smaller than b.
bool match(std::string const &label) const
Returns whether this option matches the specified label (name or alias).
OptionAlreadyExistsError(std::string const &label)
std::string const & label() const
bool operator!=(infinite_endcount_iterator< T > const &, count_iterator< T > const &)
Never admit a infinite_endcount_iterator to be equal to anything else.
std::size_t findOptionIndex(Choices_t value) const
Returns the index of the option with label, or npos if none.
Adding an option that already exists.
Helper to select one among multiple choices via strings.
std::size_t size() const
Returns the number of available options.
static bool equal(std::string const &a, std::string const &b)
Returns whether strings a and b are equal.
std::enable_if_t< details::AllConvertibleToStrings_v< Aliases... > > recordLabels(std::size_t index, std::string alias, Aliases...moreAliases)
virtual const char * what() const noexcept override
Exception(std::string const &s)
bool operator==(infinite_endcount_iterator< T > const &, count_iterator< T > const &)
cet::coded_exception< error, detail::translate > exception
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Choices_t value() const
Returns a copy of the value of the option.