LSSTApplications  18.1.0
LSSTDataManagementBasePackage
SchemaMapper.cc
Go to the documentation of this file.
1 #include "boost/preprocessor/seq/for_each.hpp"
2 #include "boost/preprocessor/tuple/to_seq.hpp"
3 
6 
7 namespace lsst {
8 namespace afw {
9 namespace table {
10 
11 namespace {
12 
13 // Variant visitation functor used in SchemaMapper::invert()
14 struct SwapKeyPair : public boost::static_visitor<> {
15  template <typename T>
16  void operator()(std::pair<Key<T>, Key<T> > &pair) const {
17  std::swap(pair.first, pair.second);
18  }
19 
20  void operator()(detail::SchemaMapperImpl::KeyPairVariant &v) const { boost::apply_visitor(*this, v); }
21 };
22 
23 // Variant visitation functor that returns true if the input key in a KeyPairVariant matches a
24 // the Key the functor was initialized with.
25 template <typename T>
26 struct KeyPairCompareEqual : public boost::static_visitor<bool> {
27  template <typename U>
28  bool operator()(std::pair<Key<U>, Key<U> > const &pair) const {
29  return _target == pair.first;
30  }
31 
32  bool operator()(detail::SchemaMapperImpl::KeyPairVariant const &v) const {
33  return boost::apply_visitor(*this, v);
34  }
35 
36  KeyPairCompareEqual(Key<T> const &target) : _target(target) {}
37 
38 private:
39  Key<T> const &_target;
40 };
41 
42 // Functor used to iterate through a minimal schema and map all fields present in the
43 // input schema and add those that are not.
44 struct MapMinimalSchema {
45  template <typename U>
46  void operator()(SchemaItem<U> const &item) const {
47  Key<U> outputKey;
48  if (_doMap) {
49  try {
50  SchemaItem<U> inputItem = _mapper->getInputSchema().find(item.key);
51  outputKey = _mapper->addMapping(item.key);
52  } catch (pex::exceptions::NotFoundError &) {
53  outputKey = _mapper->addOutputField(item.field);
54  }
55  } else {
56  outputKey = _mapper->addOutputField(item.field);
57  }
58  assert(outputKey == item.key);
59  }
60 
61  explicit MapMinimalSchema(SchemaMapper *mapper, bool doMap) : _mapper(mapper), _doMap(doMap) {}
62 
63 private:
64  SchemaMapper *_mapper;
65  bool _doMap;
66 };
67 
68 // Schema::forEach functor that copies all fields from an schema to a schema mapper and maps them.
69 struct AddMapped {
70  template <typename T>
71  void operator()(SchemaItem<T> const &item) const {
72  Field<T> field(prefix + item.field.getName(), item.field.getDoc(), item.field.getUnits(), item.field);
73  mapper->addMapping(item.key, field);
74  }
75 
76  explicit AddMapped(SchemaMapper *mapper_) : mapper(mapper_) {}
77 
78  SchemaMapper *mapper;
80 };
81 
82 // Schema::forEach functor that copies all fields from an schema to a schema mapper without mapping them.
83 struct AddUnmapped {
84  template <typename T>
85  void operator()(SchemaItem<T> const &item) const {
86  Field<T> field(prefix + item.field.getName(), item.field.getDoc(), item.field.getUnits(), item.field);
87  mapper->addOutputField(field);
88  }
89 
90  explicit AddUnmapped(SchemaMapper *mapper_) : mapper(mapper_) {}
91 
92  SchemaMapper *mapper;
94 };
95 
96 struct RemoveMinimalSchema {
97  template <typename T>
98  void operator()(SchemaItem<T> const &item) const {
99  if (!minimal.contains(item)) {
100  mapper->addMapping(item.key);
101  }
102  }
103 
104  RemoveMinimalSchema(SchemaMapper *mapper_, Schema const &minimal_) : mapper(mapper_), minimal(minimal_) {}
105 
106  SchemaMapper *mapper;
107  Schema minimal;
108 };
109 
110 } // namespace
111 
113 
114 SchemaMapper::SchemaMapper(SchemaMapper const &other) : _impl(new Impl(*other._impl)) {}
115 // Delegate to copy constructor for backwards compatibility
117 
118 SchemaMapper::SchemaMapper(Schema const &input, Schema const &output) : _impl(new Impl(input, output)) {}
119 
120 SchemaMapper::SchemaMapper(Schema const &input, bool shareAliasMap) : _impl(new Impl(input, Schema())) {
121  if (shareAliasMap) {
123  }
124 }
125 
127  std::unique_ptr<Impl> tmp(new Impl(*other._impl));
128  _impl.swap(tmp);
129  return *this;
130 }
131 // Delegate to copy assignment for backwards compatibility
133 
134 SchemaMapper::~SchemaMapper() = default;
135 
136 template <typename T>
137 Key<T> SchemaMapper::addMapping(Key<T> const &inputKey, bool doReplace) {
138  typename Impl::KeyPairMap::iterator i =
139  std::find_if(_impl->_map.begin(), _impl->_map.end(), KeyPairCompareEqual<T>(inputKey));
140  Field<T> inputField = _impl->_input.find(inputKey).field;
141  if (i != _impl->_map.end()) {
142  Key<T> const &outputKey = boost::get<std::pair<Key<T>, Key<T> > >(*i).second;
143  _impl->_output.replaceField(outputKey, inputField);
144  return outputKey;
145  } else {
146  Key<T> outputKey = _impl->_output.addField(inputField, doReplace);
147  _impl->_map.insert(i, std::make_pair(inputKey, outputKey));
148  return outputKey;
149  }
150 }
151 
152 template <typename T>
153 Key<T> SchemaMapper::addMapping(Key<T> const &inputKey, Field<T> const &field, bool doReplace) {
154  typename Impl::KeyPairMap::iterator i =
155  std::find_if(_impl->_map.begin(), _impl->_map.end(), KeyPairCompareEqual<T>(inputKey));
156  if (i != _impl->_map.end()) {
157  Key<T> const &outputKey = boost::get<std::pair<Key<T>, Key<T> > >(*i).second;
158  _impl->_output.replaceField(outputKey, field);
159  return outputKey;
160  } else {
161  Key<T> outputKey = _impl->_output.addField(field, doReplace);
162  _impl->_map.insert(i, std::make_pair(inputKey, outputKey));
163  return outputKey;
164  }
165 }
166 
167 template <typename T>
168 Key<T> SchemaMapper::addMapping(Key<T> const &inputKey, std::string const &outputName, bool doReplace) {
169  typename Impl::KeyPairMap::iterator i =
170  std::find_if(_impl->_map.begin(), _impl->_map.end(), KeyPairCompareEqual<T>(inputKey));
171  if (i != _impl->_map.end()) {
172  Key<T> const &outputKey = boost::get<std::pair<Key<T>, Key<T> > >(*i).second;
173  Field<T> field = _impl->_output.find(outputKey).field;
174  field = field.copyRenamed(outputName);
175  _impl->_output.replaceField(outputKey, field);
176  return outputKey;
177  } else {
178  Field<T> inputField = _impl->_input.find(inputKey).field;
179  Field<T> outputField = inputField.copyRenamed(outputName);
180  Key<T> outputKey = _impl->_output.addField(outputField, doReplace);
181  _impl->_map.insert(i, std::make_pair(inputKey, outputKey));
182  return outputKey;
183  }
184 }
185 
187  if (getOutputSchema().getFieldCount() > 0) {
189  "Must add minimal schema to mapper before adding any other fields");
190  }
191  MapMinimalSchema f(this, doMap);
192  minimal.forEach(f);
193 }
194 
196  SchemaMapper mapper(input);
197  RemoveMinimalSchema f(&mapper, minimal);
198  input.forEach(f);
199  return mapper;
200 }
201 
203  std::swap(_impl->_input, _impl->_output);
204  std::for_each(_impl->_map.begin(), _impl->_map.end(), SwapKeyPair());
205 }
206 
207 template <typename T>
208 bool SchemaMapper::isMapped(Key<T> const &inputKey) const {
209  return std::count_if(_impl->_map.begin(), _impl->_map.end(), KeyPairCompareEqual<T>(inputKey));
210 }
211 
212 template <typename T>
213 Key<T> SchemaMapper::getMapping(Key<T> const &inputKey) const {
214  typename Impl::KeyPairMap::iterator i =
215  std::find_if(_impl->_map.begin(), _impl->_map.end(), KeyPairCompareEqual<T>(inputKey));
216  if (i == _impl->_map.end()) {
217  throw LSST_EXCEPT(lsst::pex::exceptions::NotFoundError, "Input Key is not mapped.");
218  }
219  return boost::get<std::pair<Key<T>, Key<T> > >(*i).second;
220 }
221 
223  std::vector<std::string> const &prefixes) {
224  std::size_t const size = inputs.size();
225  if (!prefixes.empty() && prefixes.size() != inputs.size()) {
226  throw LSST_EXCEPT(
228  (boost::format("prefix vector size (%d) must be the same as input vector size (%d)") %
229  prefixes.size() % inputs.size())
230  .str());
231  }
233  for (std::size_t i = 0; i < size; ++i) {
234  result.push_back(SchemaMapper(inputs[i]));
235  }
236  for (std::size_t i = 0; i < size; ++i) {
237  for (std::size_t j = 0; j < size; ++j) {
238  if (i == j) {
239  AddMapped functor(&result[j]);
240  if (!prefixes.empty()) functor.prefix = prefixes[i];
241  inputs[i].forEach(functor);
242  } else {
243  AddUnmapped functor(&result[j]);
244  if (!prefixes.empty()) functor.prefix = prefixes[i];
245  inputs[i].forEach(functor);
246  }
247  }
248  }
249  return result;
250 }
251 
252 //----- Explicit instantiation ------------------------------------------------------------------------------
253 
254 #define INSTANTIATE_LAYOUTMAPPER(r, data, elem) \
255  template Key<elem> SchemaMapper::addOutputField(Field<elem> const &, bool); \
256  template Key<elem> SchemaMapper::addMapping(Key<elem> const &, bool); \
257  template Key<elem> SchemaMapper::addMapping(Key<elem> const &, Field<elem> const &, bool); \
258  template Key<elem> SchemaMapper::addMapping(Key<elem> const &, std::string const &, bool); \
259  template bool SchemaMapper::isMapped(Key<elem> const &) const; \
260  template Key<elem> SchemaMapper::getMapping(Key<elem> const &) const;
261 
263  BOOST_PP_TUPLE_TO_SEQ(AFW_TABLE_FIELD_TYPE_N, AFW_TABLE_FIELD_TYPE_TUPLE))
264 } // namespace table
265 } // namespace afw
266 } // namespace lsst
SchemaMapper & operator=(SchemaMapper const &other)
Assignment (copy-on-write).
Defines the fields and offsets for a table.
Definition: Schema.h:50
void setAliasMap(std::shared_ptr< AliasMap > aliases)
Set the alias map.
Definition: Schema.cc:722
Key< T > getMapping(Key< T > const &inputKey) const
Return the output Key corresponding to the given input Key, or raise NotFoundError.
T empty(T... args)
SchemaMapper()
Construct an empty mapper; useless unless you assign a fully-constructed one to it.
table::Key< int > field
Definition: ApCorrMap.cc:77
T swap(T... args)
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:21
Reports attempts to exceed implementation-defined length limits for some classes. ...
Definition: Runtime.h:76
Schema const getOutputSchema() const
Return the output schema (copy-on-write).
Definition: SchemaMapper.h:27
py::object result
Definition: schema.cc:418
A private implementation class to hide the messy details of SchemaMapper.
T end(T... args)
std::string prefix
Definition: SchemaMapper.cc:79
#define AFW_TABLE_FIELD_TYPE_TUPLE
Definition: types.h:44
void forEach(F &&func) const
Apply a functor to each SchemaItem in the Schema.
Definition: Schema.h:212
STL class.
Reports attempts to access elements using an invalid key.
Definition: Runtime.h:151
static SchemaMapper removeMinimalSchema(Schema const &input, Schema const &minimal)
Create a mapper by removing fields from the front of a schema.
static std::vector< SchemaMapper > join(std::vector< Schema > const &inputs, std::vector< std::string > const &prefixes=std::vector< std::string >())
Combine a sequence of schemas into one, creating a SchemaMapper for each.
SchemaItem< T > find(std::string const &name) const
Find a SchemaItem in the Schema by name.
Definition: Schema.cc:656
A base class for image defects.
Field< T > copyRenamed(std::string const &newName) const
Return a new Field with a new name and other properties the same as this.
Definition: Field.h:89
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:168
A description of a field in a table.
Definition: Field.h:24
T make_pair(T... args)
bool isMapped(Key< T > const &inputKey) const
Return true if the given input Key is mapped to an output Key.
SchemaMapper _mapper
Definition: Exposure.cc:220
#define INSTANTIATE_LAYOUTMAPPER(r, data, elem)
Schema & editOutputSchema()
Return a reference to the output schema that allows it to be modified in place.
Definition: SchemaMapper.h:30
Reports errors in the logical structure of the program.
Definition: Runtime.h:46
Key< Flag > const & target
T count_if(T... args)
T insert(T... args)
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
T find_if(T... args)
T size(T... args)
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
STL class.
std::shared_ptr< AliasMap > getAliasMap() const
Return the map of aliases.
Definition: Schema.h:269
boost::make_variant_over< KeyPairTypes >::type KeyPairVariant
A Boost.Variant type that can hold any one of the allowed pair types.
A class used as a handle to a particular field in a table.
Definition: fwd.h:45
void addMinimalSchema(Schema const &minimal, bool doMap=true)
Add the given minimal schema to the output schema.
T begin(T... args)
void replaceField(Key< T > const &key, Field< T > const &field)
Replace the Field (name/description) for an existing Key.
Definition: Schema.cc:674
Schema minimal
ItemVariant const * other
Definition: Schema.cc:56
void invert()
Swap the input and output schemas in-place.
Key< T > addMapping(Key< T > const &inputKey, bool doReplace=false)
Add a new field to the output Schema that is a copy of a field in the input Schema.
T for_each(T... args)
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
Definition: Schema.cc:668
#define AFW_TABLE_FIELD_TYPE_N
Definition: types.h:39
SchemaMapper * mapper
Definition: SchemaMapper.cc:78