1 /**
2 * \file RMF/FileConstHandle.h
3 * \brief Handle read/write of Model data from/to files.
4 *
5 * Copyright 2007-2021 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 <boost/shared_ptr.hpp>
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"
27 #include "RMF/infrastructure_macros.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;
67 class NodeConstHandle;
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,
88 FileConstHandle);
89 friend RMFEXPORT bool get_equal_static_values(FileConstHandle,
90 FileConstHandle);
91 #endif
compare(const FileConstHandle & o)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 boost::shared_ptr<internal::SharedData> shared_;
103
104 public:
105 RMF_COMPARISONS(FileConstHandle);
106 RMF_HASHABLE(FileConstHandle, return boost::hash_value(get_name()););
107 RMF_SHOWABLE(FileConstHandle, get_name());
108 //! Empty root handle, no open file.
FileConstHandle()109 FileConstHandle() {}
110 #if !defined(RMF_DOXYGEN) && !defined(SWIG)
111 FileConstHandle(boost::shared_ptr<internal::SharedData> shared);
112 #endif
113
114 //! Return the root of the hierarchy
get_root_node()115 NodeConstHandle get_root_node() const {
116 return NodeConstHandle(NodeID(0), shared_);
117 }
118
get_name()119 std::string get_name() const { return shared_->get_file_name(); }
120
get_path()121 std::string get_path() const { return shared_->get_file_path(); }
122
123 /** \name Methods for manipulating keys
124 When using C++ it is most convenient to specify types
125 when adding and using keys through template arguments. For python
126 we provide non-template versions, below.
127 @{
128 */
129 /** Get an existing key that has the given name of the
130 given type or Key() if the key is not found.
131 */
132 template <class Tag>
get_key(Category category,std::string name)133 ID<Tag> get_key(Category category, std::string name) const {
134 try {
135 return shared_->get_key(category, name, Tag());
136 }
137 RMF_FILE_CATCH(<< Category(get_name(category)) << Key(name));
138 }
139
140 template <class Tag>
get_keys(Category category_id,const Strings & names)141 std::vector<ID<Tag> > get_keys(Category category_id,
142 const Strings& names) const {
143 try {
144 std::vector<ID<Tag> > ret(names.size());
145 for (unsigned int i = 0; i < names.size(); ++i) {
146 ret[i] = get_key<Tag>(category_id, names[i]);
147 if (ret[i] == ID<Tag>()) {
148 ret.clear();
149 return ret;
150 }
151 }
152 return ret;
153 }
154 RMF_FILE_CATCH(<< Category(get_name(category_id)));
155 }
156
157 /** Get a list of all keys of the given type,
158 */
159 template <class Tag>
get_keys(Category category)160 std::vector<ID<Tag> > get_keys(Category category) const {
161 try {
162 if (category == Category()) return std::vector<ID<Tag> >();
163 return shared_->get_keys(category, Tag());
164 }
165 RMF_FILE_CATCH(<< Category(get_name(category)));
166 }
167
168 template <class Tag>
get_key(Category category_id,std::string nm,Tag)169 ID<Tag> get_key(Category category_id, std::string nm, Tag) const {
170 return get_key<Tag>(category_id, nm);
171 }
172 template <class Tag>
get_name(ID<Tag> k)173 std::string get_name(ID<Tag> k) const {
174 try {
175 return shared_->get_name(k);
176 }
177 RMF_FILE_CATCH();
178 }
179 template <class Tag>
get_category(ID<Tag> k)180 Category get_category(ID<Tag> k) const {
181 return shared_->get_category(k);
182 }
183 /** This returns all the keys that are used in the current frame. \
184 Other frames may have different ones.*/
185 template <class Tag>
get_keys(Category category_id,Tag)186 std::vector<ID<Tag> > get_keys(Category category_id, Tag) {
187 return get_keys<Tag>(category_id);
188 }
189
190 /** @} */
191
192 /** The file always has a single frame that is currently active at any given
193 point.
194 @{
195 */
get_current_frame()196 FrameID get_current_frame() const { return shared_->get_loaded_frame(); }
get_type(FrameID fr)197 FrameType get_type(FrameID fr) const {
198 return shared_->get_frame_data(fr).type;
199 }
get_name(FrameID fr)200 std::string get_name(FrameID fr) const {
201 return shared_->get_frame_data(fr).name;
202 }
get_children(FrameID id)203 FrameIDs get_children(FrameID id) const {
204 const internal::FrameData& fd = shared_->get_frame_data(id);
205 return FrameIDs(fd.children.begin(), fd.children.end());
206 }
get_parents(FrameID id)207 FrameIDs get_parents(FrameID id) const {
208 const internal::FrameData& fd = shared_->get_frame_data(id);
209 return FrameIDs(fd.parents.begin(), fd.parents.end());
210 }
set_current_frame(FrameID frame)211 void set_current_frame(FrameID frame) const {
212 RMF_USAGE_CHECK(frame != FrameID(), "Invalid frame passed.");
213 RMF_USAGE_CHECK(frame != ALL_FRAMES,
214 "Use set_static_value() and get_static_value() to "
215 "manipulate the static frame.");
216 try {
217 shared_->set_loaded_frame(frame);
218 }
219 RMF_FILE_CATCH(<< Frame(frame));
220 }
221
222 /** Return the number of frames in the file.
223 */
get_number_of_frames()224 unsigned int get_number_of_frames() const {
225 try {
226 return shared_->get_number_of_frames();
227 }
228 RMF_FILE_CATCH();
229 }
230
231 /** Return the number of nodes in the file.
232 */
get_number_of_nodes()233 unsigned int get_number_of_nodes() const {
234 try {
235 return shared_->get_number_of_nodes();
236 }
237 RMF_FILE_CATCH();
238 }
239
240 /** Return a string identifying the file type.
241 */
get_file_type()242 std::string get_file_type() const { return shared_->get_file_type(); }
243
244 /** Get all the frames that are roots (aren't subframes). */
245 FrameIDs get_root_frames() const;
246
247 #ifndef SWIG
get_frames()248 boost::iterator_range<internal::integer_iterator<FrameID> > get_frames()
249 const {
250 return internal::get_frames(shared_.get());
251 }
252
get_node_ids()253 boost::iterator_range<internal::integer_iterator<NodeID> > get_node_ids()
254 const {
255 return internal::get_nodes(shared_.get());
256 }
257 #endif
258
259 /** \name Non-template versions for python
260
261 @{
262 */
263
264 RMF_FOREACH_TYPE(RMF_HDF5_ROOT_CONST_KEY_TYPE_METHODS);
265
266 /** @} */
267 #ifdef RMF_DOXYGEN
268 /** \name Python only
269 The following methods are only available in python.
270 @{
271 */
272 //! Return a list with all the keys from that category
273 PythonList get_keys(Category c) const;
274 /** @} */
275 #endif
276 #ifndef SWIG
277 /** Each node in the hierarchy can be associated with some arbitrary bit
278 of external data. Nodes can be extracted using
279 these bits of data.
280 */
281 template <class T>
get_node_from_association(const T & d)282 NodeConstHandle get_node_from_association(const T& d) const {
283 if (!shared_->get_has_associated_node(d)) {
284 return NodeConstHandle();
285 } else {
286 return NodeConstHandle(shared_->get_associated_node(d), shared_);
287 }
288 }
289 #else
290 NodeConstHandle get_node_from_association(void* v) const;
291 #endif
292 NodeConstHandle get_node(NodeID id) const;
293
294 /** Along with the associations for nodes, arbitrary data can
295 be associated with the file in memory to aid in processing.
296 */
297 template <class T>
add_associated_data(int index,const T & t)298 void add_associated_data(int index, const T& t) {
299 shared_->set_user_data(index, t);
300 }
301 /** To get back the ith user data.*/
302 template <class T>
get_associated_data(int index)303 T get_associated_data(int index) {
304 return shared_->get_user_data<T>(index);
305 }
306
307 /** To get back the ith user data.*/
get_has_associated_data(int index)308 bool get_has_associated_data(int index) {
309 return shared_->get_has_user_data(index);
310 }
311
312 /** Each RMF structure has an associated description. This should
313 consist of unstructured text describing the contents of the RMF
314 data. Conventionally. this description can consist of multiple
315 paragraphs, each separated by a newline character and should end
316 in a newline.
317 */
318 std::string get_description() const;
319
320 /** Each RMF structure has an associated field that the code that
321 produced the file can use to describe itself.
322 */
323 std::string get_producer() const;
324
325 /** \name Key categories methods
326 Methods for managing the key categories in this RMF.
327 @{
328 */
get_category(std::string name)329 Category get_category(std::string name) {
330 try {
331 return shared_->get_category(name);
332 }
333 RMF_FILE_CATCH(<< Category(name));
334 }
335 /** This returns all the categories that are used in the current frame.
336 Other frames may have different ones.*/
get_categories()337 Categories get_categories() const {
338 try {
339 return shared_->get_categories();
340 }
341 RMF_FILE_CATCH();
342 }
get_name(Category kc)343 std::string get_name(Category kc) const {
344 try {
345 return shared_->get_name(kc);
346 }
347 RMF_FILE_CATCH();
348 }
349 /** @} */
350
351 //! Reread the file.
352 /** \note This may invalidate various things (e.g. the number of nodes may
353 vary). Be careful.
354 */
355 void reload();
356 };
357
358 //! Produce hash values for boost hash tables.
hash_value(const FileConstHandle & t)359 inline std::size_t hash_value(const FileConstHandle& t) {
360 return t.__hash__();
361 }
362
363 /**
364 Open an RMF from a file system path in read-only mode.
365
366 \param path the system path to the rmf file
367 \exception RMF::IOException couldn't open file, or unsupported file format
368 */
369 RMFEXPORT FileConstHandle open_rmf_file_read_only(std::string path);
370
371 /**
372 Open an RMF from a buffer in read-only mode.
373
374 \exception RMF::IOException couldn't open file, or unsupported file format
375 */
376 RMFEXPORT FileConstHandle open_rmf_buffer_read_only(BufferConstHandle buffer);
377
378 /** \name Batch data access
379 These methods provide batch access to attribute data to try
380 to reduce the overhead of repeated function calls.
381
382 The missing_value argument is a placeholder that can fill in
383 for values which are not found in the respective node.
384
385 \note These methods are experimental and subject to change.
386 @{
387 */
388 RMFEXPORT Floats
389 get_values(const NodeConstHandles& nodes, FloatKey k,
390 Float missing_value = std::numeric_limits<float>::max());
391 /** @} */
392
393 } /* namespace RMF */
394
395 RMF_DISABLE_WARNINGS
396
397 #endif /* RMF_FILE_CONST_HANDLE_H */
398