lsst.afw  22.0.0-22-gf1d71818e+db3b0def15
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"
15 #include "lsst/afw/fits.h"
16 
17 namespace lsst {
18 namespace afw {
19 namespace table {
20 
21 //-----------------------------------------------------------------------------------------------------------
22 //----- Miscellaneous Utilities -----------------------------------------------------------------------------
23 //-----------------------------------------------------------------------------------------------------------
24 
25 namespace {
26 
27 inline char getDelimiter() { return '_'; }
28 
29 // Concatenate two strings with a single-character delimiter between them
30 std::string join(std::string const &a, std::string const &b, char delimiter) {
31  std::string full;
32  full.reserve(a.size() + b.size() + 1);
33  full += a;
34  full.push_back(delimiter);
35  full += b;
36  return full;
37 }
38 
39 // Functor to compare two ItemVariants for Key equality.
40 class ItemFunctors {
41  typedef detail::SchemaImpl::ItemVariant ItemVariant;
42 
43  // Compares keys (including types).
44  struct KeyHelper {
45 
46  template <typename T>
47  bool operator()(SchemaItem<T> const &a, SchemaItem<T> const &b) const {
48  return a.key == b.key;
49  }
50 
51  template <typename T, typename U>
52  bool operator()(SchemaItem<T> const &a, SchemaItem<U> const &b) const {
53  return false;
54  }
55  };
56 
57 public:
58  static bool compareKeys(ItemVariant const &a, ItemVariant const &b) {
59  return std::visit(KeyHelper(), a, b);
60  }
61 
62  static bool compareNames(ItemVariant const &a, ItemVariant const &b) {
63  return std::visit(
64  [](auto const & a, auto const & b) { return a.field.getName() == b.field.getName(); },
65  a, b
66  );
67  }
68 
69  static bool compareDocs(ItemVariant const &a, ItemVariant const &b) {
70  return std::visit(
71  [](auto const & a, auto const & b) { return a.field.getDoc() == b.field.getDoc(); },
72  a, b
73  );
74  }
75 
76  static bool compareUnits(ItemVariant const &a, ItemVariant const &b) {
77  return std::visit(
78  [](auto const & a, auto const & b) { return a.field.getUnits() == b.field.getUnits(); },
79  a, b
80  );
81  }
82 };
83 
84 } // namespace
85 
86 //-----------------------------------------------------------------------------------------------------------
87 //----- SchemaImpl implementation ---------------------------------------------------------------------------
88 //-----------------------------------------------------------------------------------------------------------
89 
90 namespace detail {
91 
92 template <typename T>
94  NameMap::const_iterator i = _names.lower_bound(name);
95  if (i != _names.end() && i->first == name) {
96  // got an exact match; we're done if it has the right type, and dead if it doesn't.
97  try {
98  return std::get<SchemaItem<T>>(_items[i->second]);
99  } catch (std::bad_variant_access &err) {
101  (boost::format("Field '%s' does not have the given type.") % name).str());
102  }
103  }
105  (boost::format("Field with name '%s' not found with type '%s'.") % name %
107  .str());
108 }
109 
110 template <typename T>
112  OffsetMap::const_iterator i = _offsets.lower_bound(key.getOffset());
113  if (i != _offsets.end() && i->first == key.getOffset()) {
114  try {
115  return std::get<SchemaItem<T>>(_items[i->second]);
116  } catch (std::bad_variant_access &err) {
117  // just swallow the exception; this might be a subfield key that points to the beginning.
118  }
119  }
121  (boost::format("Field or subfield with offset %d not found with type '%s'.") %
123  .str());
124 }
125 
126 // We handle Flag fields separately when searching for keys, because their keys aren't like the others.
128  FlagMap::const_iterator i = _flags.lower_bound(std::make_pair(key.getOffset(), key.getBit()));
129  if (i != _flags.end()) {
130  if (i->first.first == key.getOffset() && i->first.second == key.getBit()) {
131  try {
132  return std::get<SchemaItem<Flag>>(_items[i->second]);
133  } catch (std::bad_variant_access &err) {
135  (boost::format("Flag field with offset %d and bit %d not found.") %
136  key.getOffset() % key.getBit())
137  .str());
138  }
139  }
140  }
142  (boost::format("Flag field with offset %d and bit %d not found.") % key.getOffset() %
143  key.getBit())
144  .str());
145 }
146 
147 //----- Replacing an existing SchemaItem --------------------------------------------------------------------
148 
149 // This is easier to understand if you start reading from the bottom of this section, with
150 // SchemaImpl::replaceField, then work your way up.
151 
152 namespace {
153 
154 // Find an exact SchemaItem by key ('exact' means no subfields, unlike the find member function above)
155 // Return the index into the item container.
156 template <typename T>
157 inline int findKey(SchemaImpl::OffsetMap const &offsets, SchemaImpl::FlagMap const &flags, Key<T> const &key,
158  bool throwIfMissing = true) {
159  SchemaImpl::OffsetMap::const_iterator i = offsets.find(key.getOffset());
160  if (i == offsets.end()) {
161  if (throwIfMissing) {
163  (boost::format("Key of type %s with offset %d not found in Schema") %
165  .str());
166  } else {
167  return -1;
168  }
169  }
170  return i->second;
171 }
172 
173 // Like the above, but special-cased for Flag
174 inline int findKey(SchemaImpl::OffsetMap const &offsets, SchemaImpl::FlagMap const &flags,
175  Key<Flag> const &key, bool throwIfMissing = true) {
176  SchemaImpl::FlagMap::const_iterator i = flags.find(std::make_pair(key.getOffset(), key.getBit()));
177  if (i == flags.end()) {
178  if (throwIfMissing) {
179  throw LSST_EXCEPT(
180  pex::exceptions::NotFoundError,
181  (boost::format("Key of type Flag with offset %d and bit %d not found in Schema") %
182  key.getOffset() % key.getBit())
183  .str());
184  } else {
185  return -1;
186  }
187  }
188  return i->second;
189 }
190 
191 } // namespace
192 
193 template <typename T>
194 void SchemaImpl::replaceField(Key<T> const &key, Field<T> const &field) {
195  NameMap::iterator j = _names.find(field.getName());
196  SchemaItem<T> *item = 0;
197  if (j != _names.end()) {
198  // The field name is already present in the Schema; see if it's the one we're replacing.
199  // If we can get the old item with this, we don't need to update the name map at all.
200  item = std::get_if<SchemaItem<T>>(&_items[j->second]);
201  if (!item || key != item->key) {
202  throw LSST_EXCEPT(
204  (boost::format("Field with name '%s' already present in schema with a different key.") %
205  field.getName())
206  .str());
207  }
208  }
209  if (!item) { // Need to find the original item by key, since it's a new name.
210  int index = findKey(_offsets, _flags, key);
211  item = std::get_if<SchemaItem<T>>(&_items[index]);
212  if (!item) {
214  (boost::format("Incorrect key type '%s'.") % key).str());
215  }
216  j = _names.find(item->field.getName());
217  _names.insert(j, std::pair<std::string, int>(field.getName(), j->second));
218  _names.erase(j);
219  }
220  item->field = field;
221 }
222 
223 //----- Other SchemaImpl things -----------------------------------------------------------------------------
224 
225 template <typename T>
226 int SchemaImpl::contains(SchemaItem<T> const &item, int flags) const {
227  if (!(flags & Schema::EQUAL_KEYS)) {
229  "Can only check whether item is in schema if flags & EQUAL_KEYS");
230  }
231  SchemaItem<T> const *cmpItem = 0;
232  int index = findKey(_offsets, _flags, item.key, false);
233  if (index >= 0) {
234  cmpItem = std::get_if<SchemaItem<T> >(&_items[index]);
235  if (!cmpItem) {
236  if ((flags & Schema::EQUAL_NAMES) && cmpItem->field.getName() != item.field.getName()) {
237  flags &= ~Schema::EQUAL_NAMES;
238  }
239  if ((flags & Schema::EQUAL_DOCS) && cmpItem->field.getDoc() != item.field.getDoc()) {
240  flags &= ~Schema::EQUAL_DOCS;
241  }
242  if ((flags & Schema::EQUAL_UNITS) && cmpItem->field.getUnits() != item.field.getUnits()) {
243  flags &= ~Schema::EQUAL_UNITS;
244  }
245  }
246  } else {
247  flags = 0;
248  }
249  return flags;
250 }
251 
253  std::set<std::string> result;
254  if (topOnly) {
255  for (NameMap::const_iterator i = _names.begin(); i != _names.end(); ++i) {
256  std::size_t sep = i->first.find(getDelimiter());
257  if (sep == std::string::npos) {
258  result.insert(result.end(), i->first);
259  } else {
260  result.insert(result.end(), i->first.substr(0, sep));
261  }
262  }
263  } else {
264  for (NameMap::const_iterator i = _names.begin(); i != _names.end(); ++i) {
265  result.insert(result.end(), i->first);
266  }
267  }
268  return result;
269 }
270 
272  std::set<std::string> result;
273  if (topOnly) {
274  for (NameMap::const_iterator i = _names.lower_bound(prefix); i != _names.end(); ++i) {
275  if (i->first.compare(0, prefix.size(), prefix) != 0) break;
276  std::size_t sep = i->first.find(getDelimiter(), prefix.size() + 1);
277  if (sep == std::string::npos) {
278  result.insert(result.end(),
279  i->first.substr(prefix.size() + 1, i->first.size() - prefix.size()));
280  } else {
281  result.insert(result.end(), i->first.substr(prefix.size() + 1, sep - prefix.size() - 1));
282  }
283  }
284  } else {
285  for (NameMap::const_iterator i = _names.lower_bound(prefix); i != _names.end(); ++i) {
286  if (i->first.compare(0, prefix.size(), prefix) != 0) break;
287  result.insert(result.end(),
288  i->first.substr(prefix.size() + 1, i->first.size() - prefix.size() - 1));
289  }
290  }
291  return result;
292 }
293 
294 template <typename T>
295 Key<Array<T> > SchemaImpl::addField(Field<Array<T> > const &field, bool doReplace) {
296  if (field.isVariableLength()) {
297  // Variable-length array: allocate space for one ndarray
298  return addFieldImpl(sizeof(ndarray::Array<T, 1, 1>), 1, field, doReplace);
299  }
300  // Fixed-length array: allocate space for getElementCount() elements of type T
301  return addFieldImpl(sizeof(typename Field<T>::Element), field.getElementCount(), field, doReplace);
302 }
303 
305  if (field.isVariableLength()) {
306  // Variable-length string: allocate space for one std::string
307  return addFieldImpl(sizeof(std::string), 1, field, doReplace);
308  }
309  // Fixed-length string: allocate space for getElementCount() chars
310  return addFieldImpl(sizeof(typename Field<std::string>::Element), field.getElementCount(), field,
311  doReplace);
312 }
313 
314 template <typename T>
315 Key<T> SchemaImpl::addField(Field<T> const &field, bool doReplace) {
316  return addFieldImpl(sizeof(typename Field<T>::Element), field.getElementCount(), field, doReplace);
317 }
318 
320  static int const ELEMENT_SIZE = sizeof(Field<Flag>::Element);
322  _names.insert(std::pair<std::string, int>(field.getName(), _items.size()));
323  if (!result.second) {
324  if (doReplace) {
325  SchemaItem<Flag> *item = std::get_if<SchemaItem<Flag>>(&_items[result.first->second]);
326  if (!item) {
327  throw LSST_EXCEPT(
329  (boost::format("Cannot replace field with name '%s' because types differ.") %
330  field.getName())
331  .str());
332  }
333  if (item->field.getElementCount() != field.getElementCount()) {
334  throw LSST_EXCEPT(
336  (boost::format("Cannot replace field with name '%s' because sizes differ.") %
337  field.getName())
338  .str());
339  }
340  item->field = field;
341  return item->key;
342  } else {
343  throw LSST_EXCEPT(
345  (boost::format("Field with name '%s' already present in schema.") % field.getName())
346  .str());
347  }
348  } else {
349  if (_lastFlagField < 0 || _lastFlagBit >= ELEMENT_SIZE * 8) {
350  int padding = ELEMENT_SIZE - _recordSize % ELEMENT_SIZE;
351  if (padding != ELEMENT_SIZE) {
352  _recordSize += padding;
353  }
354  _lastFlagField = _recordSize;
355  _lastFlagBit = 0;
356  _recordSize += field.getElementCount() * ELEMENT_SIZE;
357  }
358  SchemaItem<Flag> item(detail::Access::makeKey(_lastFlagField, _lastFlagBit), field);
359  ++_lastFlagBit;
360  _flags.insert(std::pair<std::pair<int, int>, int>(
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(int elementSize, int elementCount, Field<T> const &field, bool doReplace) {
370  _names.insert(std::pair<std::string, int>(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  int 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<int, int>(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) : _impl(other._impl), _aliases(other._aliases) {}
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  }
505  if ((result & EQUAL_ALIASES) && !getAliasMap()->contains(*other.getAliasMap())) result &= ~EQUAL_ALIASES;
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  typedef void result_type;
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 iter = schema.getAliasMap()->begin(); iter != schema.getAliasMap()->end(); ++iter) {
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
table::Key< std::string > name
Definition: Amplifier.cc:116
table::Key< int > field
Definition: ApCorrMap.cc:77
char * data
Definition: BaseRecord.cc:62
#define LSST_EXCEPT(type,...)
#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
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:32
Key specialization for Flag.
Definition: Flag.h:94
int getOffset() const
Return the offset in bytes of the integer element that holds this field's bit.
Definition: Flag.h:126
int getBit() const
The index of this field's bit within the integer it shares with other Flag fields.
Definition: Flag.h:129
A class used as a handle to a particular field in a table.
Definition: Key.h:53
int 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(int offset)
Definition: Access.h:65
A private implementation class to hide the messy details of Schema.
Definition: SchemaImpl.h:45
std::map< std::pair< int, int >, int > 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
std::set< std::string > getNames(bool topOnly) const
Return a set of field names (used to implement Schema::getNames).
Definition: Schema.cc:252
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a field to the schema (used to implement Schema::addField).
Definition: Schema.cc:315
int contains(SchemaItem< T > const &item, int flags) const
Definition: Schema.cc:226
void replaceField(Key< T > const &key, Field< T > const &field)
Replace the Field in an existing SchemaItem without changing the Key.
Definition: Schema.cc:194
SchemaItem< T > find(std::string const &name) const
Find an item by name (used to implement Schema::find).
Definition: Schema.cc:93
decltype(makeItemVariantType(FieldTypes{})) ItemVariant
A Boost.Variant type that can hold any one of the allowed SchemaItem types.
Definition: SchemaImpl.h:55
std::map< int, int > 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.
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)
def iter(self)
std::ostream & operator<<(std::ostream &os, BaseRecord const &record)
Definition: BaseRecord.cc:159
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
A base class for image defects.
STL namespace.
T push_back(T... args)
T reserve(T... args)
T size(T... args)
int 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
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
table::Schema schema
Definition: python.h:134
#define AFW_TABLE_FIELD_TYPE_N
Definition: types.h:38
#define AFW_TABLE_FIELD_TYPE_TUPLE
Definition: types.h:43