lsst.afw  22.0.0-22-gf1d71818e+db3b0def15
OutputArchive.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 #include <typeinfo>
4 #include <vector>
5 #include <map>
6 #include <memory>
7 
8 #include "boost/format.hpp"
9 
10 #include "lsst/pex/exceptions.h"
15 #include "lsst/afw/fits.h"
16 
17 namespace lsst {
18 namespace afw {
19 namespace table {
20 namespace io {
21 
22 namespace {
23 
24 ArchiveIndexSchema const &indexKeys = ArchiveIndexSchema::get();
25 
26 // we don't need sorting, but you can't use weak_ptrs as keys in an
27 // unordered_map
30 
31 typedef Map::value_type MapItem;
32 
33 } // namespace
34 
35 // ----- OutputArchive::Impl --------------------------------------------------------------------------------
36 
38 public:
40  int catArchive = 1;
41  CatalogVector::iterator iter = _catalogs.begin();
43  for (; iter != _catalogs.end(); ++iter, ++catArchive) {
44  if (iter->getSchema().compare(schema, flags) == flags) {
45  break;
46  }
47  }
48  if (iter == _catalogs.end()) {
50  }
51  if (!iter->getTable()->getMetadata()) {
53  iter->getTable()->setMetadata(metadata);
54  metadata->set("EXTTYPE", "ARCHIVE_DATA");
55  metadata->set("AR_CATN", catArchive, "# of this catalog relative to the start of this archive");
56  }
57  return BaseCatalog(iter->getTable());
58  }
59 
61  auto indexRecord = _index.addNew();
62  indexRecord->set(indexKeys.id, id);
63  indexRecord->set(indexKeys.name, name);
64  indexRecord->set(indexKeys.module, module);
65  return indexRecord;
66  }
67 
68  void saveEmpty(int id, std::string const &name, std::string const &module) {
69  auto indexRecord = addIndexRecord(id, name, module);
70  indexRecord->set(indexKeys.nRows, 0);
71  indexRecord->set(indexKeys.catPersistable, ArchiveIndexSchema::NO_CATALOGS_SAVED);
72  indexRecord->set(indexKeys.row0, ArchiveIndexSchema::NO_CATALOGS_SAVED);
73  indexRecord->set(indexKeys.catArchive, ArchiveIndexSchema::NO_CATALOGS_SAVED);
74  }
75 
76  void saveCatalog(BaseCatalog const &catalog, int id, std::string const &name, std::string const &module,
77  int catPersistable) {
78  auto indexRecord = addIndexRecord(id, name, module);
79  indexRecord->set(indexKeys.catPersistable, catPersistable);
80  indexRecord->set(indexKeys.nRows, catalog.size());
81  int catArchive = 1;
82  CatalogVector::iterator iter = _catalogs.begin();
83  for (; iter != _catalogs.end(); ++iter, ++catArchive) {
84  if (iter->getTable() == catalog.getTable()) {
85  break;
86  }
87  }
88  if (iter == _catalogs.end()) {
90  "All catalogs passed to saveCatalog must be created by makeCatalog");
91  }
92  // Add the name of the class to the header so anyone looking at it can
93  // tell what's stored there. But we don't want to add it multiple times.
94  try {
95  auto names = iter->getTable()->getMetadata()->getArray<std::string>("AR_NAME");
96  if (std::find(names.begin(), names.end(), name) == names.end()) {
97  iter->getTable()->getMetadata()->add("AR_NAME", name, "Class name for objects stored here");
98  }
99  } catch (pex::exceptions::NotFoundError &) {
100  iter->getTable()->getMetadata()->add("AR_NAME", name, "Class name for objects stored here");
101  }
102  // Also add an EXTNAME. The most recent AR_NAME given will be used.
103  iter->getTable()->getMetadata()->set("EXTNAME", name);
104  indexRecord->set(indexKeys.row0, iter->size());
105  indexRecord->set(indexKeys.catArchive, catArchive);
106  iter->insert(iter->end(), catalog.begin(), catalog.end(), false);
107  }
108 
109  int put(Persistable const *obj, std::shared_ptr<Impl> const &self, bool permissive) {
110  if (!obj) return 0;
111  if (permissive && !obj->isPersistable()) return 0;
112  int const currentId = _nextId;
113  ++_nextId;
114  OutputArchiveHandle handle(currentId, obj->getPersistenceName(), obj->getPythonModule(), self);
115  obj->write(handle);
116  return currentId;
117  }
118 
119  int put(std::shared_ptr<Persistable const> obj, std::shared_ptr<Impl> const &self, bool permissive) {
120  if (!obj) return 0;
121  if (permissive && !obj->isPersistable()) return 0;
122  MapItem item(obj, _nextId);
123  std::pair<Map::iterator, bool> r = _map.insert(item);
124  if (r.second) {
125  // We've never seen this object before. Save it.
126  return put(obj.get(), self, permissive);
127  } else {
128  // We had already saved this object, and insert returned an iterator
129  // to the ID we used before; return that.
130  return r.first->second;
131  }
132  }
133 
134  void writeFits(fits::Fits &fitsfile) {
135  _index.getTable()->getMetadata()->set("AR_NCAT", int(_catalogs.size() + 1),
136  "# of catalogs in this archive, including the index");
137  _index.writeFits(fitsfile);
138  int n = 1;
139  for (CatalogVector::const_iterator iter = _catalogs.begin(); iter != _catalogs.end(); ++iter, ++n) {
140  iter->writeFits(fitsfile);
141  }
142  }
143 
146  metadata->set("EXTTYPE", "ARCHIVE_INDEX");
147  metadata->set("EXTNAME", "ARCHIVE_INDEX");
148  metadata->set("AR_CATN", 0, "# of this catalog relative to the start of this archive");
149  _index.getTable()->setMetadata(metadata);
150  }
151 
152  int _nextId;
153  Map _map;
156 };
157 
158 // ----- OutputArchive --------------------------------------------------------------------------------------
159 
161 
162 OutputArchive::OutputArchive(OutputArchive const &other) : _impl(other._impl) {}
163 // Delegate to copy constructor for backward compatibility
165 
167  _impl = other._impl;
168  return *this;
169 }
170 // Delegate to copy assignment for backward compatibility
171 OutputArchive &OutputArchive::operator=(OutputArchive &&other) { return *this = other; }
172 
174 
175 int OutputArchive::put(Persistable const *obj, bool permissive) {
176  if (!_impl.unique()) { // copy on write
177  std::shared_ptr<Impl> tmp(new Impl(*_impl));
178  _impl.swap(tmp);
179  }
180  return _impl->put(obj, _impl, permissive);
181 }
182 
184  if (!_impl.unique()) { // copy on write
185  std::shared_ptr<Impl> tmp(new Impl(*_impl));
186  _impl.swap(tmp);
187  }
188  return _impl->put(std::move(obj), _impl, permissive);
189 }
190 
191 BaseCatalog const &OutputArchive::getIndexCatalog() const { return _impl->_index; }
192 
194  if (n == 0) return _impl->_index;
195  if (std::size_t(n) > _impl->_catalogs.size() || n < 0) {
196  throw LSST_EXCEPT(
198  (boost::format("Catalog number %d is out of range [0,%d]") % n % _impl->_catalogs.size())
199  .str());
200  }
201  return _impl->_catalogs[n - 1];
202 }
203 
204 int OutputArchive::countCatalogs() const { return _impl->_catalogs.size() + 1; }
205 
206 void OutputArchive::writeFits(fits::Fits &fitsfile) const { _impl->writeFits(fitsfile); }
207 
208 // ----- OutputArchiveHandle ------------------------------------------------------------------------------
209 
210 BaseCatalog OutputArchiveHandle::makeCatalog(Schema const &schema) { return _impl->makeCatalog(schema); }
211 
212 void OutputArchiveHandle::saveEmpty() { _impl->saveEmpty(_id, _name, _module); }
213 
215  _impl->saveCatalog(catalog, _id, _name, _module, _catPersistable);
216  ++_catPersistable;
217 }
218 
219 int OutputArchiveHandle::put(Persistable const *obj, bool permissive) {
220  // Handle doesn't worry about copy-on-write, because Handles should only exist
221  // while an OutputArchive::put() call is active.
222  return _impl->put(obj, _impl, permissive);
223 }
224 
226  // Handle doesn't worry about copy-on-write, because Handles should only exist
227  // while an OutputArchive::put() call is active.
228  return _impl->put(std::move(obj), _impl, permissive);
229 }
230 
233  : _id(id), _catPersistable(0), _name(name), _module(module), _impl(impl) {}
234 
236 } // namespace io
237 } // namespace table
238 } // namespace afw
239 } // namespace lsst
table::Key< std::string > name
Definition: Amplifier.cc:116
table::Key< int > id
Definition: Detector.cc:162
#define LSST_EXCEPT(type,...)
T begin(T... args)
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:297
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
Definition: Catalog.h:486
size_type size() const
Return the number of elements in the catalog.
Definition: Catalog.h:409
iterator begin()
Iterator access.
Definition: Catalog.h:397
std::shared_ptr< Table > getTable() const
Return the table associated with the catalog.
Definition: Catalog.h:115
void writeFits(std::string const &filename, std::string const &mode="w", int flags=0) const
Write a FITS binary table to a regular file.
Definition: Catalog.h:307
Defines the fields and offsets for a table.
Definition: Schema.h:51
@ EQUAL_NAMES
Fields have the same names (ordered).
Definition: Schema.h:67
@ EQUAL_KEYS
Keys have the same types offsets, and sizes.
Definition: Schema.h:66
A vector of catalogs used by Persistable.
Definition: CatalogVector.h:29
int put(Persistable const *obj, std::shared_ptr< Impl > const &self, bool permissive)
BaseCatalog makeCatalog(Schema const &schema)
int put(std::shared_ptr< Persistable const > obj, std::shared_ptr< Impl > const &self, bool permissive)
void writeFits(fits::Fits &fitsfile)
void saveEmpty(int id, std::string const &name, std::string const &module)
void saveCatalog(BaseCatalog const &catalog, int id, std::string const &name, std::string const &module, int catPersistable)
std::shared_ptr< BaseRecord > addIndexRecord(int id, std::string const &name, std::string const &module)
An object passed to Persistable::write to allow it to persist itself.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
OutputArchiveHandle(const OutputArchiveHandle &)=delete
void saveEmpty()
Indicate that the object being persisted has no state, and hence will never call makeCatalog() or sav...
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
int put(Persistable const *obj, bool permissive=false)
Save an object to the archive and return a unique ID that can be used to retrieve it from an InputArc...
A multi-catalog archive object used to save table::io::Persistable objects.
Definition: OutputArchive.h:34
int put(std::shared_ptr< Persistable const > obj, bool permissive=false)
Save an object to the archive and return a unique ID that can be used to retrieve it from an InputArc...
void writeFits(fits::Fits &fitsfile) const
Write the archive to an already-open FITS object.
BaseCatalog const & getCatalog(int n) const
Return the nth catalog. Catalog 0 is always the index catalog.
OutputArchive & operator=(OutputArchive const &other)
Assign from another OutputArchive. Saved objects are not deep-copied.
BaseCatalog const & getIndexCatalog() const
Return the index catalog that specifies where objects are stored in the data catalogs.
OutputArchive()
Construct an empty OutputArchive containing no objects.
int countCatalogs() const
Return the total number of catalogs, including the index.
A base class for objects that can be persisted via afw::table::io Archive classes.
Definition: Persistable.h:74
virtual bool isPersistable() const noexcept
Return true if this particular object can be persisted using afw::table::io.
Definition: Persistable.h:102
virtual std::string getPythonModule() const
Return the fully-qualified Python module that should be imported to guarantee that its factory is reg...
Definition: Persistable.cc:36
virtual std::string getPersistenceName() const
Return the unique name used to persist this object and look up its factory.
Definition: Persistable.cc:34
virtual void write(OutputArchiveHandle &handle) const
Write the object to one or more catalogs.
Definition: Persistable.cc:38
T end(T... args)
T find(T... args)
T get(T... args)
T insert(T... args)
T move(T... args)
def iter(self)
CatalogT< BaseRecord > BaseCatalog
Definition: fwd.h:71
A base class for image defects.
T size(T... args)
Schema for the index catalog that specifies where objects are stored in the data catalogs.
static constexpr int const NO_CATALOGS_SAVED
Special value used for catArchive, catPersistable, and row0 when an object with no state is saved.
static ArchiveIndexSchema const & get()
Return the singleton instance.
table::Schema schema
Definition: python.h:134