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;