ALPSCore reference
archive.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1998-2018 ALPS Collaboration. See COPYRIGHT.TXT
3  * All rights reserved. Use is subject to license terms. See LICENSE.TXT
4  * For use in publications, see ACKNOWLEDGE.TXT
5  */
6 
7 #ifndef ALPS_HDF5_ARCHIVE_HPP
8 #define ALPS_HDF5_ARCHIVE_HPP
9 
10 #include <alps/hdf5/config.hpp>
12 #include <alps/hdf5/errors.hpp>
15 
16 #ifndef ALPS_SINGLE_THREAD
17 
18 #include <boost/thread.hpp>
19 
20 #endif
21 
22 #include <map>
23 #include <vector>
24 #include <string>
25 #include <type_traits>
26 #include <numeric>
27 
28 #define ALPS_FOREACH_NATIVE_HDF5_TYPE(CALLBACK) \
29  CALLBACK(char) \
30  CALLBACK(signed char) \
31  CALLBACK(unsigned char) \
32  CALLBACK(short) \
33  CALLBACK(unsigned short) \
34  CALLBACK(int) \
35  CALLBACK(unsigned) \
36  CALLBACK(long) \
37  CALLBACK(unsigned long) \
38  CALLBACK(long long) \
39  CALLBACK(unsigned long long) \
40  CALLBACK(float) \
41  CALLBACK(double) \
42  CALLBACK(long double) \
43  CALLBACK(bool) \
44  CALLBACK(std::string)
45 
46 namespace alps {
47  namespace hdf5 {
48 
50  template <typename T>
51  struct is_native_type : public std::false_type {};
52 #define ALPS_HDF5_IS_NATIVE_TYPE_CALLER(__type__) \
53  template <> struct is_native_type<__type__> : public std::true_type {};
55 #undef ALPS_HDF5_IS_NATIVE_TYPE_CALLER
56 
57 #define ONLY_NATIVE(T,R) typename std::enable_if<is_native_type<T>::value, R>::type
58 #define ONLY_NOT_NATIVE(T,R) typename std::enable_if<!is_native_type<T>::value, R>::type
59 
60  namespace detail {
61  struct archivecontext;
62 
63  template<typename A, typename T> struct is_datatype_caller {
64  static bool apply(A const & ar, std::string path) {
65  throw std::logic_error("only native datatypes can be probed: " + path + ALPS_STACKTRACE);
66  return false;
67  }
68  };
69 
70  #define ALPS_HDF5_IS_DATATYPE_CALLER(T) \
71  template<typename A> struct is_datatype_caller<A, T > { \
72  static bool apply(A const & ar, std::string path, T unused = alps::detail::type_wrapper<T>::type()) { \
73  return ar.is_datatype_impl(path, unused); \
74  } \
75  };
77  #undef ALPS_HDF5_IS_DATATYPE_CALLER
78 
79  template<typename A> struct archive_proxy {
80 
81  explicit archive_proxy(std::string const & path, A & ar)
82  : path_(path), ar_(ar)
83  {}
84 
85  template<typename T> archive_proxy & operator=(T const & value);
86  template<typename T> archive_proxy & operator<<(T const & value);
87  template<typename T> archive_proxy & operator>>(T & value);
88 
89  std::string path_;
90  A ar_;
91  };
92  }
93 
94  class archive {
95  private:
96  archive& operator=(const archive&) =delete; /* not implemented*/ // FIXME: ...or implement via `swap()`?
97  public:
98  typedef enum {
99  READ = 0x00,
100  WRITE = 0x01,
101  /* REPLACE = 0x02, */ // FIXME: reactivate when we have "replace" semantics
102  COMPRESS = 0x04,
103  MEMORY = 0x10
104  } properties;
105 
106  public:
107 
110  archive();
111  archive(std::string const & filename, std::string mode = "r");
112  archive(std::string const & filename, int prop);
113  archive(archive const & arg);
114 
115  virtual ~archive();
116  static void abort();
117 
118  std::string const & get_filename() const;
119 
120  std::string encode_segment(std::string segment) const;
121  std::string decode_segment(std::string segment) const;
122 
123  std::string get_context() const;
124  void set_context(std::string const & context);
125  std::string complete_path(std::string path) const;
128  void open(const std::string & filename, const std::string &mode = "r");
129  void close();
130  bool is_open();
131 
132  bool is_data(std::string path) const;
133  bool is_attribute(std::string path) const;
134  bool is_group(std::string path) const;
135 
136  bool is_scalar(std::string path) const;
137  bool is_null(std::string path) const;
138  bool is_complex(std::string path) const;
139 
140  template<typename T> bool is_datatype(std::string path) const {
141  return detail::is_datatype_caller<archive, T>::apply(*this, path);
142  }
143 
144  std::vector<std::string> list_children(std::string path) const;
145  std::vector<std::string> list_attributes(std::string path) const;
146 
147  std::vector<std::size_t> extent(std::string path) const;
148  std::size_t dimensions(std::string path) const;
149 
150  void create_group(std::string path) const;
151 
152  void delete_data(std::string path) const;
153  void delete_group(std::string path) const;
154  void delete_attribute(std::string path) const;
155 
156  void set_complex(std::string path);
157 
158 /* TODO: implement
159  void move_data(std::string current_path, std::string new_path) const;
160  void move_attribute(std::string current_path, std::string new_path) const;
161 */
162 
163  detail::archive_proxy<archive> operator[](std::string const & path);
164 
165  template<typename T> auto read(
166  std::string path
167  , T *
168  , std::vector<std::size_t>
169  , std::vector<std::size_t> = std::vector<std::size_t>()
170  ) const -> ONLY_NOT_NATIVE(T, void) {
171  throw std::logic_error("Invalid type on path: " + path + ALPS_STACKTRACE);
172  }
173 
174  template<typename T> auto write(
175  std::string path
176  , T const * value
177  , std::vector<std::size_t> size
178  , std::vector<std::size_t> chunk = std::vector<std::size_t>()
179  , std::vector<std::size_t> offset = std::vector<std::size_t>()
180  ) const -> ONLY_NOT_NATIVE(T, void) {
181  throw std::logic_error("Invalid type on path: " + path + ALPS_STACKTRACE);
182  }
183 
184  template<typename T> auto read(std::string path, T & value) const -> ONLY_NATIVE(T, void);
185 
186  template<typename T> auto read(std::string path
187  , T * value
188  , std::vector<std::size_t> chunk
189  , std::vector<std::size_t> offset = std::vector<std::size_t>()
190  ) const -> ONLY_NATIVE(T, void);
191 
192  template<typename T> auto write(std::string path, T value) const -> ONLY_NATIVE(T, void);
193 
194  template<typename T> auto write(std::string path
195  , T const * value, std::vector<std::size_t> size
196  , std::vector<std::size_t> chunk = std::vector<std::size_t>()
197  , std::vector<std::size_t> offset = std::vector<std::size_t>()
198  ) const -> ONLY_NATIVE(T, void);
199 
200  template<typename T> auto is_datatype_impl(std::string path, T) const -> ONLY_NATIVE(T, bool);
201 
202  private:
203 
204  void construct(std::string const & filename, std::size_t props = READ);
205  std::string file_key(std::string filename, bool memory) const;
206 
207  std::string current_;
208  detail::archivecontext * context_;
209 
210 #ifndef ALPS_SINGLE_THREAD
211  static boost::recursive_mutex mutex_;
212 #endif
213  static std::map<std::string, std::pair<detail::archivecontext *, std::size_t> > ref_cnt_;
214 
215  };
216 
217  template<typename T> struct is_continuous
218  : public std::false_type
219  {};
220 
221  template<typename T> struct is_content_continuous
222  : public is_continuous<T>
223  {};
224 
225  template<typename T> struct has_complex_elements
226  : public std::false_type
227  {};
229  template<typename T> struct scalar_type {
230  typedef T type;
231  };
232 
233  namespace detail {
234 
235  template<typename T> struct get_extent {
236  static std::vector<std::size_t> apply(T const & /*value*/) {
237  return std::vector<std::size_t>();
238  }
239  };
240 
241  template<typename T> struct set_extent {
242  static void apply(T &, std::vector<std::size_t> const &) {}
243  };
244 
245  #define ALPS_HDF5_DEFINE_SET_EXTENT(T) \
246  template<> struct set_extent<T> { \
247  static void apply(T &, std::vector<std::size_t> const & extent) { \
248  if (extent.size() > 0) \
249  throw wrong_type("The extents do not match" + ALPS_STACKTRACE); \
250  } \
251  };
253  #undef ALPS_HDF5_DEFINE_SET_EXTENT
254 
255  template<typename T> struct is_vectorizable {
256  static bool apply(T const & value){
257  return false;
258  }
259  };
260 
261  template<typename T> struct get_pointer {
262  static typename alps::hdf5::scalar_type<T>::type * apply(T &) {
263  return NULL;
264  }
265  };
266 
267  template<typename T> struct get_pointer<T const> {
268  static typename alps::hdf5::scalar_type<T>::type const * apply(T const &) {
269  return NULL;
270  }
271  };
273  }
274 
275  template<typename T> typename scalar_type<T>::type * get_pointer(T & value) {
276  return detail::get_pointer<T>::apply(value);
277  }
278 
279  template<typename T> typename scalar_type<T>::type const * get_pointer(T const & value) {
280  return detail::get_pointer<T const>::apply(value);
281  }
282 
283  template<typename T> std::vector<std::size_t> get_extent(T const & value) {
284  return detail::get_extent<T>::apply(value);
285  }
286 
287  template<typename T> void set_extent(T & value, std::vector<std::size_t> const & size) {
288  detail::set_extent<T>::apply(value, size);
289  }
290 
291  template<typename T> bool is_vectorizable(T const & value) {
292  return detail::is_vectorizable<T>::apply(value);
293  }
294 
295  template<typename T> void save(
296  archive & ar
297  , std::string const & path
298  , T const & value
299  , std::vector<std::size_t> /*size*/ = std::vector<std::size_t>()
300  , std::vector<std::size_t> chunk = std::vector<std::size_t>()
301  , std::vector<std::size_t> /*offset*/ = std::vector<std::size_t>()
302  ) {
303  // FIXME: size and offset are unused -- we should at least check for this
304  if (chunk.size())
305  throw std::logic_error("user defined objects needs to be written continously" + ALPS_STACKTRACE);
306  std::string context = ar.get_context();
307  ar.set_context(ar.complete_path(path));
308  value.save(ar);
309  ar.set_context(context);
310  }
311 
312  template<typename T> void load(
313  archive & ar
314  , std::string const & path
315  , T & value
316  , std::vector<std::size_t> chunk = std::vector<std::size_t>()
317  , std::vector<std::size_t> /*offset*/ = std::vector<std::size_t>()
318  ) {
319  if (chunk.size())
320  throw std::logic_error("user defined objects needs to be written continously" + ALPS_STACKTRACE);
321  std::string context = ar.get_context();
322  ar.set_context(ar.complete_path(path));
323  value.load(ar);
324  ar.set_context(context);
325  }
326 
327  #define ALPS_HDF5_DEFINE_FREE_FUNCTIONS(T) \
328  template<> struct is_continuous< T > \
329  : public std::true_type \
330  {}; \
331  template<> struct is_continuous< T const > \
332  : public std::true_type \
333  {}; \
334  \
335  namespace detail { \
336  template<> struct is_vectorizable< T > { \
337  static bool apply(T const & value); \
338  }; \
339  template<> struct is_vectorizable< T const > { \
340  static bool apply(T & value); \
341  }; \
342  \
343  template<> struct get_pointer< T > { \
344  static alps::hdf5::scalar_type< T >::type * apply( T & value); \
345  }; \
346  \
347  template<> struct get_pointer< T const > { \
348  static alps::hdf5::scalar_type< T >::type const * apply( T const & value); \
349  }; \
350  } \
351  \
352  void save( \
353  archive & ar \
354  , std::string const & path \
355  , T const & value \
356  , std::vector<std::size_t> size = std::vector<std::size_t>() \
357  , std::vector<std::size_t> chunk = std::vector<std::size_t>() \
358  , std::vector<std::size_t> offset = std::vector<std::size_t>() \
359  ); \
360  \
361  void load( \
362  archive & ar \
363  , std::string const & path \
364  , T & value \
365  , std::vector<std::size_t> chunk = std::vector<std::size_t>() \
366  , std::vector<std::size_t> offset = std::vector<std::size_t>() \
367  );
369  #undef ALPS_HDF5_DEFINE_FREE_FUNCTIONS
370 
371  namespace detail {
372 
373  template<typename T> struct make_pvp_proxy {
374 
375  explicit make_pvp_proxy(std::string const & path, T value)
376  : path_(path), value_(value)
377  {}
378 
379  make_pvp_proxy(make_pvp_proxy<T> const & arg)
380  : path_(arg.path_), value_(arg.value_)
381  {}
382 
383  std::string path_;
384  T value_;
385  };
386 
387  }
389  template <typename T> typename std::enable_if<
391  , archive &
392  >::type operator<< (archive & ar, detail::make_pvp_proxy<T> const & proxy) {
393  save(ar, proxy.path_, proxy.value_);
394  ar.set_complex(proxy.path_);
395  return ar;
396  }
398  template <typename T> typename std::enable_if<
400  , archive &
401  >::type operator<< (archive & ar, detail::make_pvp_proxy<T> const & proxy) {
402  save(ar, proxy.path_, proxy.value_);
403  return ar;
404  }
405 
406  template <typename T> archive & operator>> (archive & ar, detail::make_pvp_proxy<T> proxy) {
407  load(ar, proxy.path_, proxy.value_);
408  return ar;
409  }
410  }
412  template <typename T> typename std::enable_if<!(
413  std::is_same<typename alps::detail::remove_cvr<typename std::remove_all_extents<T>::type>::type, char>::value
414  && std::is_array<T>::value)
415  , hdf5::detail::make_pvp_proxy<T &> >::type make_pvp(std::string const & path, T & value) {
416  return hdf5::detail::make_pvp_proxy<T &>(path, value);
417  }
418  template <typename T> typename std::enable_if<!(
419  std::is_same<typename alps::detail::remove_cvr<typename std::remove_all_extents<T>::type>::type, char>::value
420  && std::is_array<T>::value)
421  , hdf5::detail::make_pvp_proxy<T const &> >::type make_pvp(std::string const & path, T const & value) {
422  return hdf5::detail::make_pvp_proxy<T const &>(path, value);
423  }
424  template <typename T> typename std::enable_if<
425  std::is_same<typename alps::detail::remove_cvr<typename std::remove_all_extents<T>::type>::type, char>::value
426  && std::is_array<T>::value
427  , hdf5::detail::make_pvp_proxy<std::string const> >::type make_pvp(std::string const & path, T const & value) {
428  return hdf5::detail::make_pvp_proxy<std::string const>(path, value);
429  }
430 
431  namespace hdf5 {
432  namespace detail {
433 
434  template<typename A> template<typename T> archive_proxy<A> & archive_proxy<A>::operator=(T const & value) {
435  ar_ << make_pvp(path_, value);
436  return *this;
437  }
438 
439  template<typename A> template<typename T> archive_proxy<A> & archive_proxy<A>::operator<<(T const & value) {
440  return *this = value;
441  }
442 
443  template<typename A> template <typename T> archive_proxy<A> & archive_proxy<A>::operator>> (T & value) {
444  ar_ >> make_pvp(path_, value);
445  return *this;
446  }
447 
448  }
449  }
450 }
451 
452 #endif
void load(archive &ar, std::string const &path, T &value, std::vector< std::size_t > chunk=std::vector< std::size_t >(), std::vector< std::size_t >=std::vector< std::size_t >())
Definition: archive.hpp:309
bool is_vectorizable(T const &value)
Definition: archive.hpp:288
void set_extent(T &value, std::vector< std::size_t > const &size)
Definition: archive.hpp:284
#define ALPS_HDF5_DEFINE_FREE_FUNCTIONS(T)
Definition: archive.hpp:324
std::enable_if<!is_sequence< T >::value, std::size_t >::type size(T const &)
Definition: size.hpp:20
std::vector< std::size_t > get_extent(T const &value)
Definition: archive.hpp:280
scalar_type< T >::type * get_pointer(T &value)
Definition: archive.hpp:272
std::enable_if< has_complex_elements< typename alps::detail::remove_cvr< T >::type >::value, archive & >::type operator<<(archive &ar, detail::make_pvp_proxy< T > const &proxy)
Definition: archive.hpp:388
ALPS_FOREACH_NATIVE_HDF5_TYPE(ALPS_HDF5_READ_SCALAR)
void set_context(std::string const &context)
Definition: archive.cpp:148
#define ONLY_NATIVE(T, R)
Definition: archive.hpp:56
int close(int)
std::string get_context() const
Definition: archive.cpp:144
#define ONLY_NOT_NATIVE(T, R)
Definition: archive.hpp:57
#define ALPS_HDF5_DEFINE_SET_EXTENT(T)
Definition: archive.hpp:243
#define ALPS_HDF5_IS_NATIVE_TYPE_CALLER(__type__)
Definition: archive.hpp:52
void set_complex(std::string path)
Definition: archive.cpp:397
#define ALPS_STACKTRACE
Definition: stacktrace.hpp:37
std::enable_if<!(std::is_same< typename alps::detail::remove_cvr< typename std::remove_all_extents< T >::type >::type, char >::value &&std::is_array< T >::value), hdf5::detail::make_pvp_proxy< T & > >::type make_pvp(std::string const &path, T &value)
Definition: archive.hpp:411
Metafunction-predicate: returns true_type if type T is scalar.
Definition: is_scalar.hpp:24
std::string complete_path(std::string path) const
Definition: archive.cpp:153
std::enable_if< !has_complex_elements< typename alps::detail::remove_cvr< T >::type >::value, archive & >::type operator<<(archive &ar, detail::make_pvp_proxy< T > const &proxy)
Definition: archive.hpp:397
Inherits from true_type if T is a native type, from false_type otherwise.
Definition: archive.hpp:51
archive & operator>>(archive &ar, detail::make_pvp_proxy< T > proxy)
Definition: archive.hpp:402
void save(archive &ar, std::string const &path, T const &value, std::vector< std::size_t >=std::vector< std::size_t >(), std::vector< std::size_t > chunk=std::vector< std::size_t >(), std::vector< std::size_t >=std::vector< std::size_t >())
Definition: archive.hpp:292
#define ALPS_HDF5_IS_DATATYPE_CALLER(T)
Definition: archive.hpp:69