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 std::size_t 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");
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 (
auto const &_name : _names) {
257 if (sep == std::string::npos) {
258 result.
insert(result.
end(), _name.first);
264 for (
auto const &_name : _names) {
265 result.
insert(result.
end(), _name.first);
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 (!_initFlag || _lastFlagBit >= ELEMENT_SIZE * 8) {
350 std::size_t padding = ELEMENT_SIZE - _recordSize % ELEMENT_SIZE;
351 if (padding != ELEMENT_SIZE) {
352 _recordSize += padding;
354 _lastFlagField = _recordSize;
357 _recordSize +=
field.getElementCount() * ELEMENT_SIZE;
368 template <
typename T>
372 if (!result.second) {
374 SchemaItem<T> *item = std::get_if<SchemaItem<T>>(&_items[result.first->second]);
378 (boost::format(
"Cannot replace field with name '%s' because types differ.") %
385 if (item->
field.getElementCount() !=
field.getElementCount()) {
388 (boost::format(
"Cannot replace field with name '%s' because sizes differ.") %
397 (boost::format(
"Field with name '%s' already present in schema.") %
field.getName())
401 std::size_t padding = elementSize - _recordSize % elementSize;
402 if (padding != elementSize) {
403 _recordSize += padding;
406 _recordSize += elementCount * elementSize;
455 return afw::table::join(
a,
b, getDelimiter());
458 void Schema::_edit() {
459 if (!_impl.unique()) {
467 template <
typename T>
470 _aliases->_apply(tmp);
471 return _impl->find<T>(tmp);
474 template <
typename T>
476 return _impl->find(key);
479 template <
typename T>
482 return _impl->addField(
field, doReplace);
485 template <
typename T>
488 _impl->replaceField(key,
field);
492 if (_impl == other._impl)
return flags;
493 if (_impl->getItems().size() < other._impl->getItems().size())
return 0;
496 for (Impl::ItemContainer::const_iterator i1 = _impl->getItems().begin(),
497 i2 = other._impl->getItems().begin();
498 i2 != other._impl->getItems().end(); ++i1, ++i2) {
511 int result =
contains(other, flags);
512 if (_impl->getItems().size() != other._impl->getItems().size()) {
524 auto hasher = [&result](
auto const &item) { result = utils::hashCombine(result, item.
key); };
529 template <
typename T>
531 return _impl->contains(item, flags);
536 aliases = std::make_shared<AliasMap>();
549 using result_type = void;
551 template <
typename T>
553 *
os <<
" (" << item.
field <<
", " << item.
key <<
"),\n";
566 for (
auto const &
iter : *
schema.getAliasMap()) {
567 os <<
" '" <<
iter.first <<
"'->'" <<
iter.second <<
"'\n";
578 return afw::table::join(
a,
b, getDelimiter());
582 : _impl(impl), _aliases(aliases), _name(
name) {}
584 template <
typename T>
586 return _impl->find<T>(_aliases->apply(
join(_name,
name)));
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;
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.
std::size_t getBit() const
The index of this field's bit within the integer it shares with other Flag fields.
std::size_t getOffset() const
Return the offset in bytes of the integer element that holds this field's bit.
A class used as a handle to a particular field in a table.
std::size_t 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(std::size_t offset)
A private implementation class to hide the messy details of Schema.
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).
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.
decltype(makeItemVariantType(FieldTypes{})) ItemVariant
A Boost.Variant type that can hold any one of the allowed SchemaItem types.
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.
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
A base class for image defects.
std::size_t getElementCount() const
Return the number of subfield elements (always one for scalars).
A description of a field in a table.
typename 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