LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
OptionalSequence.h
Go to the documentation of this file.
1 #ifndef fhiclcpp_types_OptionalSequence_h
2 #define fhiclcpp_types_OptionalSequence_h
3 
4 #include "fhiclcpp/type_traits.h"
5 #include "fhiclcpp/types/Atom.h"
14 
15 #include <array>
16 #include <optional>
17 #include <string>
18 #include <type_traits>
19 #include <variant>
20 
21 namespace fhicl {
22 
23  class ParameterSet;
24 
25  //==================================================================
26  // e.g. OptionalSequence<int,4> ====> std::array<int,4>
27  //
28  template <typename T, std::size_t N = -1ull>
29  class OptionalSequence final : public detail::SequenceBase,
30  private detail::RegisterIfTableMember {
31  public:
32  static_assert(!tt::is_table_fragment_v<T>, NO_NESTED_TABLE_FRAGMENTS);
33  static_assert(!tt::is_optional_parameter_v<T>, NO_OPTIONAL_TYPES);
34  static_assert(!tt::is_delegated_parameter_v<T>, NO_DELEGATED_PARAMETERS);
35 
36  using ftype = std::array<std::shared_ptr<tt::fhicl_type<T>>, N>;
37  using value_type = std::array<tt::return_type<T>, N>;
38 
39  explicit OptionalSequence(Name&& name);
40  explicit OptionalSequence(Name&& name, Comment&& comment);
41  explicit OptionalSequence(Name&& name,
42  Comment&& comment,
43  std::function<bool()> maybeUse);
44 
45  std::optional<value_type>
46  operator()() const
47  {
48  if (!has_value_)
49  return std::nullopt;
50 
51  if (auto value = std::get_if<value_type>(&value_)) {
52  return std::make_optional(*value); // Do not move!
53  }
54 
55  value_type result = {{tt::return_type<T>()}};
56  cet::transform_all(std::get<ftype>(value_),
57  result.begin(),
58  [](auto const& elem) { return (*elem)(); });
59  return std::make_optional(std::move(result));
60  }
61 
62  // Obsolete interface
63  bool
65  {
66  auto const result = operator()();
67  if (result) {
68  t = *result;
69  }
70  return result.has_value();
71  }
72 
73  bool
74  hasValue() const noexcept
75  {
76  return has_value_;
77  }
78 
79  private:
80  std::variant<ftype, value_type> value_;
81  bool has_value_{false};
82 
83  std::size_t
84  get_size() const noexcept override
85  {
86  if (auto value = std::get_if<value_type>(&value_)) {
87  return value->size();
88  }
89  return std::get<ftype>(value_).size();
90  }
91 
92  void
93  do_prepare_elements_for_validation(std::size_t const n) override
94  {
96  }
97 
98  void
101  {
102  // We only enter here if we do not have a preset value.
103  cet::for_all(std::get<ftype>(value_),
104  [&pw](auto& e) { pw.walk_over(*e); });
105  }
106 
107  void
109  pw) const override
110  {
111  // We only enter here if we do not have a preset value.
112  cet::for_all(std::get<ftype>(value_),
113  [&pw](auto const& e) { pw.walk_over(*e); });
114  }
115 
116  bool do_preset_value(fhicl::ParameterSet const&) override;
117  void do_set_value(fhicl::ParameterSet const&) override;
118  };
119 
120  //==================================================================
121  // e.g. OptionalSequence<int> ====> std::vector<int>
122  //
123  template <typename T>
124  class OptionalSequence<T, -1ull> final
125  : public detail::SequenceBase,
127  public:
128  static_assert(!tt::is_table_fragment_v<T>, NO_NESTED_TABLE_FRAGMENTS);
129  static_assert(!tt::is_optional_parameter_v<T>, NO_OPTIONAL_TYPES);
130  static_assert(!tt::is_delegated_parameter_v<T>, NO_DELEGATED_PARAMETERS);
131 
132  using ftype = std::vector<std::shared_ptr<tt::fhicl_type<T>>>;
133  using value_type = std::vector<tt::return_type<T>>;
134 
135  explicit OptionalSequence(Name&& name);
136  explicit OptionalSequence(Name&& name, Comment&& comment);
137  explicit OptionalSequence(Name&& name,
138  Comment&& comment,
139  std::function<bool()> maybeUse);
140 
141  std::optional<value_type>
142  operator()() const
143  {
144  if (!has_value_)
145  return std::nullopt;
146 
147  if (auto value = std::get_if<value_type>(&value_)) {
148  return std::make_optional(std::move(*value));
149  }
150 
151  value_type result;
152  cet::transform_all(std::get<ftype>(value_),
153  std::back_inserter(result),
154  [](auto const& elem) { return (*elem)(); });
155  return std::make_optional(std::move(result));
156  }
157 
158  // Obsolete
159  bool
161  {
162  if (auto result = operator()()) {
163  t = *result;
164  return true;
165  }
166  return false;
167  }
168 
169  bool
170  hasValue() const noexcept
171  {
172  return has_value_;
173  }
174 
175  private:
176  std::variant<ftype, value_type> value_;
177  bool has_value_{false};
178 
179  void
180  do_prepare_elements_for_validation(std::size_t const n) override
181  {
182  // We only enter here if we do not have a preset value.
183  auto& value = std::get<ftype>(value_);
184 
185  if (n < value.size()) {
186  value.resize(n);
187  } else if (n > value.size()) {
188 
189  std::string key_fragment{key()};
190  // When emplacing a new element, do not include in the key
191  // argument the current name-stack stem--it will
192  // automatically be prepended.
193  if (!NameStackRegistry::empty()) {
194  std::string const& current_stem = NameStackRegistry::current();
195  std::size_t const pos =
196  key_fragment.find(current_stem) != std::string::npos ?
197  current_stem.size() + 1ul : // + 1ul to account for the '.'
198  0ul;
199  key_fragment.replace(0ul, pos, "");
200  }
201 
202  for (auto i = value.size(); i != n; ++i) {
203  value.emplace_back(
204  new tt::fhicl_type<T>{Name::sequence_element(key_fragment, i)});
205  }
206  }
207  }
208 
209  std::size_t
210  get_size() const noexcept override
211  {
212  if (auto value = std::get_if<value_type>(&value_)) {
213  return value->size();
214  }
215  return std::get<ftype>(value_).size();
216  }
217 
218  void
221  {
222  // We only enter here if we do not have a preset value.
223  cet::for_all(std::get<ftype>(value_),
224  [&pw](auto& e) { pw.walk_over(*e); });
225  }
226 
227  void
229  pw) const override
230  {
231  // We only enter here if we do not have a preset value.
232  cet::for_all(std::get<ftype>(value_),
233  [&pw](auto const& e) { pw.walk_over(*e); });
234  }
235 
236  bool do_preset_value(fhicl::ParameterSet const&) override;
237  void do_set_value(fhicl::ParameterSet const&) override;
238  };
239 }
240 
242 
243 namespace fhicl {
244 
245  //==================================================================
246  // e.g. OptionalSequence<int,4> ====> std::array<int,4>
247  //
248  template <typename T, std::size_t N>
250  : OptionalSequence{std::move(name), Comment("")}
251  {}
252 
253  template <typename T, std::size_t N>
255  : SequenceBase{std::move(name),
256  std::move(comment),
260  , RegisterIfTableMember{this}
261  , value_{ftype{nullptr}}
262  {
263  auto& value = std::get<ftype>(value_);
264  for (std::size_t i{}; i != N; ++i) {
265  value.at(i) =
266  std::make_shared<tt::fhicl_type<T>>(Name::sequence_element(i));
267  }
269  }
270 
271  template <typename T, std::size_t N>
273  Comment&& comment,
274  std::function<bool()> maybeUse)
275  : SequenceBase{std::move(name),
276  std::move(comment),
279  maybeUse}
280  , RegisterIfTableMember{this}
281  , value_{ftype{nullptr}}
282  {
283  auto& value = std::get<ftype>(value_);
284  for (std::size_t i{}; i != N; ++i) {
285  value.at(i) =
286  std::make_shared<tt::fhicl_type<T>>(Name::sequence_element(i));
287  }
289  }
290 
291  template <typename T, std::size_t N>
292  bool
294  {
295  if constexpr (std::is_same_v<tt::fhicl_type<T>, Atom<T>>) {
296  auto const trimmed_key = detail::strip_first_containing_name(key());
297  value_ = ps.get<value_type>(trimmed_key);
298  has_value_ = true;
299  return true;
300  }
301  return false;
302  }
303 
304  template <typename T, std::size_t N>
305  void
307  {
308  // We do not explicitly set the sequence values here as the
309  // individual elements are set one at a time. However, this
310  // function is reached in the ValidateThenSet algorithm if the
311  // optional parameter is present. Otherwise, this override is
312  // skipped.
313  has_value_ = true;
314  }
315 
316  //==================================================================
317  // e.g. OptionalSequence<int> ====> std::vector<int>
318  //
319 
320  template <typename T>
322  : OptionalSequence{std::move(name), Comment("")}
323  {}
324 
325  template <typename T>
327  : SequenceBase{std::move(name),
328  std::move(comment),
332  , RegisterIfTableMember{this}
333  , value_{
334  ftype{std::make_shared<tt::fhicl_type<T>>(Name::sequence_element(0ul))}}
335  {
337  }
338 
339  template <typename T>
341  Comment&& comment,
342  std::function<bool()> maybeUse)
343  : SequenceBase{std::move(name),
344  std::move(comment),
347  maybeUse}
348  , RegisterIfTableMember{this}
349  , value_{
350  ftype{std::make_shared<tt::fhicl_type<T>>(Name::sequence_element(0ul))}}
351  {
353  }
354 
355  template <typename T>
356  bool
358  {
359  if constexpr (std::is_same_v<tt::fhicl_type<T>, Atom<T>>) {
360  auto const trimmed_key = detail::strip_first_containing_name(key());
361  value_ = ps.get<value_type>(trimmed_key);
362  has_value_ = true;
363  return true;
364  }
365  return false;
366  }
367 
368  template <typename T>
369  void
371  {
372  // We do not explicitly set the sequence values here as the
373  // individual elements are set one at a time. However, this
374  // function is reached in the ValidateThenSet algorithm if the
375  // optional parameter is present. Otherwise, this override is
376  // skipped.
377  has_value_ = true;
378  }
379 }
380 
381 #endif /* fhiclcpp_types_OptionalSequence_h */
382 
383 // Local variables:
384 // mode: c++
385 // End:
std::variant< ftype, value_type > value_
void do_prepare_elements_for_validation(std::size_t const n) override
std::size_t size() const noexcept
Definition: SequenceBase.h:33
std::array< tt::return_type< art::InputTag >,-1ull > value_type
#define NO_DELEGATED_PARAMETERS
void check_nargs_for_bounded_sequences(std::string const &key, std::size_t expected, std::size_t provided)
void do_walk_elements(detail::ParameterWalker< tt::const_flavor::require_non_const > &pw) override
std::size_t get_size() const noexcept override
#define NO_OPTIONAL_TYPES
std::function< bool()> AlwaysUse()
SequenceBase(Name &&name, Comment &&comment, par_style const vt, par_type const type, std::function< bool()> maybeUse)
Definition: SequenceBase.h:19
void do_set_value(fhicl::ParameterSet const &) override
std::array< std::shared_ptr< tt::fhicl_type< art::InputTag >>,-1ull > ftype
std::variant< ftype, value_type > value_
std::string strip_first_containing_name(std::string const &key)
void walk_over(tt::maybe_const_t< ParameterBase, C > &)
static std::string current()
typename fhicl_type_impl< T >::type fhicl_type
Definition: type_traits.h:315
parameter set interface
T get(std::string const &key) const
Definition: ParameterSet.h:314
bool operator()(value_type &t) const
std::string const & name() const
void do_prepare_elements_for_validation(std::size_t const n) override
bool hasValue() const noexcept
std::string const & key() const
Definition: ParameterBase.cc:6
std::optional< value_type > operator()() const
void do_walk_elements(detail::ParameterWalker< tt::const_flavor::require_const > &pw) const override
#define NO_NESTED_TABLE_FRAGMENTS
void do_walk_elements(detail::ParameterWalker< tt::const_flavor::require_non_const > &pw) override
double value
Definition: spectrum.C:18
bool operator()(value_type &t) const
static Name sequence_element(std::size_t const i)
Definition: Name.h:16
bool do_preset_value(fhicl::ParameterSet const &) override
void do_walk_elements(detail::ParameterWalker< tt::const_flavor::require_const > &pw) const override
Char_t n[5]
std::vector< tt::return_type< T >> value_type
std::optional< value_type > operator()() const
typename return_type_impl< ARGS... >::value_type return_type
Definition: type_traits.h:357
std::string const & comment() const
std::vector< std::shared_ptr< tt::fhicl_type< T >>> ftype
Float_t e
Definition: plot.C:35
std::size_t get_size() const noexcept override