LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
intermediate_table.cc
Go to the documentation of this file.
1 // ======================================================================
2 //
3 // intermediate_table
4 //
5 // ======================================================================
6 
8 
9 #include "boost/algorithm/string.hpp"
10 #include "fhiclcpp/Protection.h"
11 #include "fhiclcpp/exception.h"
13 #include "fhiclcpp/stdmap_shims.h"
14 
15 #include <cctype>
16 #include <cstdlib>
17 #include <utility>
18 
19 using namespace std::string_literals;
20 using namespace fhicl;
21 
26 
29 
30 // ----------------------------------------------------------------------
31 namespace {
32  extended_value const&
33  nil_item()
34  {
35  static extended_value const nil_item{false, NIL, "@nil"s};
36  return nil_item;
37  }
38 
39  extended_value const&
40  empty_seq()
41  {
42  static extended_value const empty_seq{false, SEQUENCE, sequence_t{}};
43  return empty_seq;
44  }
45 
46  extended_value const&
47  empty_tbl()
48  {
49  static extended_value const empty_tbl{false, TABLE, table_t{}};
50  return empty_tbl;
51  }
52 }
53 
54 // ----------------------------------------------------------------------
55 
58 {
59  return std::any_cast<table_t const&>(ex_val.value).begin();
60 }
61 
64 {
65  return std::any_cast<table_t const&>(ex_val.value).end();
66 }
67 
68 // ----------------------------------------------------------------------
69 
70 bool
72 {
73  return std::any_cast<table_t const&>(ex_val.value).empty();
74 }
75 
76 // ----------------------------------------------------------------------
77 
78 bool
79 intermediate_table::insert(std::string const& key,
80  bool const in_prolog,
81  value_tag const tag,
82  std::any const& value)
83 {
84  return insert(key, extended_value(in_prolog, tag, value));
85 }
86 
87 bool
88 intermediate_table::insert(std::string const& key, extended_value const& value)
89 {
90  auto found_val = pre_insert_(key, value);
91  bool result = (found_val != nullptr);
92  if (result) {
93  *found_val = value;
94  }
95  return result;
96 }
97 
98 bool
99 intermediate_table::insert(std::string const& key, extended_value&& value)
100 {
101  auto found_val = pre_insert_(key, value);
102  bool result = (found_val != nullptr);
103  if (result) {
104  *found_val = std::move(value);
105  }
106  return result;
107 }
108 
109 // ----------------------------------------------------------------------
110 
111 extended_value const&
112 intermediate_table::find(std::string const& key) const
113 {
114  extended_value const* p = &ex_val;
115  for (auto const& name : split(key)) {
116  if (name.empty()) {
117  } else if (std::isdigit(name[0])) {
118  if (!p->is_a(SEQUENCE))
119  throw exception(cant_find, key)
120  << "-- not a sequence (at part \"" << name << "\")";
121  auto const& s = std::any_cast<sequence_t const&>(p->value);
122  unsigned i = std::atoi(name.c_str());
123  if (s.size() <= i)
124  throw exception(cant_find, key) << "(at part \"" << name << "\")";
125  p = &s[i];
126  } else { /* name[0] is alpha or '_' */
127  if (!p->is_a(TABLE))
128  throw exception(cant_find, key)
129  << "-- not a table (at part \"" << name << "\")";
130  auto const& t = std::any_cast<table_t const&>(p->value);
131  auto it = t.find(name);
132  if (it == t.end())
133  throw exception(cant_find, key) << "(at part \"" << name << "\")";
134  p = &it->second;
135  }
136  } // for
137  return *p;
138 } // find()
139 
140 // ----------------------------------------------------------------------
141 
142 bool
143 intermediate_table::exists(std::string const& key) const
144 {
145  extended_value const* p = &ex_val;
146  for (auto const& name : split(key)) {
147  if (name.empty()) {
148  } else if (std::isdigit(name[0])) {
149  if (!p->is_a(SEQUENCE)) {
150  return false;
151  }
152  auto const& s = std::any_cast<sequence_t const&>(p->value);
153  unsigned i = std::atoi(name.c_str());
154  if (s.size() <= i) {
155  return false;
156  }
157  p = &s[i];
158  } else { /* name[0] is alpha or '_' */
159  if (!p->is_a(TABLE)) {
160  return false;
161  }
162  auto const& t = std::any_cast<table_t const&>(p->value);
163  auto it = t.find(name);
164  if (it == t.end()) {
165  return false;
166  }
167  p = &it->second;
168  }
169  } // for
170  return true;
171 } // exists()
172 
173 void
174 intermediate_table::erase(std::string const& key, bool const in_prolog)
175 {
176  // A missing part of the "a.b.c.d" chain will not cause an error; it
177  // is an error for an intermediate link in the chain *not* to be a
178  // table.
179  auto p(&ex_val);
180  auto t(std::any_cast<table_t>(&p->value));
181  auto it(t->end());
182  auto const names = split(key);
183  if ((!in_prolog) &&
184  (((it = t->find(names[0])) == t->end()) || it->second.in_prolog)) {
185  return;
186  }
187  bool at_sequence(false);
188  for (auto const& name : names) {
189  if (name.empty()) {
190  } else if (std::isdigit(name[0])) {
191  if (!p->is_a(SEQUENCE))
192  throw exception(cant_find, name)
193  << "-- not a sequence (at part \"" << name << "\")";
194  auto& s = std::any_cast<sequence_t&>(p->value);
195  unsigned i = std::atoi(name.c_str());
196  if (s.size() <= i) {
197  return;
198  }
199  p = &s[i];
200  at_sequence = true;
201  } else { /* name[0] is alpha or '_' */
202  if (!p->is_a(TABLE))
203  throw exception(cant_find, name)
204  << "-- not a table (at part \"" << name << "\")";
205  at_sequence = false;
206  t = std::any_cast<table_t>(&p->value);
207  it = t->find(name);
208  if (it == t->end()) {
209  return;
210  }
211  p = &it->second;
212  auto prot = p->protection;
213  if (prot == Protection::PROTECT_ERROR) {
215  << ((name != key) ? (std::string("Part \"") + name +
216  "\" of specification to be erased\n") :
217  "")
218  << '"' << name << "\" is protected on " << p->pretty_src_info()
219  << '\n';
220  } else if (prot == Protection::PROTECT_IGNORE) {
221  return;
222  }
223  }
224  } // for
225  if (at_sequence) {
226  throw fhicl::exception(unimplemented, "erase sequence member");
227  }
228  if (it != t->end()) {
229  t->erase(it);
230  }
231 }
232 
234 intermediate_table::pre_insert_(std::string const& key,
235  extended_value const& value)
236 {
237  if (!value.in_prolog) {
238  auto& t = std::any_cast<table_t&>(ex_val.value);
239  auto const names = split(key);
240  auto it = t.find(names[0]);
241  if (it != t.end() && it->second.in_prolog) {
242  t.erase(it);
243  }
244  }
245  auto located = locate_(key, value.in_prolog);
246  if ((!located.first->is_a(NIL)) &&
247  value.protection > located.first->protection) {
249  << '"' << key << "\" cannot be assigned with increased protection"
250  << "\n(previous definition on " << located.first->pretty_src_info()
251  << ")\n";
252  }
253  return located.second ? located.first : nullptr;
254 }
255 
256 std::pair<extended_value*, bool>
257 intermediate_table::locate_(std::string const& key, bool const in_prolog)
258 {
259  std::pair<extended_value*, bool> result(nullptr, true);
260  extended_value*& p = result.first;
261  p = &ex_val;
262  for (auto const& name : split(key)) {
263  if (name.empty()) {
264  } else if (std::isdigit(name[0])) {
265  if (p->is_a(NIL)) {
266  *p = empty_seq();
267  }
268  if (!p->is_a(SEQUENCE))
269  throw exception(cant_find, name)
270  << "-- not a sequence (at part \"" << name << "\")";
271  auto& s = std::any_cast<sequence_t&>(p->value);
272  unsigned i = std::atoi(name.c_str());
273  while (s.size() <= i) {
274  s.push_back(nil_item());
275  }
276  p->set_prolog(in_prolog);
277  p = &s[i];
278  } else { /* name[0] is alpha or '_' */
279  if (p->is_a(NIL)) {
280  *p = empty_tbl();
281  p->set_prolog(in_prolog);
282  }
283  if (!p->is_a(TABLE))
284  throw exception(cant_find, name)
285  << "-- not a table (at part \"" << name << "\")";
286  auto& t = std::any_cast<table_t&>(p->value);
287  // This will do what we need whether the key is already in the
288  // map or not.
289  p = &t.emplace(name, nil_item()).first->second;
290  p->set_prolog(in_prolog);
291  }
292 
293  auto prot = p->protection;
294  if (prot == Protection::PROTECT_ERROR) {
296  << ((name != key) ? (std::string("Part \"") + name +
297  "\" of specification to be overwritten\n") :
298  "")
299  << '"' << key << "\" is protected on " << p->pretty_src_info() << '\n';
300  } else if (prot == Protection::PROTECT_IGNORE) {
301  result.second = false;
302  // Keep going since we might need definition location
303  // information for specified item upstream.
304  }
305  } // for
306  return result;
307 } // locate_()
308 
309 std::vector<std::string>
310 intermediate_table::split(std::string const& key)
311 {
312  static std::string const splitChars{shims::isSnippetMode() ? "[]" : ".[]"};
313  std::vector<std::string> result;
314  boost::algorithm::split(result, key, boost::algorithm::is_any_of(splitChars));
315  return result;
316 }
317 
318 // ======================================================================
intermediate_table::table_t table_t
intermediate_table::iterator iterator
intermediate_table::complex_t complex_t
bool is_a(value_tag const t) const noexcept
intermediate_table::const_iterator const_iterator
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
intermediate_table::complex_t complex_t
parameter set interface
extended_value::sequence_t sequence_t
intermediate_table::atom_t atom_t
double value
Definition: spectrum.C:18
intermediate_table::sequence_t sequence_t
fhicl::extended_value::sequence_t sequence_t
intermediate_table::atom_t atom_t
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
std::string pretty_src_info() const
bool isSnippetMode(bool m=false) noexcept
void set_prolog(bool new_prolog_state)
iterator find(Key const &key)
Definition: stdmap_shims.h:236
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:109