7#include "boost/preprocessor/seq/for_each.hpp"
8#include "boost/preprocessor/tuple/to_seq.hpp"
26inline char getDelimiter() {
return '_'; }
46 bool operator()(SchemaItem<T>
const &
a, SchemaItem<T>
const &
b)
const {
47 return a.key ==
b.key;
50 template <
typename T,
typename U>
51 bool operator()(SchemaItem<T>
const &
a, SchemaItem<U>
const &
b)
const {
57 static bool compareKeys(ItemVariant
const &
a, ItemVariant
const &
b) {
58 return std::visit(KeyHelper(),
a,
b);
61 static bool compareNames(ItemVariant
const &
a, ItemVariant
const &
b) {
63 [](
auto const &
a,
auto const &
b) {
return a.field.getName() ==
b.field.getName(); },
68 static bool compareDocs(ItemVariant
const &
a, ItemVariant
const &
b) {
70 [](
auto const &
a,
auto const &
b) {
return a.field.getDoc() ==
b.field.getDoc(); },
75 static bool compareUnits(ItemVariant
const &
a, ItemVariant
const &
b) {
77 [](
auto const &
a,
auto const &
b) {
return a.field.getUnits() ==
b.field.getUnits(); },
94 if (
i != _names.
end() &&
i->first ==
name) {
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());
104 (boost::format(
"Field with name '%s' not found with type '%s'.") %
name %
111 OffsetMap::const_iterator
i = _offsets.
lower_bound(key.getOffset());
112 if (
i != _offsets.
end() &&
i->first == key.getOffset()) {
114 return std::get<SchemaItem<T>>(_items[
i->second]);
115 }
catch (std::bad_variant_access &
err) {
120 (boost::format(
"Field or subfield with offset %d not found with type '%s'.") %
128 if (
i != _flags.
end()) {
129 if (
i->first.first == key.getOffset() &&
i->first.second == key.getBit()) {
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())
141 (boost::format(
"Flag field with offset %d and bit %d not found.") % key.getOffset() %
158 SchemaImpl::OffsetMap::const_iterator
i =
offsets.find(key.getOffset());
162 (boost::format(
"Key of type %s with offset %d not found in Schema") %
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) {
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())
194 NameMap::iterator
j = _names.
find(
field.getName());
196 if (
j != _names.
end()) {
199 item = std::get_if<SchemaItem<T>>(&_items[
j->second]);
203 (boost::format(
"Field with name '%s' already present in schema with a different key.") %
210 item = std::get_if<SchemaItem<T>>(&_items[index]);
213 (boost::format(
"Incorrect key type '%s'.") % key).str());
228 "Can only check whether item is in schema if flags & EQUAL_KEYS");
233 cmpItem = std::get_if<SchemaItem<T> >(&_items[index]);
254 for (
auto const &_name : _names) {
256 if (
sep == std::string::npos) {
257 result.
insert(result.
end(), _name.first);
263 for (
auto const &_name : _names) {
264 result.
insert(result.
end(), _name.first);
276 if (
sep == std::string::npos) {
295 if (
field.isVariableLength()) {
297 return addFieldImpl(
sizeof(ndarray::Array<T, 1, 1>), 1,
field, doReplace);
304 if (
field.isVariableLength()) {
322 if (!result.second) {
328 (boost::format(
"Cannot replace field with name '%s' because types differ.") %
332 if (
item->field.getElementCount() !=
field.getElementCount()) {
335 (boost::format(
"Cannot replace field with name '%s' because sizes differ.") %
344 (boost::format(
"Field with name '%s' already present in schema.") %
field.getName())
353 _lastFlagField = _recordSize;
371 if (!result.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 std::size_t padding = elementSize - _recordSize % elementSize;
401 if (padding != elementSize) {
402 _recordSize += padding;
405 _recordSize += elementCount * elementSize;
457void Schema::_edit() {
458 if (!_impl.unique()) {
469 _aliases->_apply(
tmp);
470 return _impl->find<T>(
tmp);
475 return _impl->find(key);
481 return _impl->addField(
field, doReplace);
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()) {
512 result &= ~EQUAL_FIELDS;
515 result &= ~EQUAL_ALIASES;
523 auto hasher = [&result](
auto const &
item) { result = utils::hashCombine(result,
item.key); };
530 return _impl->contains(
item, flags);
535 aliases = std::make_shared<AliasMap>();
548 using result_type =
void;
550 template <
typename T>
552 *os <<
" (" <<
item.field <<
", " <<
item.key <<
"),\n";
564 schema.forEach(Stream(&os));
565 for (
auto const &iter : *
schema.getAliasMap()) {
566 os <<
" '" << iter.first <<
"'->'" << iter.second <<
"'\n";
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...
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.
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::shared_ptr< AliasMap > getAliasMap() const
Return the map of aliases.
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.
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 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).
#define AFW_TABLE_FIELD_TYPE_N
#define AFW_TABLE_FIELD_TYPE_TUPLE