LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
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
35
36namespace lsst {
37namespace daf {
38namespace base {
39
40namespace {
41
48template <typename T>
49void _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
58PropertySet::PropertySet(bool flat) : _flat(flat) {}
59
60PropertySet::~PropertySet() noexcept = default;
61
63// Accessors
65
66std::shared_ptr<PropertySet> PropertySet::deepCopy() const {
67 auto n = std::make_shared<PropertySet>(_flat);
68 for (auto const& elt : _map) {
69 if (elt.second->back().type() == typeid(std::shared_ptr<PropertySet>)) {
70 for (auto const& j : *elt.second) {
71 auto p = std::any_cast<std::shared_ptr<PropertySet>>(j);
72 if (p.get() == 0) {
73 n->add(elt.first, std::shared_ptr<PropertySet>());
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
86size_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(std::shared_ptr<PropertySet>)) {
91 auto p = std::any_cast<std::shared_ptr<PropertySet>>(elt.second->back());
92 if (p.get() != 0) {
93 n += p->nameCount(false);
94 }
95 }
96 }
97 return n;
98}
99
100std::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(std::shared_ptr<PropertySet>)) {
105 auto p = std::any_cast<std::shared_ptr<PropertySet>>(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
117std::vector<std::string> PropertySet::paramNames(bool topLevelOnly) const {
119 for (auto const& elt : _map) {
120 if (elt.second->back().type() == typeid(std::shared_ptr<PropertySet>)) {
121 auto p = std::any_cast<std::shared_ptr<PropertySet>>(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
135std::vector<std::string> PropertySet::propertySetNames(bool topLevelOnly) const {
137 for (auto const& elt : _map) {
138 if (elt.second->back().type() == typeid(std::shared_ptr<PropertySet>)) {
139 v.push_back(elt.first);
140 auto p = std::any_cast<std::shared_ptr<PropertySet>>(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
152bool PropertySet::exists(std::string const& name) const { return _find(name) != _map.end(); }
153
154bool PropertySet::isArray(std::string const& name) const {
155 auto const i = _find(name);
156 return i != _map.end() && i->second->size() > 1U;
157}
158
159bool PropertySet::isPropertySetPtr(std::string const& name) const {
160 auto const i = _find(name);
161 return i != _map.end() && i->second->back().type() == typeid(std::shared_ptr<PropertySet>);
162}
163
164bool 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
169size_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
177size_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
183std::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
191template <typename T>
192std::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
198template <typename T>
199T 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
214template <typename T>
215T 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
230template <typename T>
231std::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 }
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
249bool 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
254int 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
283int64_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
309uint64_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
336double 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
365std::string PropertySet::getAsString(std::string const& name) const { return get<std::string>(name); }
366
367std::shared_ptr<PropertySet> PropertySet::getAsPropertySetPtr(std::string const& name) const {
368 return get<std::shared_ptr<PropertySet>>(name);
369}
370
371Persistable::Ptr PropertySet::getAsPersistablePtr(std::string const& name) const {
372 return get<Persistable::Ptr>(name);
373}
374
375std::string PropertySet::toString(bool topLevelOnly, std::string const& indent) const {
377 std::vector<std::string> nv = names();
378 sort(nv.begin(), nv.end());
379 for (auto const& i : nv) {
380 std::shared_ptr<std::vector<std::any>> vp = _map.find(i)->second;
381 std::type_info const& t = vp->back().type();
382 if (t == typeid(std::shared_ptr<PropertySet>)) {
383 s << indent << i << " = ";
384 if (topLevelOnly) {
385 s << "{ ... }";
386 } else {
387 auto p = std::any_cast<std::shared_ptr<PropertySet>>(vp->back());
388 if (p.get() == 0) {
389 s << "{ NULL }";
390 } else {
391 s << '{' << std::endl;
392 s << p->toString(false, indent + "..");
393 s << indent << '}';
394 }
395 }
396 s << std::endl;
397 } else {
398 s << indent << _format(i);
399 }
400 }
401 return s.str();
402}
403
404std::string PropertySet::_format(std::string const& name) const {
406 s << std::showpoint; // Always show a decimal point for floats
407 auto const j = _map.find(name);
408 s << j->first << " = ";
410 if (vp->size() > 1) {
411 s << "[ ";
412 }
413 std::type_info const& t = vp->back().type();
414 bool isFirst = true;
415 for (auto const& k : *vp) {
416 if (isFirst) {
417 isFirst = false;
418 } else {
419 s << ", ";
420 }
421 std::any const& v(k);
422 if (t == typeid(bool)) {
423 s << std::any_cast<bool>(v);
424 } else if (t == typeid(char)) {
425 s << '\'' << std::any_cast<char>(v) << '\'';
426 } else if (t == typeid(signed char)) {
427 s << '\'' << std::any_cast<signed char>(v) << '\'';
428 } else if (t == typeid(unsigned char)) {
429 s << '\'' << std::any_cast<unsigned char>(v) << '\'';
430 } else if (t == typeid(short)) {
431 s << std::any_cast<short>(v);
432 } else if (t == typeid(unsigned short)) {
433 s << std::any_cast<unsigned short>(v);
434 } else if (t == typeid(int)) {
435 s << std::any_cast<int>(v);
436 } else if (t == typeid(unsigned int)) {
437 s << std::any_cast<unsigned int>(v);
438 } else if (t == typeid(long)) {
439 s << std::any_cast<long>(v);
440 } else if (t == typeid(unsigned long)) {
441 s << std::any_cast<unsigned long>(v);
442 } else if (t == typeid(long long)) {
443 s << std::any_cast<long long>(v);
444 } else if (t == typeid(unsigned long long)) {
445 s << std::any_cast<unsigned long long>(v);
446 } else if (t == typeid(float)) {
447 s << std::setprecision(7) << std::any_cast<float>(v);
448 } else if (t == typeid(double)) {
449 s << std::setprecision(14) << std::any_cast<double>(v);
450 } else if (t == typeid(std::string)) {
451 s << '"' << std::any_cast<std::string>(v) << '"';
452 } else if (t == typeid(DateTime)) {
453 s << std::any_cast<DateTime>(v).toString(DateTime::UTC);
454 } else if (t == typeid(std::shared_ptr<PropertySet>)) {
455 s << "{ ... }";
456 } else if (t == typeid(Persistable::Ptr)) {
457 s << "<Persistable>";
458 } else {
459 s << "<Unknown>";
460 }
461 }
462 if (j->second->size() > 1) {
463 s << " ]";
464 }
465 s << std::endl;
466 return s.str();
467}
468
470// Modifiers
472
473template <typename T>
474void PropertySet::set(std::string const& name, T const& value) {
476 vp->push_back(value);
477 _set(name, vp);
478}
479
480template <typename T>
481void PropertySet::set(std::string const& name, std::vector<T> const& value) {
482 if (value.empty()) return;
484 _append(*vp, value);
485 _set(name, vp);
486}
487
488void PropertySet::set(std::string const& name, char const* value) { set(name, std::string(value)); }
489
490template <typename T>
491void PropertySet::add(std::string const& name, T const& value) {
492 AnyMap::iterator i = _find(name);
493 if (i == _map.end()) {
494 set(name, value);
495 } else {
496 if (i->second->back().type() != typeid(T)) {
497 throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
498 }
499 i->second->push_back(value);
500 }
501}
502
503// Specialize for shared_ptr to check for cycles.
504template <>
505void PropertySet::add<std::shared_ptr<PropertySet>>(
506 std::string const& name,
508) {
509 AnyMap::iterator i = _find(name);
510 if (i == _map.end()) {
511 set(name, value);
512 } else {
513 if (i->second->back().type() != typeid(std::shared_ptr<PropertySet>)) {
514 throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
515 }
516 _cycleCheckPtr(value, name);
517 i->second->push_back(value);
518 }
519}
520
521template <typename T>
522void PropertySet::add(std::string const& name, std::vector<T> const& value) {
523 AnyMap::iterator i = _find(name);
524 if (i == _map.end()) {
525 set(name, value);
526 } else {
527 if (i->second->back().type() != typeid(T)) {
528 throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
529 }
530 _append(*(i->second), value);
531 }
532}
533
534// Specialize for shared_ptr to check for cycles.
535template <>
536void PropertySet::add<std::shared_ptr<PropertySet>>(
537 std::string const& name,
539) {
540 AnyMap::iterator i = _find(name);
541 if (i == _map.end()) {
542 set(name, value);
543 } else {
544 if (i->second->back().type() != typeid(std::shared_ptr<PropertySet>)) {
545 throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
546 }
547 _cycleCheckPtrVec(value, name);
548 _append(*(i->second), value);
549 }
550}
551
552void PropertySet::add(std::string const& name, char const* value) { add(name, std::string(value)); }
553
554void PropertySet::copy(
555 std::string const& dest,
556 PropertySet const& source,
557 std::string const& name,
558 bool asScalar
559) {
560 auto const sj = source._find(name);
561 if (sj == source._map.end()) {
562 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, name + " not in source");
563 }
564 remove(dest);
565 if (asScalar) {
566 auto vp = std::make_shared<std::vector<std::any>>();
567 vp->push_back(sj->second->back());
568 _set(dest, vp);
569 } else {
570 auto vp = std::make_shared<std::vector<std::any>>(*(sj->second));
571 _set(dest, vp);
572 }
573}
574
575void PropertySet::copy(std::string const& dest, std::shared_ptr<PropertySet const> source,
576 std::string const& name, bool asScalar) {
577 if (!source) {
578 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, "Missing source");
579 }
580 copy(dest, *source, name, asScalar);
581}
582
583void PropertySet::combine(PropertySet const & source) {
584 std::vector<std::string> names = source.paramNames(false);
585 for (auto const& name : names) {
586 auto const sp = source._find(name);
587 _add(name, sp->second);
588 }
589}
590
591void PropertySet::combine(std::shared_ptr<PropertySet const> source) {
592 if (!source) {
593 return;
594 }
595 combine(*source);
596}
597
598void PropertySet::remove(std::string const& name) {
599 std::string::size_type i = name.find('.');
600 if (_flat || i == name.npos) {
601 _map.erase(name);
602 return;
603 }
604 std::string prefix(name, 0, i);
605 AnyMap::iterator j = _map.find(prefix);
606 if (j == _map.end() || j->second->back().type() != typeid(std::shared_ptr<PropertySet>)) {
607 return;
608 }
609 auto p = std::any_cast<std::shared_ptr<PropertySet>>(j->second->back());
610 if (p.get() != 0) {
611 std::string suffix(name, i + 1);
612 p->remove(suffix);
613 }
614}
615
617// Private member functions
619
620PropertySet::AnyMap::iterator PropertySet::_find(std::string const& name) {
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 AnyMap::iterator j = _map.find(prefix);
627 if (j == _map.end() || j->second->back().type() != typeid(std::shared_ptr<PropertySet>)) {
628 return _map.end();
629 }
630 auto p = std::any_cast<std::shared_ptr<PropertySet>>(j->second->back());
631 if (p.get() == 0) {
632 return _map.end();
633 }
634 std::string suffix(name, i + 1);
635 AnyMap::iterator x = p->_find(suffix);
636 if (x == p->_map.end()) {
637 return _map.end();
638 }
639 return x;
640}
641
642PropertySet::AnyMap::const_iterator PropertySet::_find(std::string const& name) const {
643 std::string::size_type i = name.find('.');
644 if (_flat || i == name.npos) {
645 return _map.find(name);
646 }
647 std::string prefix(name, 0, i);
648 auto const j = _map.find(prefix);
649 if (j == _map.end() || j->second->back().type() != typeid(std::shared_ptr<PropertySet>)) {
650 return _map.end();
651 }
652 auto p = std::any_cast<std::shared_ptr<PropertySet>>(j->second->back());
653 if (p.get() == 0) {
654 return _map.end();
655 }
656 std::string suffix(name, i + 1);
657 auto const x = p->_find(suffix);
658 if (x == p->_map.end()) {
659 return _map.end();
660 }
661 return x;
662}
663
664void PropertySet::_set(std::string const& name, std::shared_ptr<std::vector<std::any>> vp) {
665 _findOrInsert(name, vp);
666}
667
668void PropertySet::_add(std::string const& name, std::shared_ptr<std::vector<std::any>> vp) {
669 auto const dp = _find(name);
670 if (dp == _map.end()) {
671 _set(name, vp);
672 } else {
673 if (vp->back().type() != dp->second->back().type()) {
674 throw LSST_EXCEPT(pex::exceptions::TypeError, name + " has mismatched type");
675 }
676 // Check for cycles
677 if (vp->back().type() == typeid(std::shared_ptr<PropertySet>)) {
678 _cycleCheckAnyVec(*vp, name);
679 }
680 _append(*(dp->second), *vp);
681 }
682}
683
684void PropertySet::_findOrInsert(std::string const& name, std::shared_ptr<std::vector<std::any>> vp) {
685 if (vp->back().type() == typeid(std::shared_ptr<PropertySet>)) {
686 if (_flat) {
687 auto source = std::any_cast<std::shared_ptr<PropertySet>>(vp->back());
688 std::vector<std::string> names = source->paramNames(false);
689 for (auto const& i : names) {
690 auto const sp = source->_find(i);
691 _add(name + "." + i, sp->second);
692 }
693 return;
694 }
695
696 // Check for cycles
697 _cycleCheckAnyVec(*vp, name);
698 }
699
700 std::string::size_type i = name.find('.');
701 if (_flat || i == name.npos) {
702 _map[name] = vp;
703 return;
704 }
705 std::string prefix(name, 0, i);
706 std::string suffix(name, i + 1);
707 AnyMap::iterator j = _map.find(prefix);
708 if (j == _map.end()) {
709 auto pp = std::make_shared<PropertySet>();
710 pp->_findOrInsert(suffix, vp);
712 temp->push_back(pp);
713 _map[prefix] = temp;
714 return;
715 } else if (j->second->back().type() != typeid(std::shared_ptr<PropertySet>)) {
716 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
717 prefix + " exists but does not contain PropertySets");
718 }
719 auto p = std::any_cast<std::shared_ptr<PropertySet>>(j->second->back());
720 if (p.get() == 0) {
721 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
722 prefix + " exists but contains a null PropertySet");
723 }
724 p->_findOrInsert(suffix, vp);
725}
726
727void PropertySet::_cycleCheckPtrVec(
729 std::string const& name
730) {
731 for (auto const& i : v) {
732 _cycleCheckPtr(i, name);
733 }
734}
735
736void PropertySet::_cycleCheckAnyVec(std::vector<std::any> const& v, std::string const& name) {
737 for (auto const& i : v) {
738 _cycleCheckPtr(std::any_cast<std::shared_ptr<PropertySet>>(i), name);
739 }
740}
741
742void PropertySet::_cycleCheckPtr(std::shared_ptr<PropertySet> const & v, std::string const& name) {
743 if (v.get() == this) {
744 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, name + " would cause a cycle");
745 }
746 std::vector<std::string> sets = v->propertySetNames(false);
747 for (auto const& i : sets) {
748 if (v->getAsPropertySetPtr(i).get() == this) {
749 throw LSST_EXCEPT(pex::exceptions::InvalidParameterError, name + " would cause a cycle");
750 }
751 }
752}
753
755 // Explicit template instantiations
757
759 // Explicit template instantiations are not well understood by doxygen.
760
761#define INSTANTIATE(t) \
762 template std::type_info const& PropertySet::typeOfT<t>(); \
763 template t PropertySet::get<t>(std::string const& name) const; \
764 template t PropertySet::get<t>(std::string const& name, t const& defaultValue) const; \
765 template std::vector<t> PropertySet::getArray<t>(std::string const& name) const; \
766 template void PropertySet::set<t>(std::string const& name, t const& value); \
767 template void PropertySet::set<t>(std::string const& name, std::vector<t> const& value); \
768 template void PropertySet::add<t>(std::string const& name, t const& value); \
769 template void PropertySet::add<t>(std::string const& name, std::vector<t> const& value);
770
771#define INSTANTIATE_PROPERTY_SET(t) \
772 template std::type_info const& PropertySet::typeOfT<t>(); \
773 template t PropertySet::get<t>(std::string const& name) const; \
774 template t PropertySet::get<t>(std::string const& name, t const& defaultValue) const; \
775 template std::vector<t> PropertySet::getArray<t>(std::string const& name) const; \
776 template void PropertySet::set<t>(std::string const& name, t const& value); \
777 template void PropertySet::set<t>(std::string const& name, std::vector<t> const& value);
778
779INSTANTIATE(bool)
780INSTANTIATE(char)
781INSTANTIATE(signed char)
782INSTANTIATE(unsigned char)
783INSTANTIATE(short)
784INSTANTIATE(unsigned short)
785INSTANTIATE(int)
786INSTANTIATE(unsigned int)
787INSTANTIATE(long)
788INSTANTIATE(unsigned long)
789INSTANTIATE(long long)
790INSTANTIATE(unsigned long long)
791INSTANTIATE(float)
792INSTANTIATE(double)
795INSTANTIATE_PROPERTY_SET(std::shared_ptr<PropertySet>)
796INSTANTIATE(Persistable::Ptr)
797INSTANTIATE(DateTime)
798
799} // namespace base
800} // namespace daf
801} // namespace lsst
802
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 copy(T... args)
T empty(T... args)
T end(T... args)
T endl(T... args)
daf::base::PropertySet * set
Definition: fits.cc:912
T get(T... args)
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.
STL namespace.
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)