LSST Applications  21.0.0+04719a4bac,21.0.0-1-ga51b5d4+f5e6047307,21.0.0-11-g2b59f77+a9c1acf22d,21.0.0-11-ga42c5b2+86977b0b17,21.0.0-12-gf4ce030+76814010d2,21.0.0-13-g1721dae+760e7a6536,21.0.0-13-g3a573fe+768d78a30a,21.0.0-15-g5a7caf0+f21cbc5713,21.0.0-16-g0fb55c1+b60e2d390c,21.0.0-19-g4cded4ca+71a93a33c0,21.0.0-2-g103fe59+bb20972958,21.0.0-2-g45278ab+04719a4bac,21.0.0-2-g5242d73+3ad5d60fb1,21.0.0-2-g7f82c8f+8babb168e8,21.0.0-2-g8f08a60+06509c8b61,21.0.0-2-g8faa9b5+616205b9df,21.0.0-2-ga326454+8babb168e8,21.0.0-2-gde069b7+5e4aea9c2f,21.0.0-2-gecfae73+1d3a86e577,21.0.0-2-gfc62afb+3ad5d60fb1,21.0.0-25-g1d57be3cd+e73869a214,21.0.0-3-g357aad2+ed88757d29,21.0.0-3-g4a4ce7f+3ad5d60fb1,21.0.0-3-g4be5c26+3ad5d60fb1,21.0.0-3-g65f322c+e0b24896a3,21.0.0-3-g7d9da8d+616205b9df,21.0.0-3-ge02ed75+a9c1acf22d,21.0.0-4-g591bb35+a9c1acf22d,21.0.0-4-g65b4814+b60e2d390c,21.0.0-4-gccdca77+0de219a2bc,21.0.0-4-ge8a399c+6c55c39e83,21.0.0-5-gd00fb1e+05fce91b99,21.0.0-6-gc675373+3ad5d60fb1,21.0.0-64-g1122c245+4fb2b8f86e,21.0.0-7-g04766d7+cd19d05db2,21.0.0-7-gdf92d54+04719a4bac,21.0.0-8-g5674e7b+d1bd76f71f,master-gac4afde19b+a9c1acf22d,w.2021.13
LSST Data Management Base Package
PropertySet.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more errors.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
26 
27 #include <algorithm>
28 #include <iomanip>
29 #include <sstream>
30 #include <stdexcept>
31 
33 #include "lsst/daf/base/DateTime.h"
34 
35 namespace lsst {
36 namespace daf {
37 namespace base {
38 
39 namespace {
40 
47 template <typename T>
48 void _append(std::vector<boost::any>& dest, std::vector<T> const& src) {
49  dest.reserve(dest.size() + src.size());
50  for (const T& val : src) {
51  dest.push_back(static_cast<T>(val));
52  }
53 }
54 
55 } // namespace
56 
57 PropertySet::PropertySet(bool flat) : _flat(flat) {}
58 
59 PropertySet::~PropertySet() noexcept = default;
60 
62 // Accessors
64 
65 PropertySet::Ptr PropertySet::deepCopy() const {
66  Ptr n(new PropertySet(_flat));
67  for (auto const& elt : _map) {
68  if (elt.second->back().type() == typeid(Ptr)) {
69  for (auto const& j : *elt.second) {
70  Ptr p = boost::any_cast<Ptr>(j);
71  if (p.get() == 0) {
72  n->add(elt.first, Ptr());
73  } else {
74  n->add(elt.first, p->deepCopy());
75  }
76  }
77  } else {
79  n->_map[elt.first] = vp;
80  }
81  }
82  return n;
83 }
84 
85 size_t PropertySet::nameCount(bool topLevelOnly) const {
86  int n = 0;
87  for (auto const& elt : _map) {
88  ++n;
89  if (!topLevelOnly && elt.second->back().type() == typeid(Ptr)) {
90  Ptr p = boost::any_cast<Ptr>(elt.second->back());
91  if (p.get() != 0) {
92  n += p->nameCount(false);
93  }
94  }
95  }
96  return n;
97 }
98 
99 std::vector<std::string> PropertySet::names(bool topLevelOnly) const {
101  for (auto const& elt : _map) {
102  v.push_back(elt.first);
103  if (!topLevelOnly && elt.second->back().type() == typeid(Ptr)) {
104  Ptr p = boost::any_cast<Ptr>(elt.second->back());
105  if (p.get() != 0) {
106  std::vector<std::string> w = p->names(false);
107  for (auto const& k : w) {
108  v.push_back(elt.first + "." + k);
109  }
110  }
111  }
112  }
113  return v;
114 }
115 
116 std::vector<std::string> PropertySet::paramNames(bool topLevelOnly) const {
118  for (auto const& elt : _map) {
119  if (elt.second->back().type() == typeid(Ptr)) {
120  Ptr p = boost::any_cast<Ptr>(elt.second->back());
121  if (p.get() != 0 && !topLevelOnly) {
122  std::vector<std::string> w = p->paramNames(false);
123  for (auto const& k : w) {
124  v.push_back(elt.first + "." + k);
125  }
126  }
127  } else {
128  v.push_back(elt.first);
129  }
130  }
131  return v;
132 }
133 
134 std::vector<std::string> PropertySet::propertySetNames(bool topLevelOnly) const {
136  for (auto const& elt : _map) {
137  if (elt.second->back().type() == typeid(Ptr)) {
138  v.push_back(elt.first);
139  Ptr p = boost::any_cast<Ptr>(elt.second->back());
140  if (p.get() != 0 && !topLevelOnly) {
141  std::vector<std::string> w = p->propertySetNames(false);
142  for (auto const& k : w) {
143  v.push_back(elt.first + "." + k);
144  }
145  }
146  }
147  }
148  return v;
149 }
150 
151 bool PropertySet::exists(std::string const& name) const { return _find(name) != _map.end(); }
152 
153 bool PropertySet::isArray(std::string const& name) const {
154  auto const i = _find(name);
155  return i != _map.end() && i->second->size() > 1U;
156 }
157 
158 bool PropertySet::isPropertySetPtr(std::string const& name) const {
159  auto const i = _find(name);
160  return i != _map.end() && i->second->back().type() == typeid(Ptr);
161 }
162 
163 bool PropertySet::isUndefined(std::string const& name) const {
164  auto const i = _find(name);
165  return i != _map.end() && i->second->back().type() == typeid(nullptr);
166 }
167 
168 size_t PropertySet::valueCount() const {
169  size_t sum = 0;
170  for (auto const& name : paramNames(false)) {
171  sum += valueCount(name);
172  }
173  return sum;
174 }
175 
176 size_t PropertySet::valueCount(std::string const& name) const {
177  auto const i = _find(name);
178  if (i == _map.end()) return 0;
179  return i->second->size();
180 }
181 
182 std::type_info const& PropertySet::typeOf(std::string const& name) const {
183  auto const i = _find(name);
184  if (i == _map.end()) {
185  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
186  }
187  return i->second->back().type();
188 }
189 
190 template <typename T>
191 std::type_info const& PropertySet::typeOfT() {
192  return typeid(T);
193 }
194 
195 // The following throw an exception if the type does not match exactly.
196 
197 template <typename T>
198 T PropertySet::get(std::string const& name)
199  const { /* parasoft-suppress LsstDm-3-4a LsstDm-4-6 "allow template over bool" */
200  auto const i = _find(name);
201  if (i == _map.end()) {
202  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
203  }
204  try {
205  return boost::any_cast<T>(i->second->back());
206  } catch (boost::bad_any_cast) {
207  throw LSST_EXCEPT(pex::exceptions::TypeError, name);
208  }
209  // not reached
210  return boost::any_cast<T>(i->second->back());
211 }
212 
213 template <typename T>
214 T PropertySet::get(std::string const& name, T const& defaultValue)
215  const { /* parasoft-suppress LsstDm-3-4a LsstDm-4-6 "allow template over bool" */
216  auto const i = _find(name);
217  if (i == _map.end()) {
218  return defaultValue;
219  }
220  try {
221  return boost::any_cast<T>(i->second->back());
222  } catch (boost::bad_any_cast) {
223  throw LSST_EXCEPT(pex::exceptions::TypeError, name);
224  }
225  // not reached
226  return boost::any_cast<T>(i->second->back());
227 }
228 
229 template <typename T>
230 std::vector<T> PropertySet::getArray(std::string const& name) const {
231  auto const i = _find(name);
232  if (i == _map.end()) {
233  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
234  }
235  std::vector<T> v;
236  for (auto const& j : *(i->second)) {
237  try {
238  v.push_back(boost::any_cast<T>(j));
239  } catch (boost::bad_any_cast) {
240  throw LSST_EXCEPT(pex::exceptions::TypeError, name);
241  }
242  }
243  return v;
244 }
245 
246 // The following throw an exception if the conversion is inappropriate.
247 
248 bool PropertySet::getAsBool(std::string const& name)
249  const { /* parasoft-suppress LsstDm-3-4a LsstDm-4-6 "for symmetry with other types" */
250  return get<bool>(name);
251 }
252 
253 int PropertySet::getAsInt(std::string const& name) const {
254  auto const i = _find(name);
255  if (i == _map.end()) {
256  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
257  }
258  boost::any v = i->second->back();
259  std::type_info const& t = v.type();
260  if (t == typeid(bool)) {
261  return boost::any_cast<bool>(v);
262  } else if (t == typeid(char)) {
263  return boost::any_cast<char>(v);
264  } else if (t == typeid(signed char)) {
265  return boost::any_cast<signed char>(v);
266  } else if (t == typeid(unsigned char)) {
267  return boost::any_cast<unsigned char>(v);
268  } else if (t == typeid(short)) {
269  return boost::any_cast<short>(v);
270  } else if (t == typeid(unsigned short)) {
271  return boost::any_cast<unsigned short>(v);
272  }
273  try {
274  return boost::any_cast<int>(v);
275  } catch (boost::bad_any_cast) {
276  throw LSST_EXCEPT(pex::exceptions::TypeError, name);
277  }
278  // not reached
279  return boost::any_cast<int>(v);
280 }
281 
282 int64_t PropertySet::getAsInt64(std::string const& name) const {
283  auto const i = _find(name);
284  if (i == _map.end()) {
285  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
286  }
287  boost::any v = i->second->back();
288  std::type_info const& t = v.type();
289  if (t == typeid(bool)) return boost::any_cast<bool>(v);
290  if (t == typeid(char)) return boost::any_cast<char>(v);
291  if (t == typeid(signed char)) return boost::any_cast<signed char>(v);
292  if (t == typeid(unsigned char)) return boost::any_cast<unsigned char>(v);
293  if (t == typeid(short)) return boost::any_cast<short>(v);
294  if (t == typeid(unsigned short)) return boost::any_cast<unsigned short>(v);
295  if (t == typeid(int)) return boost::any_cast<int>(v);
296  if (t == typeid(unsigned int)) return boost::any_cast<unsigned int>(v);
297  if (t == typeid(long)) return boost::any_cast<long>(v);
298  if (t == typeid(long long)) return boost::any_cast<long long>(v);
299  try {
300  return boost::any_cast<int64_t>(v);
301  } catch (boost::bad_any_cast) {
302  throw LSST_EXCEPT(pex::exceptions::TypeError, name);
303  }
304  // not reached
305  return boost::any_cast<int64_t>(v);
306 }
307 
308 uint64_t PropertySet::getAsUInt64(std::string const& name) const {
309  auto const i = _find(name);
310  if (i == _map.end()) {
311  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
312  }
313  boost::any v = i->second->back();
314  std::type_info const& t = v.type();
315  if (t == typeid(bool)) return boost::any_cast<bool>(v);
316  if (t == typeid(char)) return boost::any_cast<char>(v);
317  if (t == typeid(signed char)) return boost::any_cast<signed char>(v);
318  if (t == typeid(unsigned char)) return boost::any_cast<unsigned char>(v);
319  if (t == typeid(short)) return boost::any_cast<short>(v);
320  if (t == typeid(unsigned short)) return boost::any_cast<unsigned short>(v);
321  if (t == typeid(int)) return boost::any_cast<int>(v);
322  if (t == typeid(unsigned int)) return boost::any_cast<unsigned int>(v);
323  if (t == typeid(long)) return boost::any_cast<long>(v);
324  if (t == typeid(long long)) return boost::any_cast<long long>(v);
325  if (t == typeid(unsigned long long)) return boost::any_cast<unsigned long long>(v);
326  try {
327  return boost::any_cast<uint64_t>(v);
328  } catch (boost::bad_any_cast) {
329  throw LSST_EXCEPT(pex::exceptions::TypeError, name);
330  }
331  // not reached
332  return boost::any_cast<uint64_t>(v);
333 }
334 
335 double PropertySet::getAsDouble(std::string const& name) const {
336  auto const i = _find(name);
337  if (i == _map.end()) {
338  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
339  }
340  boost::any v = i->second->back();
341  std::type_info const& t = v.type();
342  if (t == typeid(bool)) return boost::any_cast<bool>(v);
343  if (t == typeid(char)) return boost::any_cast<char>(v);
344  if (t == typeid(signed char)) return boost::any_cast<signed char>(v);
345  if (t == typeid(unsigned char)) return boost::any_cast<unsigned char>(v);
346  if (t == typeid(short)) return boost::any_cast<short>(v);
347  if (t == typeid(unsigned short)) return boost::any_cast<unsigned short>(v);
348  if (t == typeid(int)) return boost::any_cast<int>(v);
349  if (t == typeid(unsigned int)) return boost::any_cast<unsigned int>(v);
350  if (t == typeid(long)) return boost::any_cast<long>(v);
351  if (t == typeid(unsigned long)) return boost::any_cast<unsigned long>(v);
352  if (t == typeid(long long)) return boost::any_cast<long long>(v);
353  if (t == typeid(unsigned long long)) return boost::any_cast<unsigned long long>(v);
354  if (t == typeid(float)) return boost::any_cast<float>(v);
355  try {
356  return boost::any_cast<double>(v);
357  } catch (boost::bad_any_cast) {
358  throw LSST_EXCEPT(pex::exceptions::TypeError, name);
359  }
360  // not reached
361  return boost::any_cast<double>(v);
362 }
363 
364 std::string PropertySet::getAsString(std::string const& name) const { return get<std::string>(name); }
365 
366 PropertySet::Ptr PropertySet::getAsPropertySetPtr(std::string const& name) const { return get<Ptr>(name); }
367 
368 Persistable::Ptr PropertySet::getAsPersistablePtr(std::string const& name) const {
369  return get<Persistable::Ptr>(name);
370 }
371 
372 std::string PropertySet::toString(bool topLevelOnly, std::string const& indent) const {
374  std::vector<std::string> nv = names();
375  sort(nv.begin(), nv.end());
376  for (auto const& i : nv) {
377  std::shared_ptr<std::vector<boost::any>> vp = _map.find(i)->second;
378  std::type_info const& t = vp->back().type();
379  if (t == typeid(Ptr)) {
380  s << indent << i << " = ";
381  if (topLevelOnly) {
382  s << "{ ... }";
383  } else {
384  Ptr p = boost::any_cast<Ptr>(vp->back());
385  if (p.get() == 0) {
386  s << "{ NULL }";
387  } else {
388  s << '{' << std::endl;
389  s << p->toString(false, indent + "..");
390  s << indent << '}';
391  }
392  }
393  s << std::endl;
394  } else {
395  s << indent << _format(i);
396  }
397  }
398  return s.str();
399 }
400 
401 std::string PropertySet::_format(std::string const& name) const {
403  s << std::showpoint; // Always show a decimal point for floats
404  auto const j = _map.find(name);
405  s << j->first << " = ";
407  if (vp->size() > 1) {
408  s << "[ ";
409  }
410  std::type_info const& t = vp->back().type();
411  bool isFirst = true;
412  for (auto const& k : *vp) {
413  if (isFirst) {
414  isFirst = false;
415  } else {
416  s << ", ";
417  }
418  boost::any const& v(k);
419  if (t == typeid(bool)) {
420  s << boost::any_cast<bool>(v);
421  } else if (t == typeid(char)) {
422  s << '\'' << boost::any_cast<char>(v) << '\'';
423  } else if (t == typeid(signed char)) {
424  s << '\'' << boost::any_cast<signed char>(v) << '\'';
425  } else if (t == typeid(unsigned char)) {
426  s << '\'' << boost::any_cast<unsigned char>(v) << '\'';
427  } else if (t == typeid(short)) {
428  s << boost::any_cast<short>(v);
429  } else if (t == typeid(unsigned short)) {
430  s << boost::any_cast<unsigned short>(v);
431  } else if (t == typeid(int)) {
432  s << boost::any_cast<int>(v);
433  } else if (t == typeid(unsigned int)) {
434  s << boost::any_cast<unsigned int>(v);
435  } else if (t == typeid(long)) {
436  s << boost::any_cast<long>(v);
437  } else if (t == typeid(unsigned long)) {
438  s << boost::any_cast<unsigned long>(v);
439  } else if (t == typeid(long long)) {
440  s << boost::any_cast<long long>(v);
441  } else if (t == typeid(unsigned long long)) {
442  s << boost::any_cast<unsigned long long>(v);
443  } else if (t == typeid(float)) {
444  s << std::setprecision(7) << boost::any_cast<float>(v);
445  } else if (t == typeid(double)) {
446  s << std::setprecision(14) << boost::any_cast<double>(v);
447  } else if (t == typeid(std::string)) {
448  s << '"' << boost::any_cast<std::string>(v) << '"';
449  } else if (t == typeid(DateTime)) {
450  s << boost::any_cast<DateTime>(v).toString(DateTime::UTC);
451  } else if (t == typeid(Ptr)) {
452  s << "{ ... }";
453  } else if (t == typeid(Persistable::Ptr)) {
454  s << "<Persistable>";
455  } else {
456  s << "<Unknown>";
457  }
458  }
459  if (j->second->size() > 1) {
460  s << " ]";
461  }
462  s << std::endl;
463  return s.str();
464 }
465 
467 // Modifiers
469 
470 template <typename T>
471 void PropertySet::set(std::string const& name, T const& value) {
473  vp->push_back(value);
474  _set(name, vp);
475 }
476 
477 template <typename T>
478 void PropertySet::set(std::string const& name, std::vector<T> const& value) {
479  if (value.empty()) return;
481  _append(*vp, value);
482  _set(name, vp);
483 }
484 
485 void PropertySet::set(std::string const& name, char const* value) { set(name, std::string(value)); }
486 
487 template <typename T>
488 void PropertySet::add(std::string const& name, T const& value) {
489  AnyMap::iterator i = _find(name);
490  if (i == _map.end()) {
491  set(name, value);
492  } else {
493  if (i->second->back().type() != typeid(T)) {
494  throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
495  }
496  i->second->push_back(value);
497  }
498 }
499 
500 // Specialize for Ptrs to check for cycles.
501 template <>
502 void PropertySet::add<PropertySet::Ptr>(std::string const& name, Ptr const& value) {
503  AnyMap::iterator i = _find(name);
504  if (i == _map.end()) {
505  set(name, value);
506  } else {
507  if (i->second->back().type() != typeid(Ptr)) {
508  throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
509  }
510  _cycleCheckPtr(value, name);
511  i->second->push_back(value);
512  }
513 }
514 
515 template <typename T>
516 void PropertySet::add(std::string const& name, std::vector<T> const& value) {
517  AnyMap::iterator i = _find(name);
518  if (i == _map.end()) {
519  set(name, value);
520  } else {
521  if (i->second->back().type() != typeid(T)) {
522  throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
523  }
524  _append(*(i->second), value);
525  }
526 }
527 
528 // Specialize for Ptrs to check for cycles.
529 template <>
530 void PropertySet::add<PropertySet::Ptr>(std::string const& name, std::vector<Ptr> const& value) {
531  AnyMap::iterator i = _find(name);
532  if (i == _map.end()) {
533  set(name, value);
534  } else {
535  if (i->second->back().type() != typeid(Ptr)) {
536  throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
537  }
538  _cycleCheckPtrVec(value, name);
539  _append(*(i->second), value);
540  }
541 }
542 
543 void PropertySet::add(std::string const& name, char const* value) { add(name, std::string(value)); }
544 
545 void PropertySet::copy(std::string const& dest, ConstPtr source, std::string const& name, bool asScalar) {
546  if (source.get() == 0) {
547  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Missing source");
548  }
549  auto const sj = source->_find(name);
550  if (sj == source->_map.end()) {
551  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, name + " not in source");
552  }
553  remove(dest);
554  if (asScalar) {
555  auto vp = std::make_shared<std::vector<boost::any>>();
556  vp->push_back(sj->second->back());
557  _set(dest, vp);
558  } else {
559  auto vp = std::make_shared<std::vector<boost::any>>(*(sj->second));
560  _set(dest, vp);
561  }
562 }
563 
564 void PropertySet::combine(ConstPtr source) {
565  if (source.get() == 0) {
566  return;
567  }
568  std::vector<std::string> names = source->paramNames(false);
569  for (auto const& name : names) {
570  auto const sp = source->_find(name);
571  _add(name, sp->second);
572  }
573 }
574 
575 void PropertySet::remove(std::string const& name) {
576  std::string::size_type i = name.find('.');
577  if (_flat || i == name.npos) {
578  _map.erase(name);
579  return;
580  }
581  std::string prefix(name, 0, i);
582  AnyMap::iterator j = _map.find(prefix);
583  if (j == _map.end() || j->second->back().type() != typeid(Ptr)) {
584  return;
585  }
586  Ptr p = boost::any_cast<Ptr>(j->second->back());
587  if (p.get() != 0) {
588  std::string suffix(name, i + 1);
589  p->remove(suffix);
590  }
591 }
592 
594 // Private member functions
596 
597 PropertySet::AnyMap::iterator PropertySet::_find(std::string const& name) {
598  std::string::size_type i = name.find('.');
599  if (_flat || i == name.npos) {
600  return _map.find(name);
601  }
602  std::string prefix(name, 0, i);
603  AnyMap::iterator j = _map.find(prefix);
604  if (j == _map.end() || j->second->back().type() != typeid(Ptr)) {
605  return _map.end();
606  }
607  Ptr p = boost::any_cast<Ptr>(j->second->back());
608  if (p.get() == 0) {
609  return _map.end();
610  }
611  std::string suffix(name, i + 1);
612  AnyMap::iterator x = p->_find(suffix);
613  if (x == p->_map.end()) {
614  return _map.end();
615  }
616  return x;
617 }
618 
619 PropertySet::AnyMap::const_iterator PropertySet::_find(std::string const& name) const {
620  std::string::size_type i = name.find('.');
621  if (_flat || i == name.npos) {
622  return _map.find(name);
623  }
624  std::string prefix(name, 0, i);
625  auto const j = _map.find(prefix);
626  if (j == _map.end() || j->second->back().type() != typeid(Ptr)) {
627  return _map.end();
628  }
629  Ptr p = boost::any_cast<Ptr>(j->second->back());
630  if (p.get() == 0) {
631  return _map.end();
632  }
633  std::string suffix(name, i + 1);
634  auto const x = p->_find(suffix);
635  if (x == p->_map.end()) {
636  return _map.end();
637  }
638  return x;
639 }
640 
641 void PropertySet::_set(std::string const& name, std::shared_ptr<std::vector<boost::any>> vp) {
642  _findOrInsert(name, vp);
643 }
644 
645 void PropertySet::_add(std::string const& name, std::shared_ptr<std::vector<boost::any>> vp) {
646  auto const dp = _find(name);
647  if (dp == _map.end()) {
648  _set(name, vp);
649  } else {
650  if (vp->back().type() != dp->second->back().type()) {
651  throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
652  }
653  // Check for cycles
654  if (vp->back().type() == typeid(Ptr)) {
655  _cycleCheckAnyVec(*vp, name);
656  }
657  _append(*(dp->second), *vp);
658  }
659 }
660 
661 void PropertySet::_findOrInsert(std::string const& name, std::shared_ptr<std::vector<boost::any>> vp) {
662  if (vp->back().type() == typeid(Ptr)) {
663  if (_flat) {
664  Ptr source = boost::any_cast<Ptr>(vp->back());
665  std::vector<std::string> names = source->paramNames(false);
666  for (auto const& i : names) {
667  auto const sp = source->_find(i);
668  _add(name + "." + i, sp->second);
669  }
670  return;
671  }
672 
673  // Check for cycles
674  _cycleCheckAnyVec(*vp, name);
675  }
676 
677  std::string::size_type i = name.find('.');
678  if (_flat || i == name.npos) {
679  _map[name] = vp;
680  return;
681  }
682  std::string prefix(name, 0, i);
683  std::string suffix(name, i + 1);
684  AnyMap::iterator j = _map.find(prefix);
685  if (j == _map.end()) {
686  PropertySet::Ptr pp(new PropertySet);
687  pp->_findOrInsert(suffix, vp);
689  temp->push_back(pp);
690  _map[prefix] = temp;
691  return;
692  } else if (j->second->back().type() != typeid(Ptr)) {
693  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
694  prefix + " exists but does not contain PropertySet::Ptrs");
695  }
696  Ptr p = boost::any_cast<Ptr>(j->second->back());
697  if (p.get() == 0) {
698  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
699  prefix + " exists but contains null PropertySet::Ptr");
700  }
701  p->_findOrInsert(suffix, vp);
702 }
703 
704 void PropertySet::_cycleCheckPtrVec(std::vector<Ptr> const& v, std::string const& name) {
705  for (auto const& i : v) {
706  _cycleCheckPtr(i, name);
707  }
708 }
709 
710 void PropertySet::_cycleCheckAnyVec(std::vector<boost::any> const& v, std::string const& name) {
711  for (auto const& i : v) {
712  _cycleCheckPtr(boost::any_cast<Ptr>(i), name);
713  }
714 }
715 
716 void PropertySet::_cycleCheckPtr(Ptr const& v, std::string const& name) {
717  if (v.get() == this) {
718  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, name + " would cause a cycle");
719  }
720  std::vector<std::string> sets = v->propertySetNames(false);
721  for (auto const& i : sets) {
722  if (v->getAsPropertySetPtr(i).get() == this) {
723  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, name + " would cause a cycle");
724  }
725  }
726 }
727 
729  // Explicit template instantiations
731 
733  // Explicit template instantiations are not well understood by doxygen.
734 
735 #define INSTANTIATE(t) \
736  template std::type_info const& PropertySet::typeOfT<t>(); \
737  template t PropertySet::get<t>(std::string const& name) const; \
738  template t PropertySet::get<t>(std::string const& name, t const& defaultValue) const; \
739  template std::vector<t> PropertySet::getArray<t>(std::string const& name) const; \
740  template void PropertySet::set<t>(std::string const& name, t const& value); \
741  template void PropertySet::set<t>(std::string const& name, std::vector<t> const& value); \
742  template void PropertySet::add<t>(std::string const& name, t const& value); \
743  template void PropertySet::add<t>(std::string const& name, std::vector<t> const& value);
744 
745 #define INSTANTIATE_PROPERTY_SET(t) \
746  template std::type_info const& PropertySet::typeOfT<t>(); \
747  template t PropertySet::get<t>(std::string const& name) const; \
748  template t PropertySet::get<t>(std::string const& name, t const& defaultValue) const; \
749  template std::vector<t> PropertySet::getArray<t>(std::string const& name) const; \
750  template void PropertySet::set<t>(std::string const& name, t const& value); \
751  template void PropertySet::set<t>(std::string const& name, std::vector<t> const& value);
752 
753 INSTANTIATE(bool)
754 INSTANTIATE(char)
755 INSTANTIATE(signed char)
756 INSTANTIATE(unsigned char)
757 INSTANTIATE(short)
758 INSTANTIATE(unsigned short)
759 INSTANTIATE(int)
760 INSTANTIATE(unsigned int)
761 INSTANTIATE(long)
762 INSTANTIATE(unsigned long)
763 INSTANTIATE(long long)
764 INSTANTIATE(unsigned long long)
765 INSTANTIATE(float)
766 INSTANTIATE(double)
769 INSTANTIATE_PROPERTY_SET(PropertySet::Ptr)
770 INSTANTIATE(Persistable::Ptr)
771 INSTANTIATE(DateTime)
772 
773 } // namespace base
774 } // namespace daf
775 } // namespace lsst
776 
table::Key< std::string > name
Definition: Amplifier.cc:116
double x
Interface for DateTime class.
#define INSTANTIATE(FROMSYS, TOSYS)
Definition: Detector.cc:484
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
std::shared_ptr< RecordT > src
Definition: Match.cc:48
std::string prefix
Definition: SchemaMapper.cc:79
T back(T... args)
T begin(T... args)
PropertySet(bool flat=false)
Construct an empty PropertySet.
T empty(T... args)
T end(T... args)
T endl(T... args)
daf::base::PropertySet * set
Definition: fits.cc:912
const char * source()
Source function that allows astChannel to source from a Stream.
Definition: Stream.h:224
bool any(CoordinateExpr< N > const &expr) noexcept
Return true if any elements are true.
A base class for image defects.
T push_back(T... args)
T remove(T... args)
T reserve(T... args)
T showpoint(T... args)
T size(T... args)
T sort(T... args)
double w
Definition: CoaddPsf.cc:69
ImageT val
Definition: CR.cc:146
T str(T... args)