LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
BaseRecord.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 #include <iostream>
4 
5 #include "lsst/pex/exceptions.h"
8 
9 namespace lsst {
10 namespace afw {
11 namespace table {
12 
13 namespace {
14 
15 // A Schema Functor used to set floating point-fields to NaN and initialize variable-length arrays
16 // using placement new. All other fields are left alone, as they should already be zero.
17 struct RecordInitializer {
18  template <typename T>
19  static void fill(T *element, std::size_t size) {} // this matches all non-floating-point-element fields.
20 
21  static void fill(float *element, std::size_t size) {
23  }
24 
25  static void fill(double *element, std::size_t size) {
27  }
28 
29  static void fill(lsst::geom::Angle *element, std::size_t size) {
30  fill(reinterpret_cast<double *>(element), size);
31  }
32 
33  template <typename T>
34  void operator()(SchemaItem<T> const &item) const {
35  fill(reinterpret_cast<typename Field<T>::Element *>(data + item.key.getOffset()),
36  item.key.getElementCount());
37  }
38 
39  template <typename T>
40  void operator()(SchemaItem<Array<T> > const &item) const {
41  if (item.key.isVariableLength()) {
42  // Use placement new because the memory (for one ndarray) is already allocated
43  new (data + item.key.getOffset()) ndarray::Array<T, 1, 1>();
44  } else {
45  fill(reinterpret_cast<typename Field<T>::Element *>(data + item.key.getOffset()),
46  item.key.getElementCount());
47  }
48  }
49 
50  void operator()(SchemaItem<std::string> const &item) const {
51  if (item.key.isVariableLength()) {
52  // Use placement new because the memory (for one std::string) is already allocated
53  new (reinterpret_cast<std::string *>(data + item.key.getOffset())) std::string();
54  } else {
55  fill(reinterpret_cast<char *>(data + item.key.getOffset()), item.key.getElementCount());
56  }
57  }
58 
59  void operator()(SchemaItem<Flag> const &item) const {} // do nothing for Flag fields; already 0
60 
61  char *data;
62 };
63 
64 // A Schema::forEach and SchemaMapper::forEach functor that copies data from one record to another.
65 struct CopyValue {
66  template <typename U>
67  void operator()(Key<U> const& inputKey, Key<U> const& outputKey) const {
68  typename Field<U>::Element const* inputElem = _inputRecord->getElement(inputKey);
69  std::copy(inputElem, inputElem + inputKey.getElementCount(), _outputRecord->getElement(outputKey));
70  }
71 
72  template <typename U>
73  void operator()(Key<Array<U> > const& inputKey, Key<Array<U> > const& outputKey) const {
74  if (inputKey.isVariableLength() != outputKey.isVariableLength()) {
76  "At least one input array field is variable-length"
77  " and the correponding output is not, or vice-versa");
78  }
79  if (inputKey.isVariableLength()) {
80  ndarray::Array<U, 1, 1> value = ndarray::copy(_inputRecord->get(inputKey));
81  _outputRecord->set(outputKey, value);
82  return;
83  }
84  typename Field<U>::Element const* inputElem = _inputRecord->getElement(inputKey);
85  std::copy(inputElem, inputElem + inputKey.getElementCount(), _outputRecord->getElement(outputKey));
86  }
87 
88  void operator()(Key<std::string> const& inputKey, Key<std::string> const& outputKey) const {
89  if (inputKey.isVariableLength() != outputKey.isVariableLength()) {
91  "At least one input string field is variable-length "
92  "and the correponding output is not, or vice-versa");
93  }
94  if (inputKey.isVariableLength()) {
95  std::string value = _inputRecord->get(inputKey);
96  _outputRecord->set(outputKey, value);
97  return;
98  }
99  char const* inputElem = _inputRecord->getElement(inputKey);
100  std::copy(inputElem, inputElem + inputKey.getElementCount(), _outputRecord->getElement(outputKey));
101  }
102 
103  void operator()(Key<Flag> const& inputKey, Key<Flag> const& outputKey) const {
104  _outputRecord->set(outputKey, _inputRecord->get(inputKey));
105  }
106 
107  template <typename U>
108  void operator()(SchemaItem<U> const& item) const {
109  (*this)(item.key, item.key);
110  }
111 
112  CopyValue(BaseRecord const* inputRecord, BaseRecord* outputRecord)
113  : _inputRecord(inputRecord), _outputRecord(outputRecord) {}
114 
115 private:
116  BaseRecord const* _inputRecord;
117  BaseRecord* _outputRecord;
118 };
119 
120 } // namespace
121 
122 void BaseRecord::assign(BaseRecord const& other) {
123  if (this->getSchema() != other.getSchema()) {
124  throw LSST_EXCEPT(lsst::pex::exceptions::LogicError, "Unequal schemas in record assignment.");
125  }
126  this->getSchema().forEach(CopyValue(&other, this));
127  this->_assign(other); // let derived classes assign their own stuff
128 }
129 
130 void BaseRecord::assign(BaseRecord const& other, SchemaMapper const& mapper) {
131  if (!other.getSchema().contains(mapper.getInputSchema())) {
133  "Unequal schemas between input record and mapper.");
134  }
135  if (!this->getSchema().contains(mapper.getOutputSchema())) {
137  "Unequal schemas between output record and mapper.");
138  }
139  mapper.forEach(CopyValue(&other, this)); // use the functor we defined above
140  this->_assign(other); // let derived classes assign their own stuff
141 }
142 
144  _data(std::move(data.data)),
145  _table(std::move(data.table)),
146  _manager(std::move(data.manager))
147 {
148  RecordInitializer f = {reinterpret_cast<char *>(_data)};
149  _table->getSchema().forEach(f);
150 }
151 
153  getSchema().forEach([&os, this](auto const& item) {
154  os << item.field.getName() << ": " << this->get(item.key) << std::endl;
155  });
156 }
157 
159  record._stream(os);
160  return os;
161 }
162 
163 } // namespace table
164 } // namespace afw
165 } // namespace lsst
char * data
Definition: BaseRecord.cc:61
double element[2]
Definition: BaseTable.cc:90
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
std::ostream * os
Definition: Schema.cc:557
SchemaMapper * mapper
Definition: SchemaMapper.cc:71
Base class for all records.
Definition: BaseRecord.h:31
void assign(BaseRecord const &other)
Copy all field values from other to this, requiring that they have equal schemas.
Definition: BaseRecord.cc:122
Schema getSchema() const
Return the Schema that holds this record's fields and keys.
Definition: BaseRecord.h:80
BaseRecord(ConstructionToken const &, detail::RecordData &&data)
Construct a record with uninitialized data.
Definition: BaseRecord.cc:143
Field< T >::Value get(Key< T > const &key) const
Return the value of a field for the given key.
Definition: BaseRecord.h:151
virtual void _assign(BaseRecord const &other)
Called by assign() after transferring fields to allow subclass data members to be copied.
Definition: BaseRecord.h:209
virtual void _stream(std::ostream &os) const
Called by operator<<.
Definition: BaseRecord.cc:152
void forEach(F &func) const
Apply a functor to each SchemaItem in the Schema.
Definition: Schema.h:214
int contains(Schema const &other, int flags=EQUAL_KEYS) const
Test whether the given schema is a subset of this.
Definition: Schema.cc:490
A mapping between the keys of two Schemas, used to copy data between them.
Definition: SchemaMapper.h:21
Schema const getOutputSchema() const
Return the output schema (copy-on-write).
Definition: SchemaMapper.h:27
A class representing an angle.
Definition: Angle.h:127
Reports invalid arguments.
Definition: Runtime.h:66
Reports errors in the logical structure of the program.
Definition: Runtime.h:46
T copy(T... args)
T endl(T... args)
T fill(T... args)
std::ostream & operator<<(std::ostream &os, BaseRecord const &record)
Definition: BaseRecord.cc:158
A base class for image defects.
STL namespace.
typename FieldBase< T >::Element Element
Type used to store field data in the table (a field may have multiple elements).
Definition: Field.h:26
Helper struct that contains the information passed from BaseTable to BaseRecord at construction.
Definition: BaseTable.h:32