7 #include "boost/preprocessor/seq/for_each.hpp"
8 #include "boost/preprocessor/tuple/to_seq.hpp"
27 inline char getDelimiter() {
return '_'; }
47 bool operator()(SchemaItem<T>
const &
a, SchemaItem<T>
const &
b)
const {
48 return a.key ==
b.key;
51 template <
typename T,
typename U>
52 bool operator()(SchemaItem<T>
const &
a, SchemaItem<U>
const &
b)
const {
58 static bool compareKeys(ItemVariant
const &
a, ItemVariant
const &
b) {
59 return std::visit(KeyHelper(),
a,
b);
62 static bool compareNames(ItemVariant
const &
a, ItemVariant
const &
b) {
64 [](
auto const &
a,
auto const &
b) {
return a.field.getName() ==
b.field.getName(); },
69 static bool compareDocs(ItemVariant
const &
a, ItemVariant
const &
b) {
71 [](
auto const &
a,
auto const &
b) {
return a.field.getDoc() ==
b.field.getDoc(); },
76 static bool compareUnits(ItemVariant
const &
a, ItemVariant
const &
b) {
78 [](
auto const &
a,
auto const &
b) {
return a.field.getUnits() ==
b.field.getUnits(); },
95 if (i != _names.
end() && i->first ==
name) {
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());
105 (boost::format(
"Field with name '%s' not found with type '%s'.") %
name %
110 template <
typename T>
113 if (i != _offsets.
end() && i->first == key.
getOffset()) {
115 return std::get<SchemaItem<T>>(_items[i->second]);
116 }
catch (std::bad_variant_access &err) {
121 (boost::format(
"Field or subfield with offset %d not found with type '%s'.") %
129 if (i != _flags.
end()) {
130 if (i->first.first == key.
getOffset() && i->first.second == key.
getBit()) {
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.") %
142 (boost::format(
"Flag field with offset %d and bit %d not found.") % key.
getOffset() %
156 template <
typename T>
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") %
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) {
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())
193 template <
typename T>
195 NameMap::iterator j = _names.
find(
field.getName());
197 if (j != _names.
end()) {
200 item = std::get_if<SchemaItem<T>>(&_items[j->second]);
201 if (!item || key != item->
key) {
204 (boost::format(
"Field with name '%s' already present in schema with a different key.") %
210 int index = findKey(_offsets, _flags, key);
211 item = std::get_if<SchemaItem<T>>(&_items[index]);
214 (boost::format(
"Incorrect key type '%s'.") % key).str());
225 template <
typename T>
229 "Can only check whether item is in schema if flags & EQUAL_KEYS");
232 int index = findKey(_offsets, _flags, item.
key,
false);
234 cmpItem = std::get_if<SchemaItem<T> >(&_items[index]);
237 flags &= ~
Schema::EQUAL_NAMES;
240 flags &= ~
Schema::EQUAL_DOCS;
243 flags &= ~
Schema::EQUAL_UNITS;
255 for (NameMap::const_iterator i = _names.
begin(); i != _names.
end(); ++i) {
257 if (sep == std::string::npos) {
260 result.
insert(result.
end(), i->first.substr(0, sep));
264 for (NameMap::const_iterator i = _names.
begin(); i != _names.
end(); ++i) {
277 if (sep == std::string::npos) {
294 template <
typename T>
296 if (
field.isVariableLength()) {
298 return addFieldImpl(
sizeof(ndarray::Array<T, 1, 1>), 1,
field, doReplace);
305 if (
field.isVariableLength()) {
314 template <
typename T>
323 if (!result.second) {
325 SchemaItem<Flag> *item = std::get_if<SchemaItem<Flag>>(&_items[result.first->second]);
329 (boost::format(
"Cannot replace field with name '%s' because types differ.") %
336 (boost::format(
"Cannot replace field with name '%s' because sizes differ.") %
345 (boost::format(
"Field with name '%s' already present in schema.") %
field.getName())
349 if (_lastFlagField < 0 || _lastFlagBit >= ELEMENT_SIZE * 8) {
350 int padding = ELEMENT_SIZE - _recordSize % ELEMENT_SIZE;
351 if (padding != ELEMENT_SIZE) {
352 _recordSize += padding;
354 _lastFlagField = _recordSize;
356 _recordSize +=
field.getElementCount() * ELEMENT_SIZE;
367 template <
typename T>
368 Key<T> SchemaImpl::addFieldImpl(
int elementSize,
int elementCount,
Field<T> const &
field,
bool doReplace) {
371 if (!result.second) {
373 SchemaItem<T> *item = std::get_if<SchemaItem<T>>(&_items[result.first->second]);
377 (boost::format(
"Cannot replace field with name '%s' because types differ.") %
384 if (item->
field.getElementCount() !=
field.getElementCount()) {
387 (boost::format(
"Cannot replace field with name '%s' because sizes differ.") %
396 (boost::format(
"Field with name '%s' already present in schema.") %
field.getName())
400 int padding = elementSize - _recordSize % elementSize;
401 if (padding != elementSize) {
402 _recordSize += padding;
405 _recordSize += elementCount * elementSize;
454 return afw::table::join(
a,
b, getDelimiter());
457 void Schema::_edit() {
458 if (!_impl.unique()) {
466 template <
typename T>
469 _aliases->_apply(tmp);
470 return _impl->find<T>(tmp);
473 template <
typename T>
475 return _impl->find(key);
478 template <
typename T>
481 return _impl->addField(
field, doReplace);
484 template <
typename T>
487 _impl->replaceField(key,
field);
491 if (_impl == other._impl)
return flags;
492 if (_impl->getItems().size() < other._impl->getItems().size())
return 0;
495 for (Impl::ItemContainer::const_iterator i1 = _impl->getItems().begin(),
496 i2 = other._impl->getItems().begin();
497 i2 != other._impl->getItems().end(); ++i1, ++i2) {
510 int result =
contains(other, flags);
511 if (_impl->getItems().size() != other._impl->getItems().size()) {
528 template <
typename T>
530 return _impl->contains(item, flags);
535 aliases = std::make_shared<AliasMap>();
548 typedef void result_type;
550 template <
typename T>
552 *
os <<
" (" << item.
field <<
", " << item.
key <<
"),\n";
566 os <<
" '" <<
iter->first <<
"'->'" <<
iter->second <<
"'\n";
577 return afw::table::join(
a,
b, getDelimiter());
581 : _impl(impl), _aliases(aliases), _name(
name) {}
583 template <
typename T>
585 return _impl->find<T>(_aliases->apply(
join(_name,
name)));
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;
table::Key< std::string > name
#define LSST_EXCEPT(type,...)
#define INSTANTIATE_LAYOUT(r, data, elem)
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
void readMetadata(daf::base::PropertySet &metadata, bool strip=false)
Read a FITS header into a PropertySet or PropertyList.
Lifetime-management for memory that goes into FITS memory files.
Mapping class that holds aliases for a Schema.
Tag types used to declare specialized field types.
Key specialization for Flag.
int getOffset() const
Return the offset in bytes of the integer element that holds this field's bit.
int getBit() const
The index of this field's bit within the integer it shares with other Flag fields.
A class used as a handle to a particular field in a table.
int getOffset() const noexcept
Return the offset (in bytes) of this field within a record.
Defines the fields and offsets for a table.
void forEach(F &func) const
Apply a functor to each SchemaItem in the Schema.
Schema()
Construct an empty Schema.
void disconnectAliases()
Sever the connection between this schema and any others with which it shares aliases.
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.
void setAliasMap(std::shared_ptr< AliasMap > aliases)
Set the alias map.
std::set< std::string > getNames(bool topOnly=false) const
Return a set of field names in the schema.
static Schema fromFitsMetadata(daf::base::PropertyList &header, bool stripMetadata=true)
Construct from reading a FITS header.
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
static Schema readFits(std::string const &filename, int hdu=fits::DEFAULT_HDU)
Construct from reading a FITS file.
std::size_t hash_value() const noexcept
Return a hash of this object.
int contains(Schema const &other, int flags=EQUAL_KEYS) const
Test whether the given schema is a subset of this.
int compare(Schema const &other, int flags=EQUAL_KEYS) const
Do a detailed equality comparison of two schemas.
void replaceField(Key< T > const &key, Field< T > const &field)
Replace the Field (name/description) for an existing Key.
SchemaItem< T > find(std::string const &name) const
Find a SchemaItem in the Schema by name.
@ EQUAL_DOCS
Fields have the same documentation (ordered).
@ EQUAL_NAMES
Fields have the same names (ordered).
@ EQUAL_UNITS
Fields have the same units (ordered).
@ EQUAL_KEYS
Keys have the same types offsets, and sizes.
@ EQUAL_FIELDS
Fields are identical (but aliases may not be).
@ EQUAL_ALIASES
Schemas have identical AliasMaps.
std::shared_ptr< AliasMap > getAliasMap() const
Return the map of aliases.
A proxy type for name lookups in a Schema.
std::string join(std::string const &a, std::string const &b) const
Join strings using the field delimiter appropriate for this Schema.
SubSchema operator[](std::string const &name) const
Return a nested proxy.
std::set< std::string > getNames(bool topOnly=false) const
Return a set of nested names that start with the SubSchema's prefix.
SchemaItem< T > find(std::string const &name) const
Find a nested SchemaItem by name.
static Key< T > makeKey(int offset)
A private implementation class to hide the messy details of Schema.
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.
std::set< std::string > getNames(bool topOnly) const
Return a set of field names (used to implement Schema::getNames).
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a field to the schema (used to implement Schema::addField).
int contains(SchemaItem< T > const &item, int flags) const
void replaceField(Key< T > const &key, Field< T > const &field)
Replace the Field in an existing SchemaItem without changing the Key.
SchemaItem< T > find(std::string const &name) const
Find an item by name (used to implement Schema::find).
decltype(makeItemVariantType(FieldTypes{})) ItemVariant
A Boost.Variant type that can hold any one of the allowed SchemaItem types.
std::map< int, int > OffsetMap
A map from standard field offsets to position in the vector, so we can do field lookups.
std::ostream & operator<<(std::ostream &os, BaseRecord const &record)
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.
int getElementCount() const
Return the number of subfield elements (always one for scalars).
A description of a field in a table.
FieldBase< T >::Element Element
Type used to store field data in the table (a field may have multiple elements).
A simple pair-like struct for mapping a Field (name and description) with a Key (used for actual data...
#define AFW_TABLE_FIELD_TYPE_N
#define AFW_TABLE_FIELD_TYPE_TUPLE