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