LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
ValidateThenSet.cc
Go to the documentation of this file.
2 #include "cetlib/container_algorithms.h"
3 #include "fhiclcpp/exception.h"
10 
11 #include <iomanip>
12 #include <regex>
13 
14 //====================================================================
15 
17  ParameterSet const& pset,
18  std::set<std::string> const& keysToIgnore)
19  : pset_{pset}
20  , ignorableKeys_{keysToIgnore}
21  , userKeys_{pset.get_all_keys()}
23 {
24  cet::sort_all(userKeys_);
25 }
26 
28 
29 void
31 {}
32 
33 void
35 {}
36 
37 bool
39 {
40  // 'ConfigPredicate' condition must be satisfied to continue.
41  if (!p.should_use())
42  return false;
43 
44  // Check that key exists; allow defaulted or optional keys to be
45  // absent.
46  std::string const& k = strip_first_containing_name(p.key());
47  if (!pset_.has_key(k) and !cet::search_all(ignorableKeys_, k)) {
48  if (!p.has_default() and !p.is_optional()) {
49  missingParameters_.emplace_back(&p);
50  }
51  return false;
52  }
53 
54  // Sometimes we are able to short-circuit walking the parameters
55  // that belong to a sequence. This is especially helpful for
56  // sequences with many entries of atomic type.
57  if (is_sequence(p.parameter_type()) and p.preset_value(pset_)) {
58  // Remove all entries that match the sequence key and any elements
59  // of that sequence.
60  auto erase_from =
61  std::remove_if(userKeys_.begin(), userKeys_.end(), [&k](auto const& e) {
62  return e.find(k + '[') == 0ull or e == k;
63  });
64  userKeys_.erase(erase_from, userKeys_.cend());
65  return false;
66  }
67 
68  auto erase_from = std::remove(userKeys_.begin(), userKeys_.end(), k);
69  userKeys_.erase(erase_from, userKeys_.cend());
70  return true;
71 }
72 
73 void
75 {
76  p.set_value(pset_);
77 }
78 
79 //====================================================================
80 
81 void
83 {
84  // Ensure that the supplied parameter represents a sequence.
85  auto const& key = strip_first_containing_name(s.key());
86  if (!pset_.is_key_to_sequence(key)) {
87  throw fhicl::exception(type_mismatch, "error converting to sequence:\n")
88  << "The supplied value of the parameter:\n"
89  << " " << s.key() << '\n'
90  << "does not represent a sequence.\n";
91  }
92 
93  std::regex const r{fhicl::Name::regex_safe(key) + "\\[\\d+\\]"};
94  std::size_t const nElems =
95  std::count_if(userKeys_.begin(), userKeys_.end(), [&r](auto const& k) {
96  return std::regex_match(k, r);
97  });
99 }
100 
101 //====================================================================
102 
103 void
105 {
106  // A delegated parameter must itself be present, but any nested
107  // parameters do not need to be present since the nested parameters
108  // are potentially validated elsewhere.
109  auto const& name = dp.name();
110  std::string const pattern{fhicl::Name::regex_safe(name) + R"((\.|\[))"};
111  std::regex const r{pattern};
112  auto erase_from =
113  std::remove_if(userKeys_.begin(), userKeys_.end(), [&r](auto const& k) {
114  return std::regex_search(k, r);
115  });
116  userKeys_.erase(erase_from, userKeys_.end());
117 }
118 
119 //====================================================================
120 
121 namespace {
122 
126  using key_set = std::set<std::string>;
127 
128  void
129  removeIgnorableKeys(key_set const& ignorable,
130  std::vector<std::string>& extra,
131  std::vector<cet::exempt_ptr<ParameterBase>>& missing)
132  {
133  for (auto const& key : ignorable) {
134 
135  auto const& subkey = strip_first_containing_name(key);
136 
137  // Allow erasure globbing for extra keys (if "parameter" is an
138  // ignorable key, then "parameter.a" is also ignorable)
139  auto it = cet::find_in_all(extra, subkey);
140  if (it != extra.cend()) {
141  auto match = [&subkey](std::string const& key) {
142  return key.find(subkey) == 0ul;
143  };
144  auto const end = std::find_if_not(it, extra.end(), match);
145  extra.erase(it, end);
146  }
147 
148  // Since all ignorable missing keys are set explicitly, we do
149  // not glob erasures.
150  auto mit =
151  std::remove_if(missing.begin(), missing.end(), [&subkey](auto p) {
152  return p->key() == subkey;
153  });
154 
155  missing.erase(mit, missing.end());
156  }
157  }
158 
159  inline bool
160  show_parents(std::string const& k)
161  {
162  std::size_t const freq =
163  std::count(k.begin(), k.end(), '.') + std::count(k.begin(), k.end(), '[');
164  return freq > 1;
165  }
166 
167  std::string
168  fillMissingKeysMsg(
169  std::vector<cet::exempt_ptr<ParameterBase>> const& missingParams)
170  {
171  if (missingParams.empty())
172  return "";
173 
174  std::string const prefix{" - " + std::string(3, ' ')};
175 
176  std::ostringstream oss;
177  oss << "Missing parameters:\n";
178  for (auto p : missingParams) {
179 
180  // If the key is nested (e.g. pset1.pset2[0] ), show the
181  // parents
182  PrintAllowedConfiguration pc{oss, show_parents(p->key()), prefix, true};
183  pc.walk_over(*p);
184  }
185  oss << "\n";
186 
187  return oss.str();
188  }
189 
190  std::string
191  fillExtraKeysMsg(fhicl::ParameterSet const& pset,
192  std::vector<std::string> const& extraKeys)
193  {
194  if (extraKeys.empty())
195  return "";
196 
197  std::ostringstream oss;
198  oss << "Unsupported parameters:\n\n";
199  for (auto const& key : extraKeys) {
200  oss << " + " << std::setw(30) << std::left << key << " [ "
201  << pset.get_src_info(key) << " ]\n";
202  }
203  oss << '\n';
204 
205  return oss.str();
206  }
207 }
208 
209 void
211 {
212  removeIgnorableKeys(ignorableKeys_, userKeys_, missingParameters_);
213  std::string errmsg;
214  errmsg += fillMissingKeysMsg(missingParameters_);
215  errmsg += fillExtraKeysMsg(pset_, userKeys_);
216  if (!errmsg.empty()) {
217  std::string fullmsg{detail::optional_parameter_message(false)};
218  fullmsg += "\n";
219  fullmsg += errmsg;
220  throw validationException{fullmsg.c_str()};
221  }
222 }
TRandom r
Definition: spectrum.C:23
void prepare_elements_for_validation(std::size_t const n)
Definition: SequenceBase.h:39
void enter_sequence(SequenceBase &p) override
void set_value(fhicl::ParameterSet const &ps)
bool preset_value(fhicl::ParameterSet const &ps)
void enter_table(TableBase &) override
std::set< std::string > ignorableKeys_
std::vector< std::string > userKeys_
std::string optional_parameter_message(bool const with_comment=true)
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
bool is_key_to_sequence(std::string const &key) const
Definition: ParameterSet.h:214
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
std::string strip_first_containing_name(std::string const &key)
void walk_over(tt::maybe_const_t< ParameterBase, C > &)
ParameterSet const & pset_
par_type parameter_type() const
std::string const & name() const
std::string const & key() const
Definition: ParameterBase.cc:6
void delegated_parameter(DelegateBase &) override
bool has_key(std::string const &key) const
ValidateThenSet(ParameterSet const &pset, std::set< std::string > const &keysToIgnore)
std::vector< cet::exempt_ptr< ParameterBase > > missingParameters_
static std::string regex_safe(std::string const &key)
Definition: Name.h:31
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:94
void atom(AtomBase &) override
std::string get_src_info(std::string const &key) const
void after_action(ParameterBase &p) override
Float_t e
Definition: plot.C:35
bool before_action(ParameterBase &p) override
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
bool is_sequence(std::any const &val)
Definition: coding.h:49