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 %
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.") %
141 (boost::format(
"Flag field with offset %d and bit %d not found.") % key.
getOffset() %
157 bool throwIfMissing =
true) {
158 SchemaImpl::OffsetMap::const_iterator i = offsets.
find(key.
getOffset());
159 if (i == offsets.
end()) {
160 if (throwIfMissing) {
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]);
200 if (!item || key != item->
key) {
203 (boost::format(
"Field with name '%s' already present in schema with a different key.") %
209 std::size_t index = findKey(_offsets, _flags, 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) {
263 for (
auto const &_name : _names) {
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()) {
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())
348 if (!_initFlag || _lastFlagBit >= ELEMENT_SIZE * 8) {
349 std::size_t padding = ELEMENT_SIZE - _recordSize % ELEMENT_SIZE;
350 if (padding != ELEMENT_SIZE) {
351 _recordSize += padding;
353 _lastFlagField = _recordSize;
356 _recordSize +=
field.getElementCount() * ELEMENT_SIZE;
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;
454 return afw::table::join(
a,
b, getDelimiter());
457void Schema::_edit() {
469 _aliases->_apply(tmp);
470 return _impl->
find<T>(tmp);
475 return _impl->
find(key);
491 if (_impl == other._impl)
return flags;
495 for (Impl::ItemContainer::const_iterator i1 = _impl->
getItems().
begin(),
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";
565 for (
auto const &iter : *
schema.getAliasMap()) {
566 os <<
" '" << iter.first <<
"'->'" << iter.second <<
"'\n";
577 return afw::table::join(
a,
b, getDelimiter());
581 : _impl(impl), _aliases(aliases), _name(
name) {}
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,...)
Create an exception with a given 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.
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::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.
ItemContainer const & getItems() const
Return the vector of SchemaItem variants.
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.
Class for storing ordered metadata with comments.
Reports invalid arguments.
Reports errors in the logical structure of the program.
Reports attempts to access elements using an invalid key.
Reports errors from accepting an object of an unexpected or inappropriate type.
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
Combine hashes.
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