lsst.afw  22.0.1-24-g2e899d296+4206820b0d
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 std::size_t 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 {
168  }
169  }
170  return i->second;
171 }
172 
173 // Like the above, but special-cased for Flag
174 inline std::size_t 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 {
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 = nullptr;
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  std::size_t 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, std::size_t>(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 = nullptr;
232  std::size_t index = findKey(_offsets, _flags, item.key, false);
233  if (index != std::numeric_limits<size_t>::max()) {
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 std::size_t const ELEMENT_SIZE = sizeof(Field<Flag>::Element);
322  _names.insert(std::pair<std::string, std::size_t>(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 (!_initFlag || _lastFlagBit >= ELEMENT_SIZE * 8) {
350  std::size_t padding = ELEMENT_SIZE - _recordSize % ELEMENT_SIZE;
351  if (padding != ELEMENT_SIZE) {
352  _recordSize += padding;
353  }
354  _lastFlagField = _recordSize;
355  _lastFlagBit = 0;
356  _initFlag = true;
357  _recordSize += field.getElementCount() * ELEMENT_SIZE;
358  }
359  SchemaItem<Flag> item(detail::Access::makeKey(_lastFlagField, _lastFlagBit), field);
360  ++_lastFlagBit;
362  std::make_pair(item.key.getOffset(), item.key.getBit()), _items.size()));
363  _items.push_back(item);
364  return item.key;
365  }
366 }
367 
368 template <typename T>
369 Key<T> SchemaImpl::addFieldImpl(std::size_t elementSize, std::size_t elementCount, Field<T> const &field, bool doReplace) {
371  _names.insert(std::pair<std::string, std::size_t>(field.getName(), _items.size()));
372  if (!result.second) {
373  if (doReplace) {
374  SchemaItem<T> *item = std::get_if<SchemaItem<T>>(&_items[result.first->second]);
375  if (!item) {
376  throw LSST_EXCEPT(
378  (boost::format("Cannot replace field with name '%s' because types differ.") %
379  field.getName())
380  .str());
381  }
382  // n.b. we don't use elementCount here because we *do* want variable length arrays (for
383  // which we set elementCount == 1, but field->getElementCount() == -1) to compare as different
384  // from fixed-length arrays with a single element.
385  if (item->field.getElementCount() != field.getElementCount()) {
386  throw LSST_EXCEPT(
388  (boost::format("Cannot replace field with name '%s' because sizes differ.") %
389  field.getName())
390  .str());
391  }
392  item->field = field;
393  return item->key;
394  } else {
395  throw LSST_EXCEPT(
397  (boost::format("Field with name '%s' already present in schema.") % field.getName())
398  .str());
399  }
400  } else {
401  std::size_t padding = elementSize - _recordSize % elementSize;
402  if (padding != elementSize) {
403  _recordSize += padding;
404  }
405  SchemaItem<T> item(detail::Access::makeKey(field, _recordSize), field);
406  _recordSize += elementCount * elementSize;
407  _offsets.insert(std::pair<std::size_t, std::size_t>(item.key.getOffset(), _items.size()));
408  _items.push_back(item);
409  return item.key;
410  }
411 }
412 
413 } // namespace detail
414 
415 //-----------------------------------------------------------------------------------------------------------
416 //----- Schema implementation -------------------------------------------------------------------------------
417 //-----------------------------------------------------------------------------------------------------------
418 
419 int const Schema::VERSION;
420 
421 Schema::Schema() : _impl(std::make_shared<Impl>()), _aliases(std::make_shared<AliasMap>()) {}
422 
423 Schema::Schema(Schema const &other) : _impl(other._impl), _aliases(other._aliases) {}
424 // Delegate to copy constructor for backwards compatibility
425 Schema::Schema(Schema &&other) : Schema(other) {}
426 
427 Schema &Schema::operator=(Schema const &) = default;
428 Schema &Schema::operator=(Schema &&) = default;
429 Schema::~Schema() = default;
430 
431 Schema Schema::readFits(std::string const &filename, int hdu) {
433  fp.setHdu(hdu);
434  return readFits(fp);
435 }
436 
439  fp.setHdu(hdu);
440  return readFits(fp);
441 }
442 
445  fitsfile.readMetadata(header, false);
446  return fromFitsMetadata(header);
447 }
448 
450  return io::FitsSchemaInputMapper(header, stripMetadata).finalize();
451 }
452 
454  // delegate to utility funcs at top of this file
455  return afw::table::join(a, b, getDelimiter());
456 }
457 
458 void Schema::_edit() {
459  if (!_impl.unique()) {
460  std::shared_ptr<Impl> data(std::make_shared<Impl>(*_impl));
461  _impl.swap(data);
462  }
463 }
464 
465 std::set<std::string> Schema::getNames(bool topOnly) const { return _impl->getNames(topOnly); }
466 
467 template <typename T>
469  std::string tmp(name);
470  _aliases->_apply(tmp);
471  return _impl->find<T>(tmp);
472 }
473 
474 template <typename T>
475 SchemaItem<T> Schema::find(Key<T> const &key) const {
476  return _impl->find(key);
477 }
478 
479 template <typename T>
480 Key<T> Schema::addField(Field<T> const &field, bool doReplace) {
481  _edit();
482  return _impl->addField(field, doReplace);
483 }
484 
485 template <typename T>
486 void Schema::replaceField(Key<T> const &key, Field<T> const &field) {
487  _edit();
488  _impl->replaceField(key, field);
489 }
490 
491 int Schema::contains(Schema const &other, int flags) const {
492  if (_impl == other._impl) return flags;
493  if (_impl->getItems().size() < other._impl->getItems().size()) return 0;
494  int result = flags;
495  if (result & EQUAL_FIELDS) {
496  for (Impl::ItemContainer::const_iterator i1 = _impl->getItems().begin(),
497  i2 = other._impl->getItems().begin();
498  i2 != other._impl->getItems().end(); ++i1, ++i2) {
499  if ((result & EQUAL_KEYS) && !ItemFunctors::compareKeys(*i1, *i2)) result &= ~EQUAL_KEYS;
500  if ((result & EQUAL_NAMES) && !ItemFunctors::compareNames(*i1, *i2)) result &= ~EQUAL_NAMES;
501  if ((result & EQUAL_DOCS) && !ItemFunctors::compareDocs(*i1, *i2)) result &= ~EQUAL_DOCS;
502  if ((result & EQUAL_UNITS) && !ItemFunctors::compareUnits(*i1, *i2)) result &= ~EQUAL_UNITS;
503  if (!result) break;
504  }
505  }
506  if ((result & EQUAL_ALIASES) && !getAliasMap()->contains(*other.getAliasMap())) result &= ~EQUAL_ALIASES;
507  return result;
508 }
509 
510 int Schema::compare(Schema const &other, int flags) const {
511  int result = contains(other, flags);
512  if (_impl->getItems().size() != other._impl->getItems().size()) {
513  result &= ~EQUAL_FIELDS;
514  }
515  if (getAliasMap()->size() != other.getAliasMap()->size()) {
516  result &= ~EQUAL_ALIASES;
517  }
518  return result;
519 }
520 
521 std::size_t Schema::hash_value() const noexcept {
522  // Completely arbitrary seed
523  std::size_t result = 17;
524  auto hasher = [&result](auto const &item) { result = utils::hashCombine(result, item.key); };
525  forEach(hasher);
526  return result;
527 }
528 
529 template <typename T>
530 int Schema::contains(SchemaItem<T> const &item, int flags) const {
531  return _impl->contains(item, flags);
532 }
533 
535  if (!aliases) {
536  aliases = std::make_shared<AliasMap>();
537  }
538  _aliases = aliases;
539 }
540 
541 void Schema::disconnectAliases() { _aliases = std::make_shared<AliasMap>(*_aliases); }
542 
543 //----- Stringification -------------------------------------------------------------------------------------
544 
545 namespace {
546 
547 // Schema::forEach functor used for stringificationx
548 struct Stream {
549  typedef void result_type;
550 
551  template <typename T>
552  void operator()(SchemaItem<T> const &item) const {
553  *os << " (" << item.field << ", " << item.key << "),\n";
554  }
555 
556  explicit Stream(std::ostream *os_) : os(os_) {}
557 
559 };
560 
561 } // namespace
562 
564  os << "Schema(\n";
565  schema.forEach(Stream(&os));
566  for (auto iter = schema.getAliasMap()->begin(); iter != schema.getAliasMap()->end(); ++iter) {
567  os << " '" << iter->first << "'->'" << iter->second << "'\n";
568  }
569  return os << ")\n";
570 }
571 
572 //-----------------------------------------------------------------------------------------------------------
573 //----- SubSchema implementation ----------------------------------------------------------------------------
574 //-----------------------------------------------------------------------------------------------------------
575 
577  // delegate to utility funcs at top of this file
578  return afw::table::join(a, b, getDelimiter());
579 }
580 
581 SubSchema::SubSchema(std::shared_ptr<Impl> impl, std::shared_ptr<AliasMap> aliases, std::string const &name)
582  : _impl(impl), _aliases(aliases), _name(name) {}
583 
584 template <typename T>
586  return _impl->find<T>(_aliases->apply(join(_name, name)));
587 }
588 
590  return SubSchema(_impl, _aliases, join(_name, name));
591 }
592 
593 std::set<std::string> SubSchema::getNames(bool topOnly) const { return _impl->getNames(topOnly, _name); }
594 
595 //-----------------------------------------------------------------------------------------------------------
596 //----- Explicit instantiation ------------------------------------------------------------------------------
597 //-----------------------------------------------------------------------------------------------------------
598 
599 // Note: by instantiating the public functions below, we also instantiate a lot of the private
600 // implementation functions. If you move some of those to a different source file, you'll need
601 // more explicit instantiation.
602 
603 #define INSTANTIATE_LAYOUT(r, data, elem) \
604  template Key<elem> Schema::addField(Field<elem> const &, bool); \
605  template SchemaItem<elem> Schema::find(std::string const &) const; \
606  template SchemaItem<elem> Schema::find(Key<elem> const &) const; \
607  template SchemaItem<elem> detail::SchemaImpl::find(std::string const &name) const; \
608  template int Schema::contains(SchemaItem<elem> const &, int) const; \
609  template void Schema::replaceField(Key<elem> const &, Field<elem> const &); \
610  template SchemaItem<elem> SubSchema::find(std::string const &) const;
611 
613  BOOST_PP_TUPLE_TO_SEQ(AFW_TABLE_FIELD_TYPE_N, AFW_TABLE_FIELD_TYPE_TUPLE))
614 } // namespace table
615 } // namespace afw
616 } // 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:603
std::ostream * os
Definition: Schema.cc:558
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
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:421
void disconnectAliases()
Sever the connection between this schema and any others with which it shares aliases.
Definition: Schema.cc:541
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:453
void setAliasMap(std::shared_ptr< AliasMap > aliases)
Set the alias map.
Definition: Schema.cc:534
std::set< std::string > getNames(bool topOnly=false) const
Return a set of field names in the schema.
Definition: Schema.cc:465
static Schema fromFitsMetadata(daf::base::PropertyList &header, bool stripMetadata=true)
Construct from reading a FITS header.
Definition: Schema.cc:449
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:480
static Schema readFits(std::string const &filename, int hdu=fits::DEFAULT_HDU)
Construct from reading a FITS file.
Definition: Schema.cc:431
std::size_t hash_value() const noexcept
Return a hash of this object.
Definition: Schema.cc:521
int contains(Schema const &other, int flags=EQUAL_KEYS) const
Test whether the given schema is a subset of this.
Definition: Schema.cc:491
int compare(Schema const &other, int flags=EQUAL_KEYS) const
Do a detailed equality comparison of two schemas.
Definition: Schema.cc:510
void replaceField(Key< T > const &key, Field< T > const &field)
Replace the Field (name/description) for an existing Key.
Definition: Schema.cc:486
SchemaItem< T > find(std::string const &name) const
Find a SchemaItem in the Schema by name.
Definition: Schema.cc:468
@ 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:576
SubSchema operator[](std::string const &name) const
Return a nested proxy.
Definition: Schema.cc:589
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:593
SchemaItem< T > find(std::string const &name) const
Find a nested SchemaItem by name.
Definition: Schema.cc:585
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
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
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< 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.
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)
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)
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
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