14 #include <boost/array.hpp>
15 #include <boost/utility/enable_if.hpp>
16 #include <boost/noncopyable.hpp>
17 #include <boost/type_traits.hpp>
18 #include <boost/assert.hpp>
20 #include <boost/typeof/typeof.hpp>
22 #include "mpqc/range.hpp"
23 #include "mpqc/range/operator.hpp"
25 #include "mpqc/utility/check.hpp"
26 #include <boost/foreach.hpp>
27 #include "mpqc/utility/timer.hpp"
28 #include "mpqc/utility/mutex.hpp"
30 #include <util/misc/exenv.h>
41 #define MPQC_FILE_VERIFY(expr) MPQC_CHECK((expr) >= 0)
43 #ifndef H5_HAVE_THREADSAFE
44 #warning "HDF5 NOT THREADSAFE, HDF5 will use global mutex"
57 static void lock() { mutex::global::lock(); }
58 static void unlock() { mutex::global::unlock(); }
62 #define MPQC_FILE_THREADSAFE mpqc::detail::File::threadsafe _threadsafe
69 typedef typename boost::remove_const<T>::type U;
70 if (boost::is_same<U,int>::value)
return H5T_NATIVE_INT;
71 if (boost::is_same<U,double>::value)
return H5T_NATIVE_DOUBLE;
72 throw std::runtime_error(
"no mapping to HDF5 type");
78 props_ = H5Pcreate(props);
110 Object(
const Object &parent, hid_t
id,
void (*close)(hid_t),
bool increment) {
112 parent_.reset(
new Object(parent));
113 update(
id, close, increment);
119 MPQC_FILE_THREADSAFE;
123 void operator=(
const Object &o) {
124 Object *parent = o.parent_.get();
125 parent_.reset(parent ?
new Object(*parent) : NULL);
126 update(o.id_, o.close_,
true);
133 const Object& parent()
const {
138 MPQC_FILE_THREADSAFE;
139 return H5Iget_file_id(id_);
142 static std::string filename(hid_t
id) {
143 MPQC_FILE_THREADSAFE;
144 std::vector<char> str(H5Fget_name(
id, NULL, 0) + 1);
145 MPQC_FILE_VERIFY(H5Fget_name(
id, &str[0], str.size()));
146 return std::string(&str[0]);
149 operator bool()
const {
155 std::auto_ptr<Object> parent_;
157 void (*close_)(hid_t);
160 void update(hid_t
id, F close,
bool increment) {
161 if (
id && increment) {
162 MPQC_FILE_THREADSAFE;
163 MPQC_FILE_VERIFY(H5Iinc_ref(
id));
173 template<
class Container>
175 static Container data;
178 template<
class Container>
217 this->fapl_ = H5Pcreate(H5P_FILE_ACCESS);
218 MPQC_FILE_VERIFY(this->fapl_);
229 #ifdef H5_HAVE_DIRECT
230 struct DirectDriver :
Driver {
234 MPQC_FILE_VERIFY(H5Pset_fapl_direct(Driver::fapl_, 1024, 4096, 8*4096));
253 initialize(name, driver);
261 Group
group(
const std::string &name =
"/");
269 void initialize(
const std::string &name,
const Driver &driver) {
270 Object o = File::open(name, driver);
272 o = File::create(name, driver);
274 Object::operator=(o);
280 static void close(hid_t
id) {
282 MPQC_FILE_VERIFY((count = H5Iget_ref(
id)));
283 MPQC_FILE_VERIFY(result = H5Fclose(
id));
285 files_::data.erase(
id);
289 explicit File(hid_t
id,
bool increment) :
292 MPQC_FILE_VERIFY(
id);
299 static std::string realpath(
const std::string &name) {
300 char *str = ::realpath(name.c_str(), NULL);
302 std::string path(str ? str : name);
314 static File open(
const std::string &name,
const Driver &driver) {
315 if (name.empty())
return File();
316 std::string path = realpath(name);
318 BOOST_FOREACH (
auto id, files_::data) {
319 if (path == realpath(Object::filename(
id)))
320 return File(
id,
true);
322 hid_t fapl = driver.fapl();
323 hid_t
id = H5Fcreate(name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, fapl);
324 MPQC_FILE_VERIFY(
id);
325 files_::data.insert(
id);
326 return File(
id,
false);
336 static File create(
const std::string &name,
const Driver &driver) {
337 hid_t fapl = driver.fapl();
338 hid_t
id = H5Fcreate(name.c_str(), H5F_ACC_EXCL, H5P_DEFAULT, fapl);
339 MPQC_FILE_VERIFY(
id);
340 files_::data.insert(
id);
341 return File(
id,
false);
350 template<
typename T_>
351 struct File::Dataspace {
353 typedef typename boost::remove_const<T_>::type T;
367 std::vector<range> r = range_;
368 r[ndims_ - 1] =
range(i, i + 1);
369 return Dataspace(parent_, base_, r, ndims_ - 1);
385 template<
class R, ...>
390 return this->
operator()(std::vector<range>(t));
402 apply(&H5Dwrite, this->parent_.id(), rebase(range_), (T*) buffer);
414 apply(&H5Dread, this->parent_.id(), rebase(range_), buffer);
422 size_t ndims_, size_;
423 std::vector<size_t> base_;
424 std::vector<mpqc::range> range_;
428 const std::vector<mpqc::range> &r,
size_t ndims) :
434 MPQC_ASSERT(ndims <= range_.size());
435 size_ = (r.size() ? 1 : 0);
436 for (
int i = 0; i < range_.size(); ++i) {
437 size_ *= range_[i].size();
443 std::vector<range> extend(
const std::vector<range> &r)
const {
445 MPQC_ASSERT(r.size() == ndims_);
446 std::vector<range> x = r;
447 for (
size_t i = ndims_; i < range_.size(); ++i) {
448 x.push_back(range_[i]);
454 std::vector<range> rebase(
const std::vector<range> &r)
const {
455 MPQC_ASSERT(r.size() == base_.size());
456 std::vector<range> v;
457 for (
int i = 0; i < base_.size(); ++i) {
458 auto begin = *r[i].begin() - base_[i];
459 v.push_back(range(begin, begin + r[i].
size()));
466 static void apply(F f, hid_t dset,
const std::vector<range> &r, T *buffer) {
467 MPQC_FILE_THREADSAFE;
468 hid_t fspace = H5Dget_space(dset);
469 size_t size = select(fspace, r);
470 hsize_t mdims[] = {
size };
471 hid_t mspace = H5Screate_simple(1, mdims, NULL);
472 MPQC_FILE_VERIFY(mspace);
473 MPQC_FILE_VERIFY(H5Sselect_all(mspace));
474 hid_t type = detail::File::h5t<T>();
476 MPQC_FILE_VERIFY(f(dset, type, mspace, fspace, H5P_DEFAULT, buffer));
477 MPQC_FILE_VERIFY(H5Sclose(mspace));
478 MPQC_FILE_VERIFY(H5Sclose(fspace));
482 static size_t select(hid_t space,
const std::vector<range> &r) {
483 size_t N = H5Sget_simple_extent_ndims(space);
492 for (
size_t i = 0, j = N - 1; i < N; ++i, --j) {
493 fstart[i] = *r[j].begin();
494 fcount[i] = r[j].size();
505 (space, H5S_SELECT_SET, fstart, fstride, fcount, fblock));
526 template<
typename Extents>
527 Dataset(
const Object &parent,
const std::string &name,
const Extents &extents,
531 MPQC_ASSERT(
id() > 0);
532 BOOST_FOREACH (
auto e, extents) {
535 base_.push_back(*r.begin());
536 dims_.push_back(r.size());
545 std::vector<range> extents()
const {
546 std::vector<range> r;
547 for (
size_t i = 0; i < this->rank(); ++i) {
548 r.push_back(
range(base_[i], base_[i]+dims_[i]));
559 this->operator()(this->extents()).write(buffer);
568 this->operator()(this->extents()).read(buffer);
573 std::vector<range> r;
574 for (
int i = 0; i < this->rank(); ++i) {
575 r.push_back(
range(base_[i], base_[i] + dims_[i]));
583 MPQC_ASSERT(this->rank() == r.size());
589 MPQC_ASSERT(this->rank() == r.size());
601 template<
class R, ...>
606 return this->operator()(std::vector<range>(t));
610 return this->operator()(std::vector<range>(t));
616 template<
typename Extents>
617 static Object create(
const Object &parent,
618 const std::string &name,
619 const Extents &extents,
620 const Properties &dcpl) {
626 MPQC_FILE_THREADSAFE;
627 std::vector<hsize_t> dims;
628 BOOST_FOREACH (
auto e, extents) {
629 dims.push_back(extent(e).size());
632 std::reverse(dims.begin(), dims.end());
634 hid_t fspace = H5Screate_simple(dims.size(), &dims[0], NULL);
635 hid_t type = detail::File::h5t<T>();
637 #if H5_VERS_MAJOR == 1 && H5_VERS_MINOR < 8
638 id = H5Dcreate(parent.id(), name.c_str(), type, fspace, dcpl.id());
640 id = H5Dcreate1(parent.id(), name.c_str(), type, fspace, dcpl.id());
642 MPQC_FILE_VERIFY(
id);
644 return Object(parent,
id, &Dataset::close,
false);
659 template <
typename E>
666 std::vector<size_t> base_;
667 std::vector<size_t> dims_;
672 static void close(hid_t
id) {
674 MPQC_FILE_VERIFY(H5Dclose(
id));
691 #if H5_VERS_MAJOR == 1 && H5_VERS_MINOR < 8
692 hid_t
id = H5Gopen(parent.id(), name.c_str());
694 hid_t
id = H5Gopen1(parent.id(), name.c_str());
696 return Group(
Object(parent,
id, &Group::close,
false));
705 template<
typename T,
typename Dims>
715 static void close(hid_t
id) {
717 MPQC_FILE_VERIFY(H5Gclose(
id));
720 Group(Object o) : Object(o) {}
734 template<
typename T,
class A>
746 template<
typename T,
class A>
758 template<
typename T,
class A>
770 template<
typename T,
class A>
779 #endif // MPQC_FILE_HPP