All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NameSelector.h
Go to the documentation of this file.
1 /**
2  * @file NameSelector.h
3  * @brief A class providing a selection list
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date July 24, 2015
6  * @see NameSelector.cxx
7  */
8 
9 #ifndef TEST_GEOMETRY_NAMESELECTOR_H
10 #define TEST_GEOMETRY_NAMESELECTOR_H 1
11 
12 // C/C++ standard library
13 #include <initializer_list>
14 #include <iosfwd>
15 #include <string>
16 #include <set>
17 #include <map>
18 #include <stddef.h>
19 
20 // ... and more in the template implementation section below
21 
22 namespace testing {
23 
24  /**
25  * @brief Manages a set of names
26  *
27  * This class contains a set of names to be "accepted" and a set of names
28  * to be "rejected". Queries on unknown names will generate a default
29  * answer that can be acceptance, rejection or an exception.
30  *
31  * The class is initialized by a list of strings following the convention
32  * detailed in ProcessItem().
33  * The default answer is set on construction, but it can be overridden to
34  * a "reject by default" using a specific identifier.
35  *
36  */
37  class NameSelector {
38 
39  public:
40  using Name_t = std::string; ///< type representing a name
41  using Names_t = std::set<Name_t>; ///< list of names
42 
43  /// Possible responses
44  typedef enum {
45  rsRejected, ///< rejected
46  rsAccepted, ///< accepted
47  rsThrow, ///< throw art::Exception (art::errors::Configuration)
49  } Response_t;
50 
51 
52  using NameList = std::initializer_list<Name_t>;
53 
54 
55  /// Constructor: an empty selector with a default answer for unknown names
56  NameSelector(Response_t default_answer = rsDefault)
57  { SetDefaultResponse(default_answer); }
58 
59  /// Constructor: Parse()s the specified items
60  template <typename LIST>
61  NameSelector(LIST const& items, Response_t default_answer = rsDefault)
62  : NameSelector(default_answer)
63  { Parse(items); }
64 
65  /// Sets the default answer for names that are not registered
66  void SetDefaultResponse(Response_t default_answer)
67  { known_names[DefaultName] = { default_answer }; }
68 
69  /**
70  * @brief Parses the names in the list and adds them to the selector
71  * @tparam LIST type of list of strings
72  * @param items the definitions to be used
73  *
74  * Specified items are processed with ProcessItem() and the current set is
75  * modified.
76  */
77  template <typename LIST>
78  void Parse(LIST const& items) { BuildNameSet(known_names, items); }
79 
80 
81  /**
82  * @brief Parses a name and adds it to the selector
83  * @param name name specification to be parsed
84  *
85  * The name is processed with ProcessItem() and the current set is modified.
86  */
87  void ParseName(Name_t name);
88 
89  /**
90  * @brief Parses a list of names and adds them to the selector
91  * @tparam NAMES Name_t-compatible types
92  * @param names the definitions to be used
93  *
94  * Specified items are processed with ProcessItem() and modify the current
95  * set.
96  */
97  template <typename... NAMES>
98  void ParseNames(NAMES... names) { AddFirstName(known_names, names...); }
99 
100  /// Erases all the names in the selector (default answer is unchanged)
102 
103  /**
104  * @brief Defines a set
105  * @tparam LIST type of list of strings
106  * @param set_name name of the set to be defined
107  * @param items the definitions to be used
108  *
109  * Specified items are processed with BuildSet(); the result is stored as
110  * a set with the specified name.
111  * If a set with that name already exists, it's replaced and the old one
112  * is lost.
113  */
114  template <typename LIST>
115  void Define(std::string set_name, LIST const& items);
116 
117  /**
118  * @brief Parses a list of names and add them to the specified definition
119  * @tparam NAMES Name_t-compatible types
120  * @param set_name name of the set to be defined
121  * @param names the definitions to be used
122  *
123  * Specified items are processed with ProcessItem(); the result is added to
124  * the set with the specified name.
125  * If a set with that name does not exist, it's created empty.
126  */
127  template <typename... NAMES>
128  void AddToDefinition(std::string set_name, NAMES... names)
129  { AddFirstName(definitions[set_name], names...); }
130 
131  /// Returns the response for the specified name (does not throw)
132  Response_t Query(Name_t name) const;
133 
134  /// Returns whether the name is accepted as good
135  bool Accepted(Name_t name) const;
136 
137  /// Returns whether the name is rejected as bad
138  bool Rejected(Name_t name) const { return !Accepted(name); }
139 
140  /// Returns the default answer for names that are not registered
142  { return known_names.find(DefaultName)->second.response; }
143 
144  /// Returns whether the name is accepted as good (alias for accept())
145  bool operator() (Name_t name) const { return Accepted(name); }
146 
147  /// Prints the configuration into a stream
148  void PrintConfiguration(std::ostream&) const;
149 
150  /// Returns a list of names that were accepted
152 
153  /// Returns a list of names that were rejected
155 
156  /// Reests the query registry
157  void ClearQueryRegistry() { query_registry.clear(); }
158 
159  //@{
160  /// Checks that no known element with valid response was left unqueried
161  bool CheckQueryRegistry() const { return DoCheckQueryRegistry(); }
162  bool CheckQueryRegistry(std::ostream& out) const
163  { return DoCheckQueryRegistry(&out); }
164  //@}
165 
166 
167  static Name_t const DefaultName; ///< name representing the default
168  static Name_t const ClearAllName; ///< name instructing to delete all names
169 
170  protected:
171 
172  /// A data structure containing how to react to a name
173  typedef struct {
174  Response_t response; ///< the response
175  } NameResponse_t;
176 
177  /// Information about known names
178  using KnownNames_t = std::map<Name_t, NameResponse_t>;
179 
180  /// Type of list of definitions
181  using Definitions_t = std::map<Name_t, KnownNames_t>;
182 
183  /// Type of query counters
184  using QueryRegistry_t = std::map<Name_t, size_t>;
185 
186  KnownNames_t known_names; ///< list of known names, with category
187 
188  Definitions_t definitions; ///< a set of definitions
189 
190  mutable QueryRegistry_t query_registry; ///< record of all the queries
191 
192  /// Returns the response for the specified name (does not register query)
194 
195  /**
196  * @brief Fills name_set with a list of items
197  * @tparam LIST type of container of name directives
198  * @param name_set set to be modified
199  * @param items name directives
200  *
201  * A name set is modified according to the instructions in each of the
202  * items. The items are parsed sequentially, and their order matters
203  * for the final result.
204  * Each item is processed through ProcessItem().
205  */
206  template <typename LIST>
207  void BuildNameSet(KnownNames_t& name_set, LIST const& items) const;
208 
209  /// Parses the first of the provided names, and recurs
210  template <typename... NAMES>
211  void AddFirstName
212  (KnownNames_t& name_set, Name_t name, NAMES... other_names);
213 
214  /// Adds an item to the name set, working in specified mode
215  void InsertItem
216  (KnownNames_t& name_set, Name_t item, Response_t response) const;
217 
218  /// Adds an item with response to the name set, working in specified mode
219  void InsertItem(
220  KnownNames_t& name_set, KnownNames_t::value_type item,
221  Response_t response
222  ) const;
223 
224  /**
225  * @brief Fills name_set with an item
226  * @param name_set set to be modified
227  * @param item name directive
228  *
229  * A name set is modified according to the instruction in the items.
230  * An identifier may represent either a single literal item or a set name;
231  * it can appear in two forms:
232  * - "\@identifier": always denotes a set named "identifier"
233  * - "identifier": if a set named "identifier" exists, the name
234  * represents that set; otherwise, it represents a literal item
235  * named "identifier"
236  *
237  * The directives in items are:
238  * - "identifier": the element or elements represented by the identifier
239  * replace the content of the current set
240  * - "+identifier": the element or elements represented by the identifier
241  * are added to the current set; if the identifier is a predefined set,
242  * the elements accepted in the set are added as accepted here, the ones
243  * rejected are added as rejected here
244  * - "-identifier": the element or elements represented by the identifier;
245  * if the identifier is a predefined set, the elements accepted in the
246  * set are added as rejected here, the ones rejected are added as
247  * accepted here
248  *
249  */
250  void ProcessItem(KnownNames_t& name_set, Name_t item) const;
251 
252  /// Strips set specifier and returns iterator to the definition, or end()
253  Definitions_t::const_iterator FindDefinition(Name_t& item) const;
254 
255  /// Erases all the names in the selector (default answer is unchanged)
256  void ClearNameSet(KnownNames_t& name_set) const;
257 
258  /// Returns the list of queried names whose response is answer
259  Names_t QueriedWithStatus(Response_t answer) const;
260 
261  // Performs the actual registry check, optionally printing a message
262  bool DoCheckQueryRegistry(std::ostream* out = nullptr) const;
263 
264  /// Strips the mode specifier from item and returns the insertion mode
265  static Response_t ParseMode
266  (Name_t& item, Response_t default_answer = rsAccepted);
267 
268  }; // class NameSelector
269 
270 } // namespace testing
271 
272 
273 //------------------------------------------------------------------------------
274 //--- Template implementation
275 //---
276 
277 // C/C++ standard library
278 #include <utility> // std::move()
279 
280 //------------------------------------------------------------------------------
281 template <typename LIST>
282 void testing::NameSelector::Define(std::string set_name, LIST const& items) {
283  KnownNames_t name_set;
284  BuildNameSet(name_set, items);
285  definitions[set_name] = std::move(name_set);
286 } // testing::NameSelector::Define()
287 
288 
289 //------------------------------------------------------------------------------
290 template <typename LIST>
292  (KnownNames_t& name_set, LIST const& items) const
293 {
294  for (Name_t item: items) ProcessItem(name_set, item);
295 } // testing::NameSelector::BuildNameSet()
296 
297 
298 //------------------------------------------------------------------------------
299 namespace testing {
300  // forward declaration of specialization
301  template <>
302  void NameSelector::AddFirstName<>(KnownNames_t& name_set, Name_t name);
303 } // namespace testing
304 
305 template <typename... NAMES>
307  (KnownNames_t& name_set, Name_t name, NAMES... other_names)
308 {
309  AddFirstName(name_set, name);
310  AddFirstName(name_set, other_names...);
311 } // testing::NameSelector::AddFirstName()
312 
313 
314 //------------------------------------------------------------------------------
315 
316 #endif // TEST_GEOMETRY_NAMESELECTOR_H
void Define(std::string set_name, LIST const &items)
Defines a set.
Definition: NameSelector.h:282
static Name_t const ClearAllName
name instructing to delete all names
Definition: NameSelector.h:168
std::set< Name_t > Names_t
list of names
Definition: NameSelector.h:41
bool DoCheckQueryRegistry(std::ostream *out=nullptr) const
static Response_t ParseMode(Name_t &item, Response_t default_answer=rsAccepted)
Strips the mode specifier from item and returns the insertion mode.
Definitions_t::const_iterator FindDefinition(Name_t &item) const
Strips set specifier and returns iterator to the definition, or end()
std::map< Name_t, NameResponse_t > KnownNames_t
Information about known names.
Definition: NameSelector.h:178
void AddToDefinition(std::string set_name, NAMES...names)
Parses a list of names and add them to the specified definition.
Definition: NameSelector.h:128
Response_t DefaultResponse() const
Returns the default answer for names that are not registered.
Definition: NameSelector.h:141
Names_t RejectedNames() const
Returns a list of names that were rejected.
Definition: NameSelector.h:154
void BuildNameSet(KnownNames_t &name_set, LIST const &items) const
Fills name_set with a list of items.
Definition: NameSelector.h:292
bool Accepted(Name_t name) const
Returns whether the name is accepted as good.
void ParseNames(NAMES...names)
Parses a list of names and adds them to the selector.
Definition: NameSelector.h:98
void PrintConfiguration(std::ostream &) const
Prints the configuration into a stream.
bool operator()(Name_t name) const
Returns whether the name is accepted as good (alias for accept())
Definition: NameSelector.h:145
Response_t LookupResponse(Name_t name) const
Returns the response for the specified name (does not register query)
void AddFirstName(KnownNames_t &name_set, Name_t name, NAMES...other_names)
Parses the first of the provided names, and recurs.
Definition: NameSelector.h:307
NameSelector(LIST const &items, Response_t default_answer=rsDefault)
Constructor: Parse()s the specified items.
Definition: NameSelector.h:61
void ParseName(Name_t name)
Parses a name and adds it to the selector.
Manages a set of names.
Definition: NameSelector.h:37
A data structure containing how to react to a name.
Definition: NameSelector.h:173
Definitions_t definitions
a set of definitions
Definition: NameSelector.h:188
bool Rejected(Name_t name) const
Returns whether the name is rejected as bad.
Definition: NameSelector.h:138
Names_t AcceptedNames() const
Returns a list of names that were accepted.
Definition: NameSelector.h:151
void ProcessItem(KnownNames_t &name_set, Name_t item) const
Fills name_set with an item.
NameSelector(Response_t default_answer=rsDefault)
Constructor: an empty selector with a default answer for unknown names.
Definition: NameSelector.h:56
Response_t
Possible responses.
Definition: NameSelector.h:44
std::initializer_list< Name_t > NameList
Definition: NameSelector.h:52
std::map< Name_t, KnownNames_t > Definitions_t
Type of list of definitions.
Definition: NameSelector.h:181
void Parse(LIST const &items)
Parses the names in the list and adds them to the selector.
Definition: NameSelector.h:78
std::map< Name_t, size_t > QueryRegistry_t
Type of query counters.
Definition: NameSelector.h:184
bool CheckQueryRegistry() const
Checks that no known element with valid response was left unqueried.
Definition: NameSelector.h:161
void ClearQueryRegistry()
Reests the query registry.
Definition: NameSelector.h:157
KnownNames_t known_names
list of known names, with category
Definition: NameSelector.h:186
static const std::vector< std::string > names
Response_t response
the response
Definition: NameSelector.h:174
static Name_t const DefaultName
name representing the default
Definition: NameSelector.h:167
Names_t QueriedWithStatus(Response_t answer) const
Returns the list of queried names whose response is answer.
void Clear()
Erases all the names in the selector (default answer is unchanged)
Definition: NameSelector.h:101
void ClearNameSet(KnownNames_t &name_set) const
Erases all the names in the selector (default answer is unchanged)
QueryRegistry_t query_registry
record of all the queries
Definition: NameSelector.h:190
throw art::Exception (art::errors::Configuration)
Definition: NameSelector.h:47
then echo fcl name
bool CheckQueryRegistry(std::ostream &out) const
Definition: NameSelector.h:162
void InsertItem(KnownNames_t &name_set, Name_t item, Response_t response) const
Adds an item to the name set, working in specified mode.
std::string Name_t
type representing a name
Definition: NameSelector.h:40
void SetDefaultResponse(Response_t default_answer)
Sets the default answer for names that are not registered.
Definition: NameSelector.h:66
Response_t Query(Name_t name) const
Returns the response for the specified name (does not throw)