RMF
FileConstHandle.h
Go to the documentation of this file.
1 /**
2  * \file RMF/FileConstHandle.h
3  * \brief Handle read/write of Model data from/to files.
4  *
5  * Copyright 2007-2022 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef RMF_FILE_CONST_HANDLE_H
10 #define RMF_FILE_CONST_HANDLE_H
11 
12 #include <boost/current_function.hpp>
13 #include <boost/functional/hash.hpp>
14 #include <memory>
15 #include <iosfwd>
16 #include <limits>
17 #include <string>
18 #include <vector>
19 
20 #include "BufferHandle.h"
21 #include "NodeConstHandle.h"
22 #include "RMF/ID.h"
23 #include "RMF/config.h"
24 #include "RMF/constants.h"
25 #include "RMF/enums.h"
26 #include "RMF/exceptions.h"
28 #include "RMF/internal/SharedData.h"
29 #include "RMF/internal/errors.h"
30 #include "RMF/internal/shared_data_ranges.h"
31 #include "internal/SharedData.h"
32 #include "internal/shared_data_ranges.h"
33 #include "types.h"
34 
35 namespace RMF {
36 class BufferConstHandle;
37 class FileConstHandle;
38 } // namespace RMF
39 
40 RMF_ENABLE_WARNINGS
41 
42 #define RMF_FILE_CATCH(extra_info) \
43  catch (Exception& e) { \
44  RMF_RETHROW( \
45  File(get_path()) << Frame(get_current_frame()) \
46  << Operation(BOOST_CURRENT_FUNCTION) extra_info, \
47  e); \
48  }
49 
50 #ifndef SWIG
51 #define RMF_HDF5_ROOT_CONST_KEY_TYPE_METHODS(Traits, UCName)
52 #else
53 #define RMF_HDF5_ROOT_CONST_KEY_TYPE_METHODS(Traits, UCName) \
54  UCName##Key get_key(Category category_id, std::string nm, \
55  UCName##Tag) const; \
56  std::string get_name(UCName##Key k) const; \
57  Category get_category(UCName##Key k) const; \
58  /** This returns all the keys that are used in the current frame. \
59  Other frames may have different ones.*/ \
60  UCName##Key##s get_keys(Category category_id, UCName##Tag);
61 #endif
62 
63 namespace RMF {
64 
65 class FileConstHandle;
66 class FileHandle;
68 
69 //! Pass a list of them
70 typedef std::vector<FileConstHandle> FileConstHandles;
71 
72 //! A handle for a read-only RMF file
73 /** Use this handle to perform operations relevant to the
74  whole RMF hierarchy as well as to start traversal of the
75  hierarchy.
76  \see open_rmf_file_read_only
77  */
78 class RMFEXPORT FileConstHandle {
79  void gather_ids(NodeConstHandle n, Ints& ids, std::vector<std::string>& paths,
80  std::string path) const;
81 #ifndef SWIG
82  friend class RMFEXPORT NodeConstHandle;
83  friend RMFEXPORT void clone_file_info(FileConstHandle, FileHandle);
84  friend RMFEXPORT void clone_hierarchy(FileConstHandle, FileHandle);
85  friend RMFEXPORT void clone_static_frame(FileConstHandle, FileHandle);
86  friend RMFEXPORT void clone_loaded_frame(FileConstHandle, FileHandle);
87  friend RMFEXPORT bool get_equal_current_values(FileConstHandle,
89  friend RMFEXPORT bool get_equal_static_values(FileConstHandle,
91 #endif
92  int compare(const FileConstHandle& o) const {
93  if (get_name() < o.get_name())
94  return -1;
95  else if (get_name() > o.get_name())
96  return 1;
97  else
98  return 0;
99  }
100 
101  protected:
102  std::shared_ptr<internal::SharedData> shared_;
103 
104  public:
106  RMF_HASHABLE(FileConstHandle, return boost::hash_value(get_name()););
107  RMF_SHOWABLE(FileConstHandle, get_name());
108  //! Empty root handle, no open file.
110 #if !defined(RMF_DOXYGEN) && !defined(SWIG)
111  FileConstHandle(std::shared_ptr<internal::SharedData> shared);
112 #endif
113 
114  //! Return the root of the hierarchy
115  NodeConstHandle get_root_node() const {
116  RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file.");
117  return NodeConstHandle(NodeID(0), shared_);
118  }
119 
120  //! Return True iff the file is closed
121  bool get_is_closed() const {
122  return !shared_;
123  }
124 
125  //! Explicitly close the file handle.
126  /** Normally, an RMF file is automatically closed when this handle object
127  goes out of scope. If closed with this method, any further operations
128  on this handle will raise an error.
129  Trying to close a file that is already closed will do nothing. */
130  void close() {
131  if (!get_is_closed()) {
132  shared_.reset();
133  }
134  }
135 
136  std::string get_name() const {
137  if (shared_) {
138  return shared_->get_file_name();
139  } else {
140  return "(closed RMF file handle)";
141  }
142  }
143 
144  std::string get_path() const {
145  RMF_USAGE_CHECK(!get_is_closed(), "File is closed, no path.");
146  return shared_->get_file_path();
147  }
148 
149  /** \name Methods for manipulating keys
150  When using C++ it is most convenient to specify types
151  when adding and using keys through template arguments. For python
152  we provide non-template versions, below.
153  @{
154  */
155  /** Get an existing key that has the given name of the
156  given type or Key() if the key is not found.
157  */
158  template <class Tag>
159  ID<Tag> get_key(Category category, std::string name) const {
160  try {
161  return shared_->get_key(category, name, Tag());
162  }
163  RMF_FILE_CATCH(<< Category(get_name(category)) << Key(name));
164  }
165 
166  template <class Tag>
167  std::vector<ID<Tag> > get_keys(Category category_id,
168  const Strings& names) const {
169  try {
170  std::vector<ID<Tag> > ret(names.size());
171  for (unsigned int i = 0; i < names.size(); ++i) {
172  ret[i] = get_key<Tag>(category_id, names[i]);
173  if (ret[i] == ID<Tag>()) {
174  ret.clear();
175  return ret;
176  }
177  }
178  return ret;
179  }
180  RMF_FILE_CATCH(<< Category(get_name(category_id)));
181  }
182 
183  /** Get a list of all keys of the given type,
184  */
185  template <class Tag>
186  std::vector<ID<Tag> > get_keys(Category category) const {
187  try {
188  if (category == Category()) return std::vector<ID<Tag> >();
189  return shared_->get_keys(category, Tag());
190  }
191  RMF_FILE_CATCH(<< Category(get_name(category)));
192  }
193 
194  template <class Tag>
195  ID<Tag> get_key(Category category_id, std::string nm, Tag) const {
196  return get_key<Tag>(category_id, nm);
197  }
198  template <class Tag>
199  std::string get_name(ID<Tag> k) const {
200  try {
201  return shared_->get_name(k);
202  }
203  RMF_FILE_CATCH();
204  }
205  template <class Tag>
206  Category get_category(ID<Tag> k) const {
207  return shared_->get_category(k);
208  }
209  /** This returns all the keys that are used in the current frame. \
210  Other frames may have different ones.*/
211  template <class Tag>
212  std::vector<ID<Tag> > get_keys(Category category_id, Tag) {
213  return get_keys<Tag>(category_id);
214  }
215 
216  /** @} */
217 
218  /** The file always has a single frame that is currently active at any given
219  point.
220  @{
221  */
223  RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file.");
224  return shared_->get_loaded_frame();
225  }
226 
227  FrameType get_type(FrameID fr) const {
228  RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file.");
229  return shared_->get_frame_data(fr).type;
230  }
231  std::string get_name(FrameID fr) const {
232  RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file.");
233  return shared_->get_frame_data(fr).name;
234  }
235  FrameIDs get_children(FrameID id) const {
236  RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file.");
237  const internal::FrameData& fd = shared_->get_frame_data(id);
238  return FrameIDs(fd.children.begin(), fd.children.end());
239  }
240  FrameIDs get_parents(FrameID id) const {
241  RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file.");
242  const internal::FrameData& fd = shared_->get_frame_data(id);
243  return FrameIDs(fd.parents.begin(), fd.parents.end());
244  }
245  void set_current_frame(FrameID frame) const {
246  RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file.");
247  RMF_USAGE_CHECK(frame != FrameID(), "Invalid frame passed.");
248  RMF_USAGE_CHECK(frame != ALL_FRAMES,
249  "Use set_static_value() and get_static_value() to "
250  "manipulate the static frame.");
251  try {
252  shared_->set_loaded_frame(frame);
253  }
254  RMF_FILE_CATCH(<< Frame(frame));
255  }
256 
257  /** Return the number of frames in the file.
258  */
259  unsigned int get_number_of_frames() const {
260  RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file.");
261  try {
262  return shared_->get_number_of_frames();
263  }
264  RMF_FILE_CATCH();
265  }
266 
267  /** Return the number of nodes in the file.
268  */
269  unsigned int get_number_of_nodes() const {
270  RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file.");
271  try {
272  return shared_->get_number_of_nodes();
273  }
274  RMF_FILE_CATCH();
275  }
276 
277  /** Return a string identifying the file type.
278  */
279  std::string get_file_type() const {
280  RMF_USAGE_CHECK(!get_is_closed(), "Operation on closed file.");
281  return shared_->get_file_type();
282  }
283 
284  /** Get all the frames that are roots (aren't subframes). */
285  FrameIDs get_root_frames() const;
286 
287 #ifndef SWIG
288  boost::iterator_range<internal::integer_iterator<FrameID> > get_frames()
289  const {
290  return internal::get_frames(shared_.get());
291  }
292 
293  boost::iterator_range<internal::integer_iterator<NodeID> > get_node_ids()
294  const {
295  return internal::get_nodes(shared_.get());
296  }
297 #endif
298 
299  /** \name Non-template versions for python
300 
301  @{
302  */
303 
304  RMF_FOREACH_TYPE(RMF_HDF5_ROOT_CONST_KEY_TYPE_METHODS);
305 
306 /** @} */
307 #ifdef RMF_DOXYGEN
308  /** \name Python only
309  The following methods are only available in python.
310  @{
311  */
312  //! Return a list with all the keys from that category
313  PythonList get_keys(Category c) const;
314 /** @} */
315 #endif
316 #ifndef SWIG
317  /** Each node in the hierarchy can be associated with some arbitrary bit
318  of external data. Nodes can be extracted using
319  these bits of data.
320  */
321  template <class T>
322  NodeConstHandle get_node_from_association(const T& d) const {
323  if (!shared_->get_has_associated_node(d)) {
324  return NodeConstHandle();
325  } else {
326  return NodeConstHandle(shared_->get_associated_node(d), shared_);
327  }
328  }
329 #else
330  NodeConstHandle get_node_from_association(void* v) const;
331 #endif
332  NodeConstHandle get_node(NodeID id) const;
333 
334  /** Along with the associations for nodes, arbitrary data can
335  be associated with the file in memory to aid in processing.
336  */
337  template <class T>
338  void add_associated_data(int index, const T& t) {
339  shared_->set_user_data(index, t);
340  }
341  /** To get back the ith user data.*/
342  template <class T>
343  T get_associated_data(int index) {
344  return shared_->get_user_data<T>(index);
345  }
346 
347  /** To get back the ith user data.*/
348  bool get_has_associated_data(int index) {
349  return shared_->get_has_user_data(index);
350  }
351 
352  /** Each RMF structure has an associated description. This should
353  consist of unstructured text describing the contents of the RMF
354  data. Conventionally. this description can consist of multiple
355  paragraphs, each separated by a newline character and should end
356  in a newline.
357  */
358  std::string get_description() const;
359 
360  /** Each RMF structure has an associated field that the code that
361  produced the file can use to describe itself.
362  */
363  std::string get_producer() const;
364 
365  /** \name Key categories methods
366  Methods for managing the key categories in this RMF.
367  @{
368  */
369  Category get_category(std::string name) {
370  try {
371  return shared_->get_category(name);
372  }
373  RMF_FILE_CATCH(<< Category(name));
374  }
375  /** This returns all the categories that are used in the current frame.
376  Other frames may have different ones.*/
378  try {
379  return shared_->get_categories();
380  }
381  RMF_FILE_CATCH();
382  }
383  std::string get_name(Category kc) const {
384  try {
385  return shared_->get_name(kc);
386  }
387  RMF_FILE_CATCH();
388  }
389  /** @} */
390 
391  //! Reread the file.
392  /** \note This may invalidate various things (e.g. the number of nodes may
393  vary). Be careful.
394  */
395  void reload();
396 };
397 
398 //! Produce hash values for boost hash tables.
399 inline std::size_t hash_value(const FileConstHandle& t) {
400  return t.__hash__();
401 }
402 
403 /**
404  Open an RMF from a file system path in read-only mode.
405 
406  \param path the system path to the rmf file
407  \exception RMF::IOException couldn't open file, or unsupported file format
408  */
409 RMFEXPORT FileConstHandle open_rmf_file_read_only(std::string path);
410 
411 /**
412  Open an RMF from a buffer in read-only mode.
413 
414  \exception RMF::IOException couldn't open file, or unsupported file format
415  */
416 RMFEXPORT FileConstHandle open_rmf_buffer_read_only(BufferConstHandle buffer);
417 
418 /** \name Batch data access
419  These methods provide batch access to attribute data to try
420  to reduce the overhead of repeated function calls.
421 
422  The missing_value argument is a placeholder that can fill in
423  for values which are not found in the respective node.
424 
425  \note These methods are experimental and subject to change.
426  @{
427  */
428 RMFEXPORT Floats
429  get_values(const NodeConstHandles& nodes, FloatKey k,
430  Float missing_value = std::numeric_limits<float>::max());
431 /** @} */
432 
433 } /* namespace RMF */
434 
435 RMF_DISABLE_WARNINGS
436 
437 #endif /* RMF_FILE_CONST_HANDLE_H */
std::vector< ID< Tag > > get_keys(Category category_id, Tag)
std::size_t hash_value(const FileConstHandle &t)
Produce hash values for boost hash tables.
FileConstHandle open_rmf_buffer_read_only(BufferConstHandle buffer)
Declaration of RMF::ID.
Default implementation for types.h.
float Float
Definition: types.h:33
void clone_static_frame(FileConstHandle input, FileHandle output)
Various constants.
FileConstHandle()
Empty root handle, no open file.
NodeConstHandle get_node_from_association(const T &d) const
void clone_hierarchy(FileConstHandle input, FileHandle output)
A handle for a particular node in a read-only hierarchy.
T get_associated_data(int index)
unsigned int get_number_of_frames() const
std::vector< Category > Categories
Definition: ID.h:117
ID< FrameTag > FrameID
Definition: ID.h:108
A handle for a read-only RMF file.
std::size_t hash_value(const BufferConstHandle &t)
Produce hash values for boost hash tables.
FrameID get_current_frame() const
FileConstHandle open_rmf_file_read_only(std::string path)
std::vector< FileConstHandle > FileConstHandles
Pass a list of them.
void clone_file_info(FileConstHandle input, FileHandle output)
void clone_loaded_frame(FileConstHandle input, FileHandle output)
A general purpose ID in RMF used, with different tags, to identify things.
Definition: ID.h:33
ID< CategoryTag > Category
Definition: ID.h:110
std::vector< String > Strings
Definition: types.h:41
Declarations of the various exception types.
std::vector< Int > Ints
Definition: types.h:31
Categories get_categories() const
A handle for an RMF file.
Definition: FileHandle.h:54
ID< NodeTag > NodeID
Definition: ID.h:106
#define RMF_COMPARISONS(Name)
Implement comparison in a class using field as the variable to compare.
Declaration of NodeConstHandle.
A strong enum with an associated string name for each value.
Definition: Enum.h:46
The various enums used in RMF.
unsigned int get_number_of_nodes() const
#define RMF_HASHABLE(name, hashret)
Implement a hash function for the class.
std::vector< NodeConstHandle > NodeConstHandles
Pass a list of them.
bool get_equal_current_values(FileConstHandle input, FileConstHandle out)
void add_associated_data(int index, const T &t)
NodeConstHandle get_root_node() const
Return the root of the hierarchy.
#define RMF_FOREACH_TYPE(macroname)
bool get_is_closed() const
Return True iff the file is closed.
std::vector< ID< Tag > > get_keys(Category category) const
std::vector< Float > Floats
Definition: types.h:35
void close()
Explicitly close the file handle.
ID< FloatTag > FloatKey
Definition: keys.h:41
ID< Tag > get_key(Category category, std::string name) const
std::vector< FrameID > FrameIDs
Definition: ID.h:115
Various general useful macros for IMP.
bool get_has_associated_data(int index)
bool get_equal_static_values(FileConstHandle input, FileConstHandle out)
static const FrameID ALL_FRAMES
Definition: constants.h:20
Declare RMF::BufferHandle.
std::string get_file_type() const