LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
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 #include <any>
32 
34 #include "lsst/daf/base/DateTime.h"
35 
36 namespace lsst {
37 namespace daf {
38 namespace base {
39 
40 namespace {
41 
48 template <typename T>
49 void _append(std::vector<std::any>& dest, std::vector<T> const& src) {
50  dest.reserve(dest.size() + src.size());
51  for (const T& val : src) {
52  dest.push_back(static_cast<T>(val));
53  }
54 }
55 
56 } // namespace
57 
58 PropertySet::PropertySet(bool flat) : _flat(flat) {}
59 
60 PropertySet::~PropertySet() noexcept = default;
61 
63 // Accessors
65 
66 PropertySet::Ptr PropertySet::deepCopy() const {
67  Ptr n(new PropertySet(_flat));
68  for (auto const& elt : _map) {
69  if (elt.second->back().type() == typeid(Ptr)) {
70  for (auto const& j : *elt.second) {
71  Ptr p = std::any_cast<Ptr>(j);
72  if (p.get() == 0) {
73  n->add(elt.first, Ptr());
74  } else {
75  n->add(elt.first, p->deepCopy());
76  }
77  }
78  } else {
80  n->_map[elt.first] = vp;
81  }
82  }
83  return n;
84 }
85 
86 size_t PropertySet::nameCount(bool topLevelOnly) const {
87  int n = 0;
88  for (auto const& elt : _map) {
89  ++n;
90  if (!topLevelOnly && elt.second->back().type() == typeid(Ptr)) {
91  Ptr p = std::any_cast<Ptr>(elt.second->back());
92  if (p.get() != 0) {
93  n += p->nameCount(false);
94  }
95  }
96  }
97  return n;
98 }
99 
100 std::vector<std::string> PropertySet::names(bool topLevelOnly) const {
102  for (auto const& elt : _map) {
103  v.push_back(elt.first);
104  if (!topLevelOnly && elt.second->back().type() == typeid(Ptr)) {
105  Ptr p = std::any_cast<Ptr>(elt.second->back());
106  if (p.get() != 0) {
107  std::vector<std::string> w = p->names(false);
108  for (auto const& k : w) {
109  v.push_back(elt.first + "." + k);
110  }
111  }
112  }
113  }
114  return v;
115 }
116 
117 std::vector<std::string> PropertySet::paramNames(bool topLevelOnly) const {
119  for (auto const& elt : _map) {
120  if (elt.second->back().type() == typeid(Ptr)) {
121  Ptr p = std::any_cast<Ptr>(elt.second->back());
122  if (p.get() != 0 && !topLevelOnly) {
123  std::vector<std::string> w = p->paramNames(false);
124  for (auto const& k : w) {
125  v.push_back(elt.first + "." + k);
126  }
127  }
128  } else {
129  v.push_back(elt.first);
130  }
131  }
132  return v;
133 }
134 
135 std::vector<std::string> PropertySet::propertySetNames(bool topLevelOnly) const {
137  for (auto const& elt : _map) {
138  if (elt.second->back().type() == typeid(Ptr)) {
139  v.push_back(elt.first);
140  Ptr p = std::any_cast<Ptr>(elt.second->back());
141  if (p.get() != 0 && !topLevelOnly) {
142  std::vector<std::string> w = p->propertySetNames(false);
143  for (auto const& k : w) {
144  v.push_back(elt.first + "." + k);
145  }
146  }
147  }
148  }
149  return v;
150 }
151 
152 bool PropertySet::exists(std::string const& name) const { return _find(name) != _map.end(); }
153 
154 bool PropertySet::isArray(std::string const& name) const {
155  auto const i = _find(name);
156  return i != _map.end() && i->second->size() > 1U;
157 }
158 
159 bool PropertySet::isPropertySetPtr(std::string const& name) const {
160  auto const i = _find(name);
161  return i != _map.end() && i->second->back().type() == typeid(Ptr);
162 }
163 
164 bool PropertySet::isUndefined(std::string const& name) const {
165  auto const i = _find(name);
166  return i != _map.end() && i->second->back().type() == typeid(nullptr);
167 }
168 
169 size_t PropertySet::valueCount() const {
170  size_t sum = 0;
171  for (auto const& name : paramNames(false)) {
172  sum += valueCount(name);
173  }
174  return sum;
175 }
176 
177 size_t PropertySet::valueCount(std::string const& name) const {
178  auto const i = _find(name);
179  if (i == _map.end()) return 0;
180  return i->second->size();
181 }
182 
183 std::type_info const& PropertySet::typeOf(std::string const& name) const {
184  auto const i = _find(name);
185  if (i == _map.end()) {
186  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
187  }
188  return i->second->back().type();
189 }
190 
191 template <typename T>
192 std::type_info const& PropertySet::typeOfT() {
193  return typeid(T);
194 }
195 
196 // The following throw an exception if the type does not match exactly.
197 
198 template <typename T>
199 T PropertySet::get(std::string const& name)
200  const { /* parasoft-suppress LsstDm-3-4a LsstDm-4-6 "allow template over bool" */
201  auto const i = _find(name);
202  if (i == _map.end()) {
203  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
204  }
205  try {
206  return std::any_cast<T>(i->second->back());
207  } catch (std::bad_any_cast &) {
208  std::throw_with_nested(LSST_EXCEPT(pex::exceptions::TypeError, name));
209  }
210  // not reached
211  return std::any_cast<T>(i->second->back());
212 }
213 
214 template <typename T>
215 T PropertySet::get(std::string const& name, T const& defaultValue)
216  const { /* parasoft-suppress LsstDm-3-4a LsstDm-4-6 "allow template over bool" */
217  auto const i = _find(name);
218  if (i == _map.end()) {
219  return defaultValue;
220  }
221  try {
222  return std::any_cast<T>(i->second->back());
223  } catch (std::bad_any_cast &) {
224  std::throw_with_nested(LSST_EXCEPT(pex::exceptions::TypeError, name));
225  }
226  // not reached
227  return std::any_cast<T>(i->second->back());
228 }
229 
230 template <typename T>
231 std::vector<T> PropertySet::getArray(std::string const& name) const {
232  auto const i = _find(name);
233  if (i == _map.end()) {
234  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
235  }
236  std::vector<T> v;
237  for (auto const& j : *(i->second)) {
238  try {
239  v.push_back(std::any_cast<T>(j));
240  } catch (std::bad_any_cast &) {
241  std::throw_with_nested(LSST_EXCEPT(pex::exceptions::TypeError, name));
242  }
243  }
244  return v;
245 }
246 
247 // The following throw an exception if the conversion is inappropriate.
248 
249 bool PropertySet::getAsBool(std::string const& name)
250  const { /* parasoft-suppress LsstDm-3-4a LsstDm-4-6 "for symmetry with other types" */
251  return get<bool>(name);
252 }
253 
254 int PropertySet::getAsInt(std::string const& name) const {
255  auto const i = _find(name);
256  if (i == _map.end()) {
257  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
258  }
259  std::any v = i->second->back();
260  std::type_info const& t = v.type();
261  if (t == typeid(bool)) {
262  return std::any_cast<bool>(v);
263  } else if (t == typeid(char)) {
264  return std::any_cast<char>(v);
265  } else if (t == typeid(signed char)) {
266  return std::any_cast<signed char>(v);
267  } else if (t == typeid(unsigned char)) {
268  return std::any_cast<unsigned char>(v);
269  } else if (t == typeid(short)) {
270  return std::any_cast<short>(v);
271  } else if (t == typeid(unsigned short)) {
272  return std::any_cast<unsigned short>(v);
273  }
274  try {
275  return std::any_cast<int>(v);
276  } catch (std::bad_any_cast &) {
277  std::throw_with_nested(LSST_EXCEPT(pex::exceptions::TypeError, name));
278  }
279  // not reached
280  return std::any_cast<int>(v);
281 }
282 
283 int64_t PropertySet::getAsInt64(std::string const& name) const {
284  auto const i = _find(name);
285  if (i == _map.end()) {
286  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
287  }
288  std::any v = i->second->back();
289  std::type_info const& t = v.type();
290  if (t == typeid(bool)) return std::any_cast<bool>(v);
291  if (t == typeid(char)) return std::any_cast<char>(v);
292  if (t == typeid(signed char)) return std::any_cast<signed char>(v);
293  if (t == typeid(unsigned char)) return std::any_cast<unsigned char>(v);
294  if (t == typeid(short)) return std::any_cast<short>(v);
295  if (t == typeid(unsigned short)) return std::any_cast<unsigned short>(v);
296  if (t == typeid(int)) return std::any_cast<int>(v);
297  if (t == typeid(unsigned int)) return std::any_cast<unsigned int>(v);
298  if (t == typeid(long)) return std::any_cast<long>(v);
299  if (t == typeid(long long)) return std::any_cast<long long>(v);
300  try {
301  return std::any_cast<int64_t>(v);
302  } catch (std::bad_any_cast &) {
303  std::throw_with_nested(LSST_EXCEPT(pex::exceptions::TypeError, name));
304  }
305  // not reached
306  return std::any_cast<int64_t>(v);
307 }
308 
309 uint64_t PropertySet::getAsUInt64(std::string const& name) const {
310  auto const i = _find(name);
311  if (i == _map.end()) {
312  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
313  }
314  std::any v = i->second->back();
315  std::type_info const& t = v.type();
316  if (t == typeid(bool)) return std::any_cast<bool>(v);
317  if (t == typeid(char)) return std::any_cast<char>(v);
318  if (t == typeid(signed char)) return std::any_cast<signed char>(v);
319  if (t == typeid(unsigned char)) return std::any_cast<unsigned char>(v);
320  if (t == typeid(short)) return std::any_cast<short>(v);
321  if (t == typeid(unsigned short)) return std::any_cast<unsigned short>(v);
322  if (t == typeid(int)) return std::any_cast<int>(v);
323  if (t == typeid(unsigned int)) return std::any_cast<unsigned int>(v);
324  if (t == typeid(long)) return std::any_cast<long>(v);
325  if (t == typeid(long long)) return std::any_cast<long long>(v);
326  if (t == typeid(unsigned long long)) return std::any_cast<unsigned long long>(v);
327  try {
328  return std::any_cast<uint64_t>(v);
329  } catch (std::bad_any_cast &) {
330  std::throw_with_nested(LSST_EXCEPT(pex::exceptions::TypeError, name));
331  }
332  // not reached
333  return std::any_cast<uint64_t>(v);
334 }
335 
336 double PropertySet::getAsDouble(std::string const& name) const {
337  auto const i = _find(name);
338  if (i == _map.end()) {
339  throw LSST_EXCEPT(pex::exceptions::NotFoundError, name + " not found");
340  }
341  std::any v = i->second->back();
342  std::type_info const& t = v.type();
343  if (t == typeid(bool)) return std::any_cast<bool>(v);
344  if (t == typeid(char)) return std::any_cast<char>(v);
345  if (t == typeid(signed char)) return std::any_cast<signed char>(v);
346  if (t == typeid(unsigned char)) return std::any_cast<unsigned char>(v);
347  if (t == typeid(short)) return std::any_cast<short>(v);
348  if (t == typeid(unsigned short)) return std::any_cast<unsigned short>(v);
349  if (t == typeid(int)) return std::any_cast<int>(v);
350  if (t == typeid(unsigned int)) return std::any_cast<unsigned int>(v);
351  if (t == typeid(long)) return std::any_cast<long>(v);
352  if (t == typeid(unsigned long)) return std::any_cast<unsigned long>(v);
353  if (t == typeid(long long)) return std::any_cast<long long>(v);
354  if (t == typeid(unsigned long long)) return std::any_cast<unsigned long long>(v);
355  if (t == typeid(float)) return std::any_cast<float>(v);
356  try {
357  return std::any_cast<double>(v);
358  } catch (std::bad_any_cast &) {
359  std::throw_with_nested(LSST_EXCEPT(pex::exceptions::TypeError, name));
360  }
361  // not reached
362  return std::any_cast<double>(v);
363 }
364 
365 std::string PropertySet::getAsString(std::string const& name) const { return get<std::string>(name); }
366 
367 PropertySet::Ptr PropertySet::getAsPropertySetPtr(std::string const& name) const { return get<Ptr>(name); }
368 
369 Persistable::Ptr PropertySet::getAsPersistablePtr(std::string const& name) const {
370  return get<Persistable::Ptr>(name);
371 }
372 
373 std::string PropertySet::toString(bool topLevelOnly, std::string const& indent) const {
375  std::vector<std::string> nv = names();
376  sort(nv.begin(), nv.end());
377  for (auto const& i : nv) {
378  std::shared_ptr<std::vector<std::any>> vp = _map.find(i)->second;
379  std::type_info const& t = vp->back().type();
380  if (t == typeid(Ptr)) {
381  s << indent << i << " = ";
382  if (topLevelOnly) {
383  s << "{ ... }";
384  } else {
385  Ptr p = std::any_cast<Ptr>(vp->back());
386  if (p.get() == 0) {
387  s << "{ NULL }";
388  } else {
389  s << '{' << std::endl;
390  s << p->toString(false, indent + "..");
391  s << indent << '}';
392  }
393  }
394  s << std::endl;
395  } else {
396  s << indent << _format(i);
397  }
398  }
399  return s.str();
400 }
401 
402 std::string PropertySet::_format(std::string const& name) const {
404  s << std::showpoint; // Always show a decimal point for floats
405  auto const j = _map.find(name);
406  s << j->first << " = ";
408  if (vp->size() > 1) {
409  s << "[ ";
410  }
411  std::type_info const& t = vp->back().type();
412  bool isFirst = true;
413  for (auto const& k : *vp) {
414  if (isFirst) {
415  isFirst = false;
416  } else {
417  s << ", ";
418  }
419  std::any const& v(k);
420  if (t == typeid(bool)) {
421  s << std::any_cast<bool>(v);
422  } else if (t == typeid(char)) {
423  s << '\'' << std::any_cast<char>(v) << '\'';
424  } else if (t == typeid(signed char)) {
425  s << '\'' << std::any_cast<signed char>(v) << '\'';
426  } else if (t == typeid(unsigned char)) {
427  s << '\'' << std::any_cast<unsigned char>(v) << '\'';
428  } else if (t == typeid(short)) {
429  s << std::any_cast<short>(v);
430  } else if (t == typeid(unsigned short)) {
431  s << std::any_cast<unsigned short>(v);
432  } else if (t == typeid(int)) {
433  s << std::any_cast<int>(v);
434  } else if (t == typeid(unsigned int)) {
435  s << std::any_cast<unsigned int>(v);
436  } else if (t == typeid(long)) {
437  s << std::any_cast<long>(v);
438  } else if (t == typeid(unsigned long)) {
439  s << std::any_cast<unsigned long>(v);
440  } else if (t == typeid(long long)) {
441  s << std::any_cast<long long>(v);
442  } else if (t == typeid(unsigned long long)) {
443  s << std::any_cast<unsigned long long>(v);
444  } else if (t == typeid(float)) {
445  s << std::setprecision(7) << std::any_cast<float>(v);
446  } else if (t == typeid(double)) {
447  s << std::setprecision(14) << std::any_cast<double>(v);
448  } else if (t == typeid(std::string)) {
449  s << '"' << std::any_cast<std::string>(v) << '"';
450  } else if (t == typeid(DateTime)) {
451  s << std::any_cast<DateTime>(v).toString(DateTime::UTC);
452  } else if (t == typeid(Ptr)) {
453  s << "{ ... }";
454  } else if (t == typeid(Persistable::Ptr)) {
455  s << "<Persistable>";
456  } else {
457  s << "<Unknown>";
458  }
459  }
460  if (j->second->size() > 1) {
461  s << " ]";
462  }
463  s << std::endl;
464  return s.str();
465 }
466 
468 // Modifiers
470 
471 template <typename T>
472 void PropertySet::set(std::string const& name, T const& value) {
474  vp->push_back(value);
475  _set(name, vp);
476 }
477 
478 template <typename T>
479 void PropertySet::set(std::string const& name, std::vector<T> const& value) {
480  if (value.empty()) return;
482  _append(*vp, value);
483  _set(name, vp);
484 }
485 
486 void PropertySet::set(std::string const& name, char const* value) { set(name, std::string(value)); }
487 
488 template <typename T>
489 void PropertySet::add(std::string const& name, T const& value) {
490  AnyMap::iterator i = _find(name);
491  if (i == _map.end()) {
492  set(name, value);
493  } else {
494  if (i->second->back().type() != typeid(T)) {
495  throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
496  }
497  i->second->push_back(value);
498  }
499 }
500 
501 // Specialize for Ptrs to check for cycles.
502 template <>
503 void PropertySet::add<PropertySet::Ptr>(std::string const& name, Ptr const& value) {
504  AnyMap::iterator i = _find(name);
505  if (i == _map.end()) {
506  set(name, value);
507  } else {
508  if (i->second->back().type() != typeid(Ptr)) {
509  throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
510  }
511  _cycleCheckPtr(value, name);
512  i->second->push_back(value);
513  }
514 }
515 
516 template <typename T>
517 void PropertySet::add(std::string const& name, std::vector<T> const& value) {
518  AnyMap::iterator i = _find(name);
519  if (i == _map.end()) {
520  set(name, value);
521  } else {
522  if (i->second->back().type() != typeid(T)) {
523  throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
524  }
525  _append(*(i->second), value);
526  }
527 }
528 
529 // Specialize for Ptrs to check for cycles.
530 template <>
531 void PropertySet::add<PropertySet::Ptr>(std::string const& name, std::vector<Ptr> const& value) {
532  AnyMap::iterator i = _find(name);
533  if (i == _map.end()) {
534  set(name, value);
535  } else {
536  if (i->second->back().type() != typeid(Ptr)) {
537  throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
538  }
539  _cycleCheckPtrVec(value, name);
540  _append(*(i->second), value);
541  }
542 }
543 
544 void PropertySet::add(std::string const& name, char const* value) { add(name, std::string(value)); }
545 
546 void PropertySet::copy(std::string const& dest, ConstPtr source, std::string const& name, bool asScalar) {
547  if (source.get() == 0) {
548  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Missing source");
549  }
550  auto const sj = source->_find(name);
551  if (sj == source->_map.end()) {
552  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, name + " not in source");
553  }
554  remove(dest);
555  if (asScalar) {
556  auto vp = std::make_shared<std::vector<std::any>>();
557  vp->push_back(sj->second->back());
558  _set(dest, vp);
559  } else {
560  auto vp = std::make_shared<std::vector<std::any>>(*(sj->second));
561  _set(dest, vp);
562  }
563 }
564 
565 void PropertySet::combine(ConstPtr source) {
566  if (source.get() == 0) {
567  return;
568  }
569  std::vector<std::string> names = source->paramNames(false);
570  for (auto const& name : names) {
571  auto const sp = source->_find(name);
572  _add(name, sp->second);
573  }
574 }
575 
576 void PropertySet::remove(std::string const& name) {
577  std::string::size_type i = name.find('.');
578  if (_flat || i == name.npos) {
579  _map.erase(name);
580  return;
581  }
582  std::string prefix(name, 0, i);
583  AnyMap::iterator j = _map.find(prefix);
584  if (j == _map.end() || j->second->back().type() != typeid(Ptr)) {
585  return;
586  }
587  Ptr p = std::any_cast<Ptr>(j->second->back());
588  if (p.get() != 0) {
589  std::string suffix(name, i + 1);
590  p->remove(suffix);
591  }
592 }
593 
595 // Private member functions
597 
598 PropertySet::AnyMap::iterator PropertySet::_find(std::string const& name) {
599  std::string::size_type i = name.find('.');
600  if (_flat || i == name.npos) {
601  return _map.find(name);
602  }
603  std::string prefix(name, 0, i);
604  AnyMap::iterator j = _map.find(prefix);
605  if (j == _map.end() || j->second->back().type() != typeid(Ptr)) {
606  return _map.end();
607  }
608  Ptr p = std::any_cast<Ptr>(j->second->back());
609  if (p.get() == 0) {
610  return _map.end();
611  }
612  std::string suffix(name, i + 1);
613  AnyMap::iterator x = p->_find(suffix);
614  if (x == p->_map.end()) {
615  return _map.end();
616  }
617  return x;
618 }
619 
620 PropertySet::AnyMap::const_iterator PropertySet::_find(std::string const& name) const {
621  std::string::size_type i = name.find('.');
622  if (_flat || i == name.npos) {
623  return _map.find(name);
624  }
625  std::string prefix(name, 0, i);
626  auto const j = _map.find(prefix);
627  if (j == _map.end() || j->second->back().type() != typeid(Ptr)) {
628  return _map.end();
629  }
630  Ptr p = std::any_cast<Ptr>(j->second->back());
631  if (p.get() == 0) {
632  return _map.end();
633  }
634  std::string suffix(name, i + 1);
635  auto const x = p->_find(suffix);
636  if (x == p->_map.end()) {
637  return _map.end();
638  }
639  return x;
640 }
641 
642 void PropertySet::_set(std::string const& name, std::shared_ptr<std::vector<std::any>> vp) {
643  _findOrInsert(name, vp);
644 }
645 
646 void PropertySet::_add(std::string const& name, std::shared_ptr<std::vector<std::any>> vp) {
647  auto const dp = _find(name);
648  if (dp == _map.end()) {
649  _set(name, vp);
650  } else {
651  if (vp->back().type() != dp->second->back().type()) {
652  throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
653  }
654  // Check for cycles
655  if (vp->back().type() == typeid(Ptr)) {
656  _cycleCheckAnyVec(*vp, name);
657  }
658  _append(*(dp->second), *vp);
659  }
660 }
661 
662 void PropertySet::_findOrInsert(std::string const& name, std::shared_ptr<std::vector<std::any>> vp) {
663  if (vp->back().type() == typeid(Ptr)) {
664  if (_flat) {
665  Ptr source = std::any_cast<Ptr>(vp->back());
666  std::vector<std::string> names = source->paramNames(false);
667  for (auto const& i : names) {
668  auto const sp = source->_find(i);
669  _add(name + "." + i, sp->second);
670  }
671  return;
672  }
673 
674  // Check for cycles
675  _cycleCheckAnyVec(*vp, name);
676  }
677 
678  std::string::size_type i = name.find('.');
679  if (_flat || i == name.npos) {
680  _map[name] = vp;
681  return;
682  }
683  std::string prefix(name, 0, i);
684  std::string suffix(name, i + 1);
685  AnyMap::iterator j = _map.find(prefix);
686  if (j == _map.end()) {
687  PropertySet::Ptr pp(new PropertySet);
688  pp->_findOrInsert(suffix, vp);
690  temp->push_back(pp);
691  _map[prefix] = temp;
692  return;
693  } else if (j->second->back().type() != typeid(Ptr)) {
694  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
695  prefix + " exists but does not contain PropertySet::Ptrs");
696  }
697  Ptr p = std::any_cast<Ptr>(j->second->back());
698  if (p.get() == 0) {
699  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
700  prefix + " exists but contains null PropertySet::Ptr");
701  }
702  p->_findOrInsert(suffix, vp);
703 }
704 
705 void PropertySet::_cycleCheckPtrVec(std::vector<Ptr> const& v, std::string const& name) {
706  for (auto const& i : v) {
707  _cycleCheckPtr(i, name);
708  }
709 }
710 
711 void PropertySet::_cycleCheckAnyVec(std::vector<std::any> const& v, std::string const& name) {
712  for (auto const& i : v) {
713  _cycleCheckPtr(std::any_cast<Ptr>(i), name);
714  }
715 }
716 
717 void PropertySet::_cycleCheckPtr(Ptr const& v, std::string const& name) {
718  if (v.get() == this) {
719  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, name + " would cause a cycle");
720  }
721  std::vector<std::string> sets = v->propertySetNames(false);
722  for (auto const& i : sets) {
723  if (v->getAsPropertySetPtr(i).get() == this) {
724  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, name + " would cause a cycle");
725  }
726  }
727 }
728 
730  // Explicit template instantiations
732 
734  // Explicit template instantiations are not well understood by doxygen.
735 
736 #define INSTANTIATE(t) \
737  template std::type_info const& PropertySet::typeOfT<t>(); \
738  template t PropertySet::get<t>(std::string const& name) const; \
739  template t PropertySet::get<t>(std::string const& name, t const& defaultValue) const; \
740  template std::vector<t> PropertySet::getArray<t>(std::string const& name) const; \
741  template void PropertySet::set<t>(std::string const& name, t const& value); \
742  template void PropertySet::set<t>(std::string const& name, std::vector<t> const& value); \
743  template void PropertySet::add<t>(std::string const& name, t const& value); \
744  template void PropertySet::add<t>(std::string const& name, std::vector<t> const& value);
745 
746 #define INSTANTIATE_PROPERTY_SET(t) \
747  template std::type_info const& PropertySet::typeOfT<t>(); \
748  template t PropertySet::get<t>(std::string const& name) const; \
749  template t PropertySet::get<t>(std::string const& name, t const& defaultValue) const; \
750  template std::vector<t> PropertySet::getArray<t>(std::string const& name) const; \
751  template void PropertySet::set<t>(std::string const& name, t const& value); \
752  template void PropertySet::set<t>(std::string const& name, std::vector<t> const& value);
753 
754 INSTANTIATE(bool)
755 INSTANTIATE(char)
756 INSTANTIATE(signed char)
757 INSTANTIATE(unsigned char)
758 INSTANTIATE(short)
759 INSTANTIATE(unsigned short)
760 INSTANTIATE(int)
761 INSTANTIATE(unsigned int)
762 INSTANTIATE(long)
763 INSTANTIATE(unsigned long)
764 INSTANTIATE(long long)
765 INSTANTIATE(unsigned long long)
766 INSTANTIATE(float)
767 INSTANTIATE(double)
770 INSTANTIATE_PROPERTY_SET(PropertySet::Ptr)
771 INSTANTIATE(Persistable::Ptr)
772 INSTANTIATE(DateTime)
773 
774 } // namespace base
775 } // namespace daf
776 } // namespace lsst
777 
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:72
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)
T throw_with_nested(T... args)