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
Schema.cc
Go to the documentation of this file.
1 #include <list>
2 #include <memory>
3 #include <stdexcept>
4 #include <type_traits>
5 #include <variant>
6 
7 #include "boost/preprocessor/seq/for_each.hpp"
8 #include "boost/preprocessor/tuple/to_seq.hpp"
9 
10 #include "lsst/utils/hashCombine.h"
11 #include "lsst/afw/table/Schema.h"
14 #include "lsst/afw/fits.h"
15 
16 namespace lsst {
17 namespace afw {
18 namespace table {
19 
20 //-----------------------------------------------------------------------------------------------------------
21 //----- Miscellaneous Utilities -----------------------------------------------------------------------------
22 //-----------------------------------------------------------------------------------------------------------
23 
24 namespace {
25 
26 inline char getDelimiter() { return '_'; }
27 
28 // Concatenate two strings with a single-character delimiter between them
29 std::string join(std::string const &a, std::string const &b, char delimiter) {
30  std::string full;
31  full.reserve(a.size() + b.size() + 1);
32  full += a;
33  full.push_back(delimiter);
34  full += b;
35  return full;
36 }
37 
38 // Functor to compare two ItemVariants for Key equality.
39 class ItemFunctors {
40  using ItemVariant = detail::SchemaImpl::ItemVariant;
41 
42  // Compares keys (including types).
43  struct KeyHelper {
44 
45  template <typename T>
46  bool operator()(SchemaItem<T> const &a, SchemaItem<T> const &b) const {
47  return a.key == b.key;
48  }
49 
50  template <typename T, typename U>
51  bool operator()(SchemaItem<T> const &a, SchemaItem<U> const &b) const {
52  return false;
53  }
54  };
55 
56 public:
57  static bool compareKeys(ItemVariant const &a, ItemVariant const &b) {
58  return std::visit(KeyHelper(), a, b);
59  }
60 
61  static bool compareNames(ItemVariant const &a, ItemVariant const &b) {
62  return std::visit(
63  [](auto const & a, auto const & b) { return a.field.getName() == b.field.getName(); },
64  a, b
65  );
66  }
67 
68  static bool compareDocs(ItemVariant const &a, ItemVariant const &b) {
69  return std::visit(
70  [](auto const & a, auto const & b) { return a.field.getDoc() == b.field.getDoc(); },
71  a, b
72  );
73  }
74 
75  static bool compareUnits(ItemVariant const &a, ItemVariant const &b) {
76  return std::visit(
77  [](auto const & a, auto const & b) { return a.field.getUnits() == b.field.getUnits(); },
78  a, b
79  );
80  }
81 };
82 
83 } // namespace
84 
85 //-----------------------------------------------------------------------------------------------------------
86 //----- SchemaImpl implementation ---------------------------------------------------------------------------
87 //-----------------------------------------------------------------------------------------------------------
88 
89 namespace detail {
90 
91 template <typename T>
93  NameMap::const_iterator i = _names.lower_bound(name);
94  if (i != _names.end() && i->first == name) {
95  // got an exact match; we're done if it has the right type, and dead if it doesn't.
96  try {
97  return std::get<SchemaItem<T>>(_items[i->second]);
98  } catch (std::bad_variant_access &err) {
100  (boost::format("Field '%s' does not have the given type.") % name).str());
101  }
102  }
104  (boost::format("Field with name '%s' not found with type '%s'.") % name %
106  .str());
107 }
108 
109 template <typename T>
111  OffsetMap::const_iterator i = _offsets.lower_bound(key.getOffset());
112  if (i != _offsets.end() && i->first == key.getOffset()) {
113  try {
114  return std::get<SchemaItem<T>>(_items[i->second]);
115  } catch (std::bad_variant_access &err) {
116  // just swallow the exception; this might be a subfield key that points to the beginning.
117  }
118  }
120  (boost::format("Field or subfield with offset %d not found with type '%s'.") %
122  .str());
123 }
124 
125 // We handle Flag fields separately when searching for keys, because their keys aren't like the others.
127  FlagMap::const_iterator i = _flags.lower_bound(std::make_pair(key.getOffset(), key.getBit()));
128  if (i != _flags.end()) {
129  if (i->first.first == key.getOffset() && i->first.second == key.getBit()) {
130  try {
131  return std::get<SchemaItem<Flag>>(_items[i->second]);
132  } catch (std::bad_variant_access &err) {
134  (boost::format("Flag field with offset %d and bit %d not found.") %
135  key.getOffset() % key.getBit())
136  .str());
137  }
138  }
139  }
141  (boost::format("Flag field with offset %d and bit %d not found.") % key.getOffset() %
142  key.getBit())
143  .str());
144 }
145 
146 //----- Replacing an existing SchemaItem --------------------------------------------------------------------
147 
148 // This is easier to understand if you start reading from the bottom of this section, with
149 // SchemaImpl::replaceField, then work your way up.
150 
151 namespace {
152 
153 // Find an exact SchemaItem by key ('exact' means no subfields, unlike the find member function above)
154 // Return the index into the item container.
155 template <typename T>
156 inline std::size_t findKey(SchemaImpl::OffsetMap const &offsets, SchemaImpl::FlagMap const &flags, Key<T> const &key,
157  bool throwIfMissing = true) {
158  SchemaImpl::OffsetMap::const_iterator i = offsets.find(key.getOffset());
159  if (i == offsets.end()) {
160  if (throwIfMissing) {
162  (boost::format("Key of type %s with offset %d not found in Schema") %
164  .str());
165  } else {
167  }
168  }
169  return i->second;
170 }
171 
172 // Like the above, but special-cased for Flag
173 inline std::size_t findKey(SchemaImpl::OffsetMap const &offsets, SchemaImpl::FlagMap const &flags,
174  Key<Flag> const &key, bool throwIfMissing = true) {
175  SchemaImpl::FlagMap::const_iterator i = flags.find(std::make_pair(key.getOffset(), key.getBit()));
176  if (i == flags.end()) {
177  if (throwIfMissing) {
178  throw LSST_EXCEPT(
179  pex::exceptions::NotFoundError,
180  (boost::format("Key of type Flag with offset %d and bit %d not found in Schema") %
181  key.getOffset() % key.getBit())
182  .str());
183  } else {
185  }
186  }
187  return i->second;
188 }
189 
190 } // namespace
191 
192 template <typename T>
193 void SchemaImpl::replaceField(Key<T> const &key, Field<T> const &field) {
194  NameMap::iterator j = _names.find(field.getName());
195  SchemaItem<T> *item = nullptr;
196  if (j != _names.end()) {
197  // The field name is already present in the Schema; see if it's the one we're replacing.
198  // If we can get the old item with this, we don't need to update the name map at all.
199  item = std::get_if<SchemaItem<T>>(&_items[j->second]);
200  if (!item || key != item->key) {
201  throw LSST_EXCEPT(
203  (boost::format("Field with name '%s' already present in schema with a different key.") %
204  field.getName())
205  .str());
206  }
207  }
208  if (!item) { // Need to find the original item by key, since it's a new name.
209  std::size_t index = findKey(_offsets, _flags, key);
210  item = std::get_if<SchemaItem<T>>(&_items[index]);
211  if (!item) {
213  (boost::format("Incorrect key type '%s'.") % key).str());
214  }
215  j = _names.find(item->field.getName());
216  _names.insert(j, std::pair<std::string, std::size_t>(field.getName(), j->second));
217  _names.erase(j);
218  }
219  item->field = field;
220 }
221 
222 //----- Other SchemaImpl things -----------------------------------------------------------------------------
223 
224 template <typename T>
225 int SchemaImpl::contains(SchemaItem<T> const &item, int flags) const {
226  if (!(flags & Schema::EQUAL_KEYS)) {
228  "Can only check whether item is in schema if flags & EQUAL_KEYS");
229  }
230  SchemaItem<T> const *cmpItem = nullptr;
231  std::size_t index = findKey(_offsets, _flags, item.key, false);
232  if (index != std::numeric_limits<size_t>::max()) {
233  cmpItem = std::get_if<SchemaItem<T> >(&_items[index]);
234  if (!cmpItem) {
235  if ((flags & Schema::EQUAL_NAMES) && cmpItem->field.getName() != item.field.getName()) {
236  flags &= ~Schema::EQUAL_NAMES;
237  }
238  if ((flags & Schema::EQUAL_DOCS) && cmpItem->field.getDoc() != item.field.getDoc()) {
239  flags &= ~Schema::EQUAL_DOCS;
240  }
241  if ((flags & Schema::EQUAL_UNITS) && cmpItem->field.getUnits() != item.field.getUnits()) {
242  flags &= ~Schema::EQUAL_UNITS;
243  }
244  }
245  } else {
246  flags = 0;
247  }
248  return flags;
249 }
250 
253  if (topOnly) {
254  for (auto const &_name : _names) {
255  std::size_t sep = _name.first.find(getDelimiter());
256  if (sep == std::string::npos) {
257  result.insert(result.end(), _name.first);
258  } else {
259  result.insert(result.end(), _name.first.substr(0, sep));
260  }
261  }
262  } else {
263  for (auto const &_name : _names) {
264  result.insert(result.end(), _name.first);
265  }
266  }
267  return result;
268 }
269 
272  if (topOnly) {
273  for (NameMap::const_iterator i = _names.lower_bound(prefix); i != _names.end(); ++i) {
274  if (i->first.compare(0, prefix.size(), prefix) != 0) break;
275  std::size_t sep = i->first.find(getDelimiter(), prefix.size() + 1);
276  if (sep == std::string::npos) {
277  result.insert(result.end(),
278  i->first.substr(prefix.size() + 1, i->first.size() - prefix.size()));
279  } else {
280  result.insert(result.end(), i->first.substr(prefix.size() + 1, sep - prefix.size() - 1));
281  }
282  }
283  } else {
284  for (NameMap::const_iterator i = _names.lower_bound(prefix); i != _names.end(); ++i) {
285  if (i->first.compare(0, prefix.size(), prefix) != 0) break;
286  result.insert(result.end(),
287  i->first.substr(prefix.size() + 1, i->first.size() - prefix.size() - 1));
288  }
289  }
290  return result;
291 }
292 
293 template <typename T>
294 Key<Array<T> > SchemaImpl::addField(Field<Array<T> > const &field, bool doReplace) {
295  if (field.isVariableLength()) {
296  // Variable-length array: allocate space for one ndarray
297  return addFieldImpl(sizeof(ndarray::Array<T, 1, 1>), 1, field, doReplace);
298  }
299  // Fixed-length array: allocate space for getElementCount() elements of type T
300  return addFieldImpl(sizeof(typename Field<T>::Element), field.getElementCount(), field, doReplace);
301 }
302 
304  if (field.isVariableLength()) {
305  // Variable-length string: allocate space for one std::string
306  return addFieldImpl(sizeof(std::string), 1, field, doReplace);
307  }
308  // Fixed-length string: allocate space for getElementCount() chars
309  return addFieldImpl(sizeof(typename Field<std::string>::Element), field.getElementCount(), field,
310  doReplace);
311 }
312 
313 template <typename T>
314 Key<T> SchemaImpl::addField(Field<T> const &field, bool doReplace) {
315  return addFieldImpl(sizeof(typename Field<T>::Element), field.getElementCount(), field, doReplace);
316 }
317 
319  static std::size_t const ELEMENT_SIZE = sizeof(Field<Flag>::Element);
321  _names.insert(std::pair<std::string, std::size_t>(field.getName(), _items.size()));
322  if (!result.second) {
323  if (doReplace) {
324  SchemaItem<Flag> *item = std::get_if<SchemaItem<Flag>>(&_items[result.first->second]);
325  if (!item) {
326  throw LSST_EXCEPT(
328  (boost::format("Cannot replace field with name '%s' because types differ.") %
329  field.getName())
330  .str());
331  }
332  if (item->field.getElementCount() != field.getElementCount()) {
333  throw LSST_EXCEPT(
335  (boost::format("Cannot replace field with name '%s' because sizes differ.") %
336  field.getName())
337  .str());
338  }
339  item->field = field;
340  return item->key;
341  } else {
342  throw LSST_EXCEPT(
344  (boost::format("Field with name '%s' already present in schema.") % field.getName())
345  .str());
346  }
347  } else {
348  if (!_initFlag || _lastFlagBit >= ELEMENT_SIZE * 8) {
349  std::size_t padding = ELEMENT_SIZE - _recordSize % ELEMENT_SIZE;
350  if (padding != ELEMENT_SIZE) {
351  _recordSize += padding;
352  }
353  _lastFlagField = _recordSize;
354  _lastFlagBit = 0;
355  _initFlag = true;
356  _recordSize += field.getElementCount() * ELEMENT_SIZE;
357  }
358  SchemaItem<Flag> item(detail::Access::makeKey(_lastFlagField, _lastFlagBit), field);
359  ++_lastFlagBit;
361  std::make_pair(item.key.getOffset(), item.key.getBit()), _items.size()));
362  _items.push_back(item);
363  return item.key;
364  }
365 }
366 
367 template <typename T>
368 Key<T> SchemaImpl::addFieldImpl(std::size_t elementSize, std::size_t elementCount, Field<T> const &field, bool doReplace) {
370  _names.insert(std::pair<std::string, std::size_t>(field.getName(), _items.size()));
371  if (!result.second) {
372  if (doReplace) {
373  SchemaItem<T> *item = std::get_if<SchemaItem<T>>(&_items[result.first->second]);
374  if (!item) {
375  throw LSST_EXCEPT(
377  (boost::format("Cannot replace field with name '%s' because types differ.") %
378  field.getName())
379  .str());
380  }
381  // n.b. we don't use elementCount here because we *do* want variable length arrays (for
382  // which we set elementCount == 1, but field->getElementCount() == -1) to compare as different
383  // from fixed-length arrays with a single element.
384  if (item->field.getElementCount() != field.getElementCount()) {
385  throw LSST_EXCEPT(
387  (boost::format("Cannot replace field with name '%s' because sizes differ.") %
388  field.getName())
389  .str());
390  }
391  item->field = field;
392  return item->key;
393  } else {
394  throw LSST_EXCEPT(
396  (boost::format("Field with name '%s' already present in schema.") % field.getName())
397  .str());
398  }
399  } else {
400  std::size_t padding = elementSize - _recordSize % elementSize;
401  if (padding != elementSize) {
402  _recordSize += padding;
403  }
404  SchemaItem<T> item(detail::Access::makeKey(field, _recordSize), field);
405  _recordSize += elementCount * elementSize;
406  _offsets.insert(std::pair<std::size_t, std::size_t>(item.key.getOffset(), _items.size()));
407  _items.push_back(item);
408  return item.key;
409  }
410 }
411 
412 } // namespace detail
413 
414 //-----------------------------------------------------------------------------------------------------------
415 //----- Schema implementation -------------------------------------------------------------------------------
416 //-----------------------------------------------------------------------------------------------------------
417 
418 int const Schema::VERSION;
419 
420 Schema::Schema() : _impl(std::make_shared<Impl>()), _aliases(std::make_shared<AliasMap>()) {}
421 
422 Schema::Schema(Schema const &other) = default;
423 // Delegate to copy constructor for backwards compatibility
424 Schema::Schema(Schema &&other) : Schema(other) {}
425 
426 Schema &Schema::operator=(Schema const &) = default;
427 Schema &Schema::operator=(Schema &&) = default;
428 Schema::~Schema() = default;
429 
430 Schema Schema::readFits(std::string const &filename, int hdu) {
432  fp.setHdu(hdu);
433  return readFits(fp);
434 }
435 
438  fp.setHdu(hdu);
439  return readFits(fp);
440 }
441 
444  fitsfile.readMetadata(header, false);
445  return fromFitsMetadata(header);
446 }
447 
449  return io::FitsSchemaInputMapper(header, stripMetadata).finalize();
450 }
451 
453  // delegate to utility funcs at top of this file
454  return afw::table::join(a, b, getDelimiter());
455 }
456 
457 void Schema::_edit() {
458  if (!_impl.unique()) {
459  std::shared_ptr<Impl> data(std::make_shared<Impl>(*_impl));
460  _impl.swap(data);
461  }
462 }
463 
464 std::set<std::string> Schema::getNames(bool topOnly) const { return _impl->getNames(topOnly); }
465 
466 template <typename T>
468  std::string tmp(name);
469  _aliases->_apply(tmp);
470  return _impl->find<T>(tmp);
471 }
472 
473 template <typename T>
474 SchemaItem<T> Schema::find(Key<T> const &key) const {
475  return _impl->find(key);
476 }
477 
478 template <typename T>
479 Key<T> Schema::addField(Field<T> const &field, bool doReplace) {
480  _edit();
481  return _impl->addField(field, doReplace);
482 }
483 
484 template <typename T>
485 void Schema::replaceField(Key<T> const &key, Field<T> const &field) {
486  _edit();
487  _impl->replaceField(key, field);
488 }
489 
490 int Schema::contains(Schema const &other, int flags) const {
491  if (_impl == other._impl) return flags;
492  if (_impl->getItems().size() < other._impl->getItems().size()) return 0;
493  int result = flags;
494  if (result & EQUAL_FIELDS) {
495  for (Impl::ItemContainer::const_iterator i1 = _impl->getItems().begin(),
496  i2 = other._impl->getItems().begin();
497  i2 != other._impl->getItems().end(); ++i1, ++i2) {
498  if ((result & EQUAL_KEYS) && !ItemFunctors::compareKeys(*i1, *i2)) result &= ~EQUAL_KEYS;
499  if ((result & EQUAL_NAMES) && !ItemFunctors::compareNames(*i1, *i2)) result &= ~EQUAL_NAMES;
500  if ((result & EQUAL_DOCS) && !ItemFunctors::compareDocs(*i1, *i2)) result &= ~EQUAL_DOCS;
501  if ((result & EQUAL_UNITS) && !ItemFunctors::compareUnits(*i1, *i2)) result &= ~EQUAL_UNITS;
502  if (!result) break;
503  }
504  }
506  return result;
507 }
508 
509 int Schema::compare(Schema const &other, int flags) const {
510  int result = contains(other, flags);
511  if (_impl->getItems().size() != other._impl->getItems().size()) {
512  result &= ~EQUAL_FIELDS;
513  }
514  if (getAliasMap()->size() != other.getAliasMap()->size()) {
515  result &= ~EQUAL_ALIASES;
516  }
517  return result;
518 }
519 
520 std::size_t Schema::hash_value() const noexcept {
521  // Completely arbitrary seed
522  std::size_t result = 17;
523  auto hasher = [&result](auto const &item) { result = utils::hashCombine(result, item.key); };
524  forEach(hasher);
525  return result;
526 }
527 
528 template <typename T>
529 int Schema::contains(SchemaItem<T> const &item, int flags) const {
530  return _impl->contains(item, flags);
531 }
532 
534  if (!aliases) {
535  aliases = std::make_shared<AliasMap>();
536  }
537  _aliases = aliases;
538 }
539 
540 void Schema::disconnectAliases() { _aliases = std::make_shared<AliasMap>(*_aliases); }
541 
542 //----- Stringification -------------------------------------------------------------------------------------
543 
544 namespace {
545 
546 // Schema::forEach functor used for stringificationx
547 struct Stream {
548  using result_type = void;
549 
550  template <typename T>
551  void operator()(SchemaItem<T> const &item) const {
552  *os << " (" << item.field << ", " << item.key << "),\n";
553  }
554 
555  explicit Stream(std::ostream *os_) : os(os_) {}
556 
558 };
559 
560 } // namespace
561 
563  os << "Schema(\n";
564  schema.forEach(Stream(&os));
565  for (auto const &iter : *schema.getAliasMap()) {
566  os << " '" << iter.first << "'->'" << iter.second << "'\n";
567  }
568  return os << ")\n";
569 }
570 
571 //-----------------------------------------------------------------------------------------------------------
572 //----- SubSchema implementation ----------------------------------------------------------------------------
573 //-----------------------------------------------------------------------------------------------------------
574 
576  // delegate to utility funcs at top of this file
577  return afw::table::join(a, b, getDelimiter());
578 }
579 
580 SubSchema::SubSchema(std::shared_ptr<Impl> impl, std::shared_ptr<AliasMap> aliases, std::string const &name)
581  : _impl(impl), _aliases(aliases), _name(name) {}
582 
583 template <typename T>
585  return _impl->find<T>(_aliases->apply(join(_name, name)));
586 }
587 
589  return SubSchema(_impl, _aliases, join(_name, name));
590 }
591 
592 std::set<std::string> SubSchema::getNames(bool topOnly) const { return _impl->getNames(topOnly, _name); }
593 
594 //-----------------------------------------------------------------------------------------------------------
595 //----- Explicit instantiation ------------------------------------------------------------------------------
596 //-----------------------------------------------------------------------------------------------------------
597 
598 // Note: by instantiating the public functions below, we also instantiate a lot of the private
599 // implementation functions. If you move some of those to a different source file, you'll need
600 // more explicit instantiation.
601 
602 #define INSTANTIATE_LAYOUT(r, data, elem) \
603  template Key<elem> Schema::addField(Field<elem> const &, bool); \
604  template SchemaItem<elem> Schema::find(std::string const &) const; \
605  template SchemaItem<elem> Schema::find(Key<elem> const &) const; \
606  template SchemaItem<elem> detail::SchemaImpl::find(std::string const &name) const; \
607  template int Schema::contains(SchemaItem<elem> const &, int) const; \
608  template void Schema::replaceField(Key<elem> const &, Field<elem> const &); \
609  template SchemaItem<elem> SubSchema::find(std::string const &) const;
610 
612  BOOST_PP_TUPLE_TO_SEQ(AFW_TABLE_FIELD_TYPE_N, AFW_TABLE_FIELD_TYPE_TUPLE))
613 } // namespace table
614 } // namespace afw
615 } // namespace lsst
py::object result
Definition: _schema.cc:429
table::Key< std::string > name
Definition: Amplifier.cc:116
table::Key< int > field
Definition: ApCorrMap.cc:77
char * data
Definition: BaseRecord.cc:61
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
#define INSTANTIATE_LAYOUT(r, data, elem)
Definition: Schema.cc:602
std::ostream * os
Definition: Schema.cc:557
std::string prefix
Definition: SchemaMapper.cc:72
table::Key< int > b
table::Key< int > a
table::Schema schema
Definition: python.h:134
T begin(T... args)
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:297
void readMetadata(daf::base::PropertySet &metadata, bool strip=false)
Read a FITS header into a PropertySet or PropertyList.
Definition: fits.cc:1087
Lifetime-management for memory that goes into FITS memory files.
Definition: fits.h:121
Mapping class that holds aliases for a Schema.
Definition: AliasMap.h:36
Tag types used to declare specialized field types.
Definition: misc.h:31
Key specialization for Flag.
Definition: Flag.h:94
std::size_t getBit() const
The index of this field's bit within the integer it shares with other Flag fields.
Definition: Flag.h:129
std::size_t getOffset() const
Return the offset in bytes of the integer element that holds this field's bit.
Definition: Flag.h:126
A class used as a handle to a particular field in a table.
Definition: Key.h:53
std::size_t getOffset() const noexcept
Return the offset (in bytes) of this field within a record.
Definition: Key.h:87
Defines the fields and offsets for a table.
Definition: Schema.h:51
void forEach(F &func) const
Apply a functor to each SchemaItem in the Schema.
Definition: Schema.h:214
static int const VERSION
Definition: Schema.h:57
Schema()
Construct an empty Schema.
Definition: Schema.cc:420
void disconnectAliases()
Sever the connection between this schema and any others with which it shares aliases.
Definition: Schema.cc:540
Schema & operator=(Schema const &other)
std::string join(std::string const &a, std::string const &b) const
Join strings using the field delimiter appropriate for this Schema.
Definition: Schema.cc:452
void setAliasMap(std::shared_ptr< AliasMap > aliases)
Set the alias map.
Definition: Schema.cc:533
std::set< std::string > getNames(bool topOnly=false) const
Return a set of field names in the schema.
Definition: Schema.cc:464
static Schema fromFitsMetadata(daf::base::PropertyList &header, bool stripMetadata=true)
Construct from reading a FITS header.
Definition: Schema.cc:448
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
Definition: Schema.cc:479
static Schema readFits(std::string const &filename, int hdu=fits::DEFAULT_HDU)
Construct from reading a FITS file.
Definition: Schema.cc:430
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition: Schema.cc:520
int contains(Schema const &other, int flags=EQUAL_KEYS) const
Test whether the given schema is a subset of this.
Definition: Schema.cc:490
int compare(Schema const &other, int flags=EQUAL_KEYS) const
Do a detailed equality comparison of two schemas.
Definition: Schema.cc:509
void replaceField(Key< T > const &key, Field< T > const &field)
Replace the Field (name/description) for an existing Key.
Definition: Schema.cc:485
SchemaItem< T > find(std::string const &name) const
Find a SchemaItem in the Schema by name.
Definition: Schema.cc:467
@ EQUAL_DOCS
Fields have the same documentation (ordered).
Definition: Schema.h:68
@ EQUAL_NAMES
Fields have the same names (ordered).
Definition: Schema.h:67
@ EQUAL_UNITS
Fields have the same units (ordered).
Definition: Schema.h:69
@ EQUAL_KEYS
Keys have the same types offsets, and sizes.
Definition: Schema.h:66
@ EQUAL_FIELDS
Fields are identical (but aliases may not be).
Definition: Schema.h:70
@ EQUAL_ALIASES
Schemas have identical AliasMaps.
Definition: Schema.h:71
std::shared_ptr< AliasMap > getAliasMap() const
Return the map of aliases.
Definition: Schema.h:279
A proxy type for name lookups in a Schema.
Definition: Schema.h:367
std::string join(std::string const &a, std::string const &b) const
Join strings using the field delimiter appropriate for this Schema.
Definition: Schema.cc:575
SubSchema operator[](std::string const &name) const
Return a nested proxy.
Definition: Schema.cc:588
std::set< std::string > getNames(bool topOnly=false) const
Return a set of nested names that start with the SubSchema's prefix.
Definition: Schema.cc:592
SchemaItem< T > find(std::string const &name) const
Find a nested SchemaItem by name.
Definition: Schema.cc:584
static Key< T > makeKey(std::size_t offset)
Definition: Access.h:65
A private implementation class to hide the messy details of Schema.
Definition: SchemaImpl.h:45
ItemContainer const & getItems() const
Return the vector of SchemaItem variants.
Definition: SchemaImpl.h:133
std::set< std::string > getNames(bool topOnly) const
Return a set of field names (used to implement Schema::getNames).
Definition: Schema.cc:251
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a field to the schema (used to implement Schema::addField).
Definition: Schema.cc:314
int contains(SchemaItem< T > const &item, int flags) const
Definition: Schema.cc:225
void replaceField(Key< T > const &key, Field< T > const &field)
Replace the Field in an existing SchemaItem without changing the Key.
Definition: Schema.cc:193
SchemaItem< T > find(std::string const &name) const
Find an item by name (used to implement Schema::find).
Definition: Schema.cc:92
std::map< std::pair< std::size_t, std::size_t >, std::size_t > FlagMap
A map from Flag field offset/bit pairs to position in the vector, so we can do Flag field lookups.
Definition: SchemaImpl.h:63
decltype(makeItemVariantType(FieldTypes{})) ItemVariant
A Boost.Variant type that can hold any one of the allowed SchemaItem types.
Definition: SchemaImpl.h:55
std::map< std::size_t, std::size_t > OffsetMap
A map from standard field offsets to position in the vector, so we can do field lookups.
Definition: SchemaImpl.h:61
A class that describes a mapping from a FITS binary table to an afw::table Schema.
Schema finalize()
Map any remaining items into regular Schema items, and return the final Schema.
Class for storing ordered metadata with comments.
Definition: PropertyList.h:68
Reports invalid arguments.
Definition: Runtime.h:66
Reports errors in the logical structure of the program.
Definition: Runtime.h:46
Reports attempts to access elements using an invalid key.
Definition: Runtime.h:151
Reports errors from accepting an object of an unexpected or inappropriate type.
Definition: Runtime.h:167
T end(T... args)
T erase(T... args)
T find(T... args)
T insert(T... args)
T lower_bound(T... args)
T make_pair(T... args)
T max(T... args)
std::ostream & operator<<(std::ostream &os, BaseRecord const &record)
Definition: BaseRecord.cc:158
BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_COLUMNVIEW_SCALAR, _, BOOST_PP_TUPLE_TO_SEQ(AFW_TABLE_SCALAR_FIELD_TYPE_N, AFW_TABLE_SCALAR_FIELD_TYPE_TUPLE)) BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_COLUMNVIEW_ARRAY
std::size_t hashCombine(std::size_t seed) noexcept
Combine hashes.
Definition: hashCombine.h:35
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
A base class for image defects.
STL namespace.
T push_back(T... args)
T reserve(T... args)
T size(T... args)
std::size_t getElementCount() const
Return the number of subfield elements (always one for scalars).
Definition: Flag.h:38
A description of a field in a table.
Definition: Field.h:24
typename FieldBase< T >::Element Element
Type used to store field data in the table (a field may have multiple elements).
Definition: Field.h:26
A simple pair-like struct for mapping a Field (name and description) with a Key (used for actual data...
Definition: SchemaImpl.h:22
T substr(T... args)
T swap(T... args)
#define AFW_TABLE_FIELD_TYPE_N
Definition: types.h:38
#define AFW_TABLE_FIELD_TYPE_TUPLE
Definition: types.h:43
T unique(T... args)