1 /***************************************************************************
2 * Copyright (c) Wolf Vollprecht, Sylvain Corlay and Johan Mabille          *
3 * Copyright (c) QuantStack                                                 *
4 *                                                                          *
5 * Distributed under the terms of the BSD 3-Clause License.                 *
6 *                                                                          *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9 
10 #ifndef XTENSOR_IO_XHIGHFIVE_HPP
11 #define XTENSOR_IO_XHIGHFIVE_HPP
12 
13 #include <iostream>
14 #include <string>
15 #include <vector>
16 
17 #include <highfive/H5DataSet.hpp>
18 #include <highfive/H5File.hpp>
19 #include <highfive/H5Easy.hpp>
20 
21 #include <xtensor/xarray.hpp>
22 #include <xtensor/xtensor.hpp>
23 
24 #include "xtensor-io.hpp"
25 
26 namespace xt
27 {
28     namespace extensions
29     {
30         /**
31         * Check if a path exists (is a Group or DataSet) in an open HDF5 file.
32         *
33         * @param file opened HighFive::File
34         * @param path path of the Group/DataSet
35         */
exist(const HighFive::File & file,const std::string & path)36         inline bool exist(const HighFive::File& file, const std::string& path)
37         {
38             return file.exist(path);
39         }
40 
41         /**
42         * Recursively create groups in an open HDF5 file such that a DataSet can be created.
43         * For example if the path = "/path/to/dataset", this function will create the groups
44         * "/path" and "/path/to".
45         *
46         * @param file opened HighFive::File
47         * @param path path of the DataSet
48         */
create_group(HighFive::File & file,const std::string & path)49         inline void create_group(HighFive::File& file, const std::string& path)
50         {
51             file.createGroup(path);
52         }
53 
54         /**
55         * Get the size of an existing DataSet in an open HDF5 file.
56         *
57         * @param file opened HighFive::File
58         * @param path path of the DataSet
59         *
60         * @return size the size of the HighFive::DataSet
61         */
size(const HighFive::File & file,const std::string & path)62         inline std::size_t size(const HighFive::File& file, const std::string& path)
63         {
64             return H5Easy::getSize(file, path);
65         }
66 
67         /**
68         * Get the shape of an existing DataSet in an open HDF5 file.
69         *
70         * @param file opened HighFive::File
71         * @param path path of the DataSet
72         *
73         * @return shape the shape of the HighFive::DataSet
74         */
shape(const HighFive::File & file,const std::string & path)75         inline std::vector<std::size_t> shape(const HighFive::File& file, const std::string& path)
76         {
77             return H5Easy::getShape(file, path);
78         }
79     }
80 
81     namespace detail
82     {
highfive_file_mode(xt::file_mode mode)83         inline auto highfive_file_mode(xt::file_mode mode)
84         {
85             switch (mode)
86             {
87                 case xt::file_mode::create:
88                   return HighFive::File::Create;
89                 case xt::file_mode::overwrite:
90                   return HighFive::File::Overwrite;
91                 case xt::file_mode::append:
92                   return HighFive::File::ReadWrite;
93                 case xt::file_mode::read:
94                   return HighFive::File::ReadOnly;
95                 default:
96                   return HighFive::File::ReadOnly;
97             }
98         }
99 
highfive_dump_mode(xt::dump_mode mode)100         inline auto highfive_dump_mode(xt::dump_mode mode)
101         {
102             switch (mode)
103             {
104                 case xt::dump_mode::create:
105                   return H5Easy::DumpMode::Create;
106                 case xt::dump_mode::overwrite:
107                   return H5Easy::DumpMode::Overwrite;
108                 default:
109                   return H5Easy::DumpMode::Create;
110             }
111         }
112     }
113 
114     /**
115     * Write scalar/string to a new DataSet in an open HDF5 file.
116     *
117     * @param file opened HighFive::File (has to be writeable)
118     * @param path path of the DataSet
119     * @param data the data to write
120     * @param dmode DataSet-write mode (xt::dump_mode::create | xt::dump_mode::overwrite)
121     *
122     * @return dataset the newly created HighFive::DataSet (e.g. to add an attribute)
123     */
124     template <class T>
dump(HighFive::File & file,const std::string & path,const T & data,xt::dump_mode dmode=xt::dump_mode::create)125     inline HighFive::DataSet dump(HighFive::File& file, const std::string& path, const T& data,
126                                   xt::dump_mode dmode=xt::dump_mode::create)
127     {
128         return H5Easy::dump(file, path, data, detail::highfive_dump_mode(dmode));
129     }
130 
131     /**
132     * Write a scalar to a (new, extendible) DataSet in an open HDF5 file.
133     *
134     * @param file opened HighFive::File (has to be writeable)
135     * @param path path of the DataSet
136     * @param data the data to write
137     * @param idx the indices to which to write
138     *
139     * @return dataset the (newly created) HighFive::DataSet (e.g. to add an attribute)
140     */
141     template <class T>
dump(HighFive::File & file,const std::string & path,const T & data,const std::vector<std::size_t> & idx)142     inline HighFive::DataSet dump(HighFive::File& file, const std::string& path, const T& data,
143                                   const std::vector<std::size_t>& idx)
144     {
145         return H5Easy::dump(file, path, data, idx);
146     }
147 
148     /**
149     * Load entry "{i,...}" from a DataSet in an open HDF5 file to a scalar.
150     *
151     * @param file opened HighFive::File (has to be writeable)
152     * @param idx the indices to load
153     * @param path path of the DataSet
154     *
155     * @return data the read data
156     */
157     template <class T>
load(const HighFive::File & file,const std::string & path,const std::vector<std::size_t> & idx)158     inline auto load(const HighFive::File& file, const std::string& path, const std::vector<std::size_t>& idx)
159     {
160         return H5Easy::load<T>(file, path, idx);
161     }
162 
163     /**
164     * Load a DataSet in an open HDF5 file to an object (templated).
165     *
166     * @param file opened HighFive::File (has to be writeable)
167     * @param path path of the DataSet
168     *
169     * @return data the read data
170     */
171     template <class T>
load(const HighFive::File & file,const std::string & path)172     inline auto load(const HighFive::File& file, const std::string& path)
173     {
174         return H5Easy::load<T>(file, path);
175     }
176 
177     /**
178     * Write field to a new DataSet in an HDF5 file.
179     *
180     * @param file opened HighFive::File (has to be writeable)
181     * @param path path of the DataSet
182     * @param data the data to write
183     * @param dmode DataSet-write mode (xt::dump_mode::create | xt::dump_mode::overwrite)
184     *
185     * @return dataset the newly created HighFive::DataSet (e.g. to add an attribute)
186     */
187     template <class T>
dump_hdf5(const std::string & fname,const std::string & path,const T & data,xt::file_mode fmode=xt::file_mode::create,xt::dump_mode dmode=xt::dump_mode::create)188     inline void dump_hdf5(const std::string& fname, const std::string& path, const T& data,
189                           xt::file_mode fmode=xt::file_mode::create,
190                           xt::dump_mode dmode=xt::dump_mode::create)
191     {
192         HighFive::File file(fname, detail::highfive_file_mode(fmode));
193 
194         xt::dump(file, path, data, dmode);
195     }
196 
197     /**
198     * Load a DataSet in an open HDF5 file to an object (templated).
199     *
200     * @param file opened HighFive::File (has to be writeable)
201     * @param path path of the DataSet
202     *
203     * @return data the read data
204     */
205     template <class T>
load_hdf5(const std::string & fname,const std::string & path)206     inline auto load_hdf5(const std::string& fname, const std::string& path)
207     {
208         HighFive::File file(fname, detail::highfive_file_mode(xt::file_mode::read));
209 
210         return xt::load<T>(file, path);
211     }
212 }
213 
214 #endif
215