All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FHiCLutils.h
Go to the documentation of this file.
1 /**
2  * @file icarusalg/Utilities/FHiCLutils.h
3  * @brief Simple helper functions to deal with FHiCL.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date August 8, 2019
6  *
7  * This library is header only.
8  */
9 
10 #ifndef ICARUSALG_UTILITIES_FHICLUTILS_H
11 #define ICARUSALG_UTILITIES_FHICLUTILS_H
12 
13 // C/C++ standard libraries
14 #include <vector>
15 
16 
17 namespace util::fhicl {
18 
19  //--------------------------------------------------------------------------
20  /*
21  * Currently util::Quantity objects have serious issues with FHiCL validation,
22  * so we are not reading them directly as such. This pulls in a number of
23  * workarounds for:
24  * * every `Quantity` parameter: its FHiCL parameter must be declared as
25  * the base type `Quantity::value_t`
26  * * every optional parameter must be then read indirectly since a reference
27  * to the exact type of the parameter is required in such reading
28  * * for sequences, direct vector assignment
29  * (`vector<Quantity> = vector<Quantity::value_t>`) won't work, and since
30  * `Sequence::operator()` returns a temporary, this needs to be wraped too
31  */
32 
33  /**
34  * @brief Helper to return a converted sequence from FHiCL configuration.
35  * @tparam SeqValueType type of the sequence value being extracted
36  *
37  * This class can be used to apply implicit conversion of a `fhicl::Sequence`
38  * of objects into a `std::vector` of another type, as sometimes
39  * `fhicl::Sequence` does not support the desired type directly.
40  * For example:
41  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
42  * struct MyData {
43  * int fValue;
44  *
45  * MyData(int value): fValue(value) {}
46  * };
47  *
48  * struct Config {
49  *
50  * fhicl::Sequence<int> Data {
51  * fhicl::Name("Data"),
52  * fhicl::Comment("The data"),
53  * { 0, 1, 2 }
54  * };
55  *
56  * };
57  *
58  * std::vector<MyData> fData;
59  *
60  * MyClass(Config const& config)
61  * : fData(util::FHiCLsequenceWrapper(config.Data()))
62  * {}
63  *
64  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
65  */
66  template <typename SeqValueType>
68 
69 
70  //--------------------------------------------------------------------------
71  /**
72  * @brief Returns the value of an optional parameter as `std::optional`.
73  * @tparam Optional FHiCL optional class (e.g. `fhicl::OptionalAtom`)
74  * @param parameter the optional FHiCL parameter
75  * @return the value of the parameter
76  *
77  * This utility allows to carry the information whether an optional parameter
78  * was specified or not.
79  * It may also help with single-line initialization of data members from
80  * FHiCL optional parameters, e.g.
81  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
82  * struct Config {
83  *
84  * fhicl::Atom<unsigned int> A {
85  * fhicl::Name("A"),
86  * fhicl::Comment("parameter A")
87  * };
88  *
89  * fhicl::OptionalAtom<unsigned int> B {
90  * fhicl::Name("B"),
91  * fhicl::Comment("parameter B (default: same as A)")
92  * };
93  *
94  * };
95  *
96  * unsigned int fA, fB;
97  *
98  * MyClass(Config const& config)
99  * : fA(config.A())
100  * , fB(util::fhicl::getOptionalValue(config.B).value_or(fA))
101  * {}
102  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
103  *
104  * This feature will be rendered obsolete by Redmine Issue #23653.
105  *
106  */
107  template <typename Optional>
108  std::optional<typename Optional::value_type> getOptionalValue
109  (Optional const& parameter);
110 
111 
112  //--------------------------------------------------------------------------
113 
114  /**
115  * @brief Returns the value of an optional parameter, or a default value.
116  * @tparam T type of the value being returned
117  * @tparam Optional FHiCL optional class (e.g. `fhicl::OptionalAtom`)
118  * @param parameter the optional FHiCL parameter
119  * @param defValue default value to be returned
120  * @return the value of the parameter, or `defValue` if absent
121  *
122  * It is usually preferable to use a non-optional FHiCL parameter with a
123  * default value, but some types are not well suited for this.
124  * Also, this function does not buy much unless the parameter reading needs to
125  * be done in a single statement, like in the initialization list of a
126  * constructor:
127  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
128  * struct Config {
129  *
130  * fhicl::OptionalSequenceTable<BoardCfg> Boards {
131  * fhicl::Name("MyStruct"),
132  * fhicl::Comment("data configuration elements")
133  * };
134  *
135  * };
136  *
137  * using AllBoardCfg_t = std::vector<BoardCfg>;
138  *
139  * AllBoardCfg_t fBoards;
140  *
141  *
142  * MyClass(Config const& config)
143  * : fBoards
144  * (util::fhicl::getOptionalValue<BoardCfg>(config.Boards, AllBoardCfg_t{}))
145  * {}
146  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147  *
148  */
149  template <typename T, typename Optional>
150  T getOptionalValue(Optional const& parameter, T defValue);
151 
152 
153  //--------------------------------------------------------------------------
154 
155 
156 } // namespace util
157 
158 
159 //--------------------------------------------------------------------------
160 /*
161  * Currently util::Quantity objects have serious issues with FHiCL validation,
162  * so we are not reading them directly as such. This pulls in a number of
163  * workarounds for:
164  * * every `Quantity` parameter: its FHiCL parameter must be declared as
165  * the base type `Quantity::value_t`
166  * * every optional parameter must be then read indirectly since a reference
167  * to the exact type of the parameter is required in such reading
168  * * for sequences, direct vector assignment
169  * (`vector<Quantity> = vector<Quantity::value_t>`) won't work, and since
170  * `Sequence::operator()` returns a temporary, this needs to be wrapped too
171  */
172 template <typename SeqValueType>
174  SeqValueType seqValue;
175 
176  SequenceWrapper(SeqValueType seqValue): seqValue(seqValue) {}
177 
178  template <typename T>
179  operator std::vector<T>() const
180  { return { seqValue.cbegin(), seqValue.cend() }; }
181 
182 }; // util::fhicl::SequenceWrapper
183 
184 
185 //--------------------------------------------------------------------------
186 template <typename Optional>
187 std::optional<typename Optional::value_type>
188 util::fhicl::getOptionalValue(Optional const& parameter) {
189 
190  using Value_t = typename Optional::value_type;
191 
192  if (!parameter.hasValue()) return std::nullopt;
193 
194  Value_t value;
195  parameter(value);
196  return { value };
197 
198 } // util::fhicl::getOptionalValue(Optional& parameter)
199 
200 
201 //--------------------------------------------------------------------------
202 template <typename T, typename Optional>
203 T util::fhicl::getOptionalValue(Optional const& parameter, T defValue)
204  { parameter(defValue); return defValue; }
205 
206 
207 //--------------------------------------------------------------------------
208 
209 
210 #endif // ICARUSALG_UTILITIES_FHICLUTILS_H
Helper to return a converted sequence from FHiCL configuration.
Definition: FHiCLutils.h:67
std::optional< typename Optional::value_type > getOptionalValue(Optional const &parameter)
Returns the value of an optional parameter as std::optional.
Definition: FHiCLutils.h:188
SequenceWrapper(SeqValueType seqValue)
Definition: FHiCLutils.h:176
temporary value