6 #include "boost/mpl/and.hpp"
7 #include "boost/mpl/bool.hpp"
8 #include "boost/iterator/transform_iterator.hpp"
9 #include "boost/iterator/filter_iterator.hpp"
10 #include "boost/preprocessor/seq/for_each.hpp"
11 #include "boost/preprocessor/tuple/to_seq.hpp"
30 inline char getDelimiter() {
return '_'; }
47 struct KeyHelper :
public boost::static_visitor<bool> {
48 explicit KeyHelper(ItemVariant
const *other_) :
other(other_) {}
51 bool operator()(SchemaItem<T>
const &
a)
const {
52 SchemaItem<T>
const *
b = boost::get<SchemaItem<T> >(
other);
53 return (
b) &&
a.key ==
b->key;
60 struct NameHelper :
public boost::static_visitor<std::string const &> {
62 std::string const &operator()(SchemaItem<T>
const &
a)
const {
63 return a.field.getName();
68 struct DocHelper :
public boost::static_visitor<std::string const &> {
70 std::string const &operator()(SchemaItem<T>
const &
a)
const {
71 return a.field.getDoc();
76 struct UnitsHelper :
public boost::static_visitor<std::string const &> {
78 std::string const &operator()(SchemaItem<T>
const &
a)
const {
79 return a.field.getUnits();
84 static bool compareKeys(ItemVariant
const &
a, ItemVariant
const &
b) {
85 return boost::apply_visitor(KeyHelper(&
b),
a);
88 static bool compareNames(ItemVariant
const &
a, ItemVariant
const &
b) {
89 return boost::apply_visitor(NameHelper(),
a) == boost::apply_visitor(NameHelper(),
b);
92 static bool compareDocs(ItemVariant
const &
a, ItemVariant
const &
b) {
93 return boost::apply_visitor(DocHelper(),
a) == boost::apply_visitor(DocHelper(),
b);
96 static bool compareUnits(ItemVariant
const &
a, ItemVariant
const &
b) {
97 return boost::apply_visitor(UnitsHelper(),
a) == boost::apply_visitor(UnitsHelper(),
b);
118 template <
typename T>
119 inline int findNamedSubfield(
123 if (
name.
size() <= item.field.getName().size())
return -1;
126 name.
compare(0, item.field.getName().size(), item.field.getName()) == 0 &&
128 int const position = item.field.getName().size() + 1;
129 int const size =
name.
size() - position;
130 int const nElements = item.field.getElementCount();
131 for (
int i = 0; i < nElements; ++i) {
132 if (
name.
compare(position, size, Key<T>::subfields[i]) == 0) {
142 template <
typename T>
143 inline int findNamedSubfield(
152 template <
typename T,
typename U>
153 inline void makeSubfieldItem(
158 Field<U>(join(item.field.getName(), Key<T>::subfields[index],
delimiter),
159 item.field.getDoc(), item.field.getUnits())));
163 template <
typename T,
typename U>
164 inline void makeSubfieldItem(
173 template <
typename U>
174 struct ExtractItemByName :
public boost::static_visitor<> {
175 explicit ExtractItemByName(
std::string const &name_,
char delimiter_)
178 template <
typename T>
179 void operator()(SchemaItem<T>
const &item)
const {
184 typedef typename boost::mpl::and_<std::is_same<U, typename Field<T>::Element>,
185 boost::mpl::bool_<KeyBase<T>::HAS_NAMED_SUBFIELDS> >
::type
188 int n = findNamedSubfield(item,
name,
delimiter, (IsMatchPossible *)0);
190 if (n >= 0) makeSubfieldItem(item, n,
delimiter,
result, (IsMatchPossible *)0);
201 template <
typename T>
204 if (i != _names.
end()) {
205 if (i->first ==
name) {
208 return boost::get<SchemaItem<T>
const>(_items[i->second]);
209 }
catch (boost::bad_get &err) {
217 ExtractItemByName<T> extractor(
name, getDelimiter());
218 while (i != _names.
begin()) {
220 boost::apply_visitor(extractor, _items[i->second]);
221 if (extractor.result)
return *extractor.result;
224 (
boost::format(
"Field or subfield with name '%s' not found with type '%s'.") %
name %
238 template <
typename T,
typename U>
239 inline int findKeySubfield(
243 int n = (
key.getOffset() - item.
key.getOffset()) /
sizeof(U);
244 if (n >= 0 && n < item.
key.getElementCount()) {
252 template <
typename T,
typename U>
253 inline int findKeySubfield(
254 SchemaItem<T>
const &item, Key<U>
const &
key,
261 template <
typename U>
262 struct ExtractItemByKey :
public boost::static_visitor<> {
263 explicit ExtractItemByKey(Key<U>
const &key_,
char delimiter_) :
delimiter(delimiter_),
key(key_) {}
265 template <
typename T>
266 void operator()(SchemaItem<T>
const &item)
const {
270 typedef typename boost::mpl::and_<std::is_same<U, typename Field<T>::Element>,
271 boost::mpl::bool_<KeyBase<T>::HAS_NAMED_SUBFIELDS> >
::type
274 int n = findKeySubfield(item,
key, (IsMatchPossible *)0);
277 if (n >= 0) makeSubfieldItem(item, n,
delimiter,
result, (IsMatchPossible *)0);
288 template <
typename T>
290 OffsetMap::const_iterator i = _offsets.
lower_bound(
key.getOffset());
291 if (i != _offsets.
end()) {
292 if (i->first ==
key.getOffset()) {
294 return boost::get<SchemaItem<T>
const>(_items[i->second]);
295 }
catch (boost::bad_get &err) {
301 ExtractItemByKey<T> extractor(
key, getDelimiter());
302 while (i != _offsets.
begin()) {
304 boost::apply_visitor(extractor, _items[i->second]);
305 if (extractor.result)
return *extractor.result;
309 (
boost::format(
"Field or subfield with offset %d not found with type '%s'.") %
317 if (i != _flags.
end()) {
318 if (i->first.first ==
key.getOffset() && i->first.second ==
key.getBit()) {
320 return boost::get<SchemaItem<Flag>
const>(_items[i->second]);
321 }
catch (boost::bad_get &err) {
323 (
boost::format(
"Flag field with offset %d and bit %d not found.") %
324 key.getOffset() %
key.getBit())
331 (
boost::format(
"Flag field with offset %d and bit %d not found.") %
key.getOffset() %
345 template <
typename T>
347 bool throwIfMissing =
true) {
348 SchemaImpl::OffsetMap::const_iterator i = offsets.
find(
key.getOffset());
349 if (i == offsets.
end()) {
350 if (throwIfMissing) {
352 (
boost::format(
"Key of type %s with offset %d not found in Schema") %
364 Key<Flag>
const &
key,
bool throwIfMissing =
true) {
365 SchemaImpl::FlagMap::const_iterator i = flags.find(
std::make_pair(
key.getOffset(),
key.getBit()));
366 if (i == flags.end()) {
367 if (throwIfMissing) {
369 pex::exceptions::NotFoundError,
370 (
boost::format(
"Key of type Flag with offset %d and bit %d not found in Schema") %
371 key.getOffset() %
key.getBit())
382 template <
typename T>
384 NameMap::iterator j = _names.
find(
field.getName());
386 if (j != _names.
end()) {
389 item = boost::get<SchemaItem<T> >(&_items[j->second]);
390 if (!item ||
key != item->
key) {
393 (
boost::format(
"Field with name '%s' already present in schema with a different key.") %
399 int index = findKey(_offsets, _flags,
key);
400 item = boost::get<SchemaItem<T> >(&_items[index]);
414 template <
typename T>
418 "Can only check whether item is in schema if flags & EQUAL_KEYS");
421 int index = findKey(_offsets, _flags, item.
key,
false);
423 cmpItem = boost::get<SchemaItem<T> >(&_items[index]);
426 flags &= ~
Schema::EQUAL_NAMES;
429 flags &= ~
Schema::EQUAL_DOCS;
432 flags &= ~
Schema::EQUAL_UNITS;
444 for (NameMap::const_iterator i = _names.
begin(); i != _names.
end(); ++i) {
446 if (sep == std::string::npos) {
453 for (NameMap::const_iterator i = _names.
begin(); i != _names.
end(); ++i) {
466 if (sep == std::string::npos) {
483 template <
typename T>
485 if (
field.isVariableLength()) {
487 return addFieldImpl(
sizeof(ndarray::Array<T, 1, 1>), 1,
field, doReplace);
494 if (
field.isVariableLength()) {
503 template <
typename T>
518 (
boost::format(
"Cannot replace field with name '%s' because types differ.") %
525 (
boost::format(
"Cannot replace field with name '%s' because sizes differ.") %
538 if (_lastFlagField < 0 || _lastFlagBit >= ELEMENT_SIZE * 8) {
539 int padding = ELEMENT_SIZE - _recordSize % ELEMENT_SIZE;
540 if (padding != ELEMENT_SIZE) {
541 _recordSize += padding;
543 _lastFlagField = _recordSize;
545 _recordSize +=
field.getElementCount() * ELEMENT_SIZE;
556 template <
typename T>
557 Key<T> SchemaImpl::addFieldImpl(
int elementSize,
int elementCount,
Field<T> const &
field,
bool doReplace) {
566 (
boost::format(
"Cannot replace field with name '%s' because types differ.") %
573 if (item->
field.getElementCount() !=
field.getElementCount()) {
576 (
boost::format(
"Cannot replace field with name '%s' because sizes differ.") %
589 int padding = elementSize - _recordSize % elementSize;
590 if (padding != elementSize) {
591 _recordSize += padding;
594 _recordSize += elementCount * elementSize;
643 return afw::table::join(
a,
b, getDelimiter());
646 void Schema::_edit() {
647 if (!_impl.unique()) {
655 template <
typename T>
658 _aliases->_apply(tmp);
659 return _impl->find<T>(tmp);
662 template <
typename T>
664 return _impl->find(
key);
667 template <
typename T>
670 return _impl->addField(
field, doReplace);
673 template <
typename T>
680 if (_impl ==
other._impl)
return flags;
681 if (_impl->getItems().size() <
other._impl->getItems().size())
return 0;
684 for (Impl::ItemContainer::const_iterator i1 = _impl->getItems().begin(),
685 i2 =
other._impl->getItems().begin();
686 i2 !=
other._impl->getItems().end(); ++i1, ++i2) {
700 if (_impl->getItems().size() !=
other._impl->getItems().size()) {
717 template <
typename T>
719 return _impl->contains(item, flags);
724 aliases = std::make_shared<AliasMap>();
737 typedef void result_type;
739 template <
typename T>
741 *
os <<
" (" << item.
field <<
", " << item.
key <<
"),\n";
755 os <<
" '" <<
iter->first <<
"'->'" <<
iter->second <<
"'\n";
766 return afw::table::join(
a,
b, getDelimiter());
770 : _impl(impl), _aliases(aliases), _name(
name) {}
772 template <
typename T>
774 return _impl->find<T>(_aliases->apply(
join(_name,
name)));
791 #define INSTANTIATE_LAYOUT(r, data, elem) \
792 template Key<elem> Schema::addField(Field<elem> const &, bool); \
793 template SchemaItem<elem> Schema::find(std::string const &) const; \
794 template SchemaItem<elem> Schema::find(Key<elem> const &) const; \
795 template SchemaItem<elem> detail::SchemaImpl::find(std::string const &name) const; \
796 template int Schema::contains(SchemaItem<elem> const &, int) const; \
797 template void Schema::replaceField(Key<elem> const &, Field<elem> const &); \
798 template SchemaItem<elem> SubSchema::find(std::string const &) const;
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
ItemVariant const * other
#define INSTANTIATE_LAYOUT(r, data, elem)
std::unique_ptr< SchemaItem< U > > result
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.
Defines the fields and offsets for a table.
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.
void forEach(F &&func) const
Apply a functor to each SchemaItem in the Schema.
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< typename Key< T >::Element > extractElement(KeyBase< T > const &kb, int n)
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).
boost::make_variant_over< ItemTypes >::type 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.
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
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
std::size_t hashCombine(std::size_t seed) noexcept
Combine hashes.
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