24 #ifndef GOBY_MIDDLEWARE_LOG_HDF5_HDF5_H
25 #define GOBY_MIDDLEWARE_LOG_HDF5_HDF5_H
37 #include <google/protobuf/descriptor.h>
47 struct HDF5ProtobufEntry;
61 std::multimap<std::uint64_t, HDF5ProtobufEntry>
entries;
74 std::map<std::string, MessageCollection>
entries;
81 GroupFactory(H5::H5File& h5file) : root_group_(h5file.openGroup(
"/")) {}
84 H5::Group&
fetch_group(
const std::string& group_path);
91 GroupWrapper(
const H5::Group&
group) : group_(
group) {}
94 GroupWrapper(
const std::string& name, H5::Group& parent) : group_(parent.createGroup(name))
98 H5::Group&
fetch_group(std::deque<std::string>& nodes);
102 std::map<std::string, GroupWrapper> children_;
104 GroupWrapper root_group_;
110 Writer(
const std::string& output_file,
bool write_zero_length_dim =
true,
111 bool use_chunks =
false, hsize_t chunk_length = 0,
bool use_compression =
false,
112 int compression_level = 0);
116 void write(
bool final_write =
true);
123 void write_time(
const std::string&
group,
125 void write_scheme(
const std::string&
group,
128 void write_field_selector(
const std::string&
group,
129 const google::protobuf::FieldDescriptor* field_desc,
130 const std::vector<const google::protobuf::Message*>& messages,
131 std::vector<hsize_t>& hs);
133 void write_enum_attributes(
const std::string&
group,
134 const google::protobuf::FieldDescriptor* field_desc);
136 template <
typename T>
137 void write_field(
const std::string&
group,
const google::protobuf::FieldDescriptor* field_desc,
138 const std::vector<const google::protobuf::Message*>& messages,
139 std::vector<hsize_t>& hs);
141 void write_embedded_message(
const std::string&
group,
142 const google::protobuf::FieldDescriptor* field_desc,
143 const std::vector<const google::protobuf::Message*> messages,
144 std::vector<hsize_t>& hs);
146 template <
typename T>
147 void write_vector(
const std::string&
group,
const std::string dataset_name,
148 const std::vector<T>& data,
const std::vector<hsize_t>& hs,
149 const T& default_value, T empty_value = retrieve_empty_value<T>());
151 void write_vector(
const std::string&
group,
const std::string& dataset_name,
152 const std::vector<std::string>& data,
const std::vector<hsize_t>& hs,
153 const std::string& default_value);
155 std::string dim_str(
const std::vector<hsize_t>& hs)
165 std::map<std::string, goby::middleware::hdf5::Channel> channels_;
168 bool write_zero_length_dim_;
170 hsize_t chunk_length_;
171 bool use_compression_;
172 int compression_level_;
176 template <
typename T>
177 void Writer::write_field(
const std::string&
group,
178 const google::protobuf::FieldDescriptor* field_desc,
179 const std::vector<const google::protobuf::Message*>& messages,
180 std::vector<hsize_t>& hs)
182 if (field_desc->is_repeated())
185 int max_field_size = 0;
186 for (
auto message : messages)
191 int field_size = refl->
FieldSize(*message, field_desc);
192 if (field_size > max_field_size)
193 max_field_size = field_size;
197 hs.push_back(max_field_size);
199 std::vector<T> values(messages.size() * max_field_size, retrieve_empty_value<T>());
201 for (
unsigned i = 0, n = messages.size(); i < n; ++i)
206 int field_size = refl->
FieldSize(*messages[i], field_desc);
207 for (
int j = 0; j < field_size; ++j)
208 retrieve_repeated_value<T>(&values[i * max_field_size + j], j,
209 PBMeta(refl, field_desc, (*messages[i])));
216 write_vector(
group, field_desc->name(), values, hs, default_value);
222 std::vector<T> values(messages.size(), retrieve_empty_value<T>());
223 for (
unsigned i = 0, n = messages.size(); i < n; ++i)
228 retrieve_single_value<T>(&values[i], PBMeta(refl, field_desc, (*messages[i])));
235 write_vector(
group, field_desc->name(), values, hs, default_value);
239 template <
typename T>
240 void Writer::write_vector(
const std::string&
group,
const std::string dataset_name,
241 const std::vector<T>& data,
const std::vector<hsize_t>& hs,
242 const T& default_value, T empty_value)
244 std::unique_ptr<H5::DataSpace> dataspace;
248 H5::DSetCreatPropList prop;
249 bool ds_exists = grp.exists(dataset_name);
252 if (use_chunks_ && !final_write_)
255 for (
auto& m : maxhs) m = H5S_UNLIMITED;
257 chunkhs.front() = chunk_length_;
260 for (
auto& s : chunkhs)
266 glog.
is_debug2() &&
glog <<
"Setting chunks to " << dim_str(chunkhs) << std::endl;
267 prop.setChunk(chunkhs.size(), chunkhs.data());
268 prop.setFillValue(predicate<T>(), &empty_value);
269 if (use_compression_)
270 prop.setDeflate(compression_level_);
275 if (data.size() || write_zero_length_dim_)
276 dataspace = std::make_unique<H5::DataSpace>(hs.size(), hs.data(), maxhs.data());
278 dataspace = std::make_unique<H5::DataSpace>(H5S_NULL);
280 H5::DataSet dataset = ds_exists
281 ? grp.openDataSet(dataset_name)
282 : grp.createDataSet(dataset_name, predicate<T>(), *dataspace, prop);
286 H5::DataSpace existing_space(dataset.getSpace());
287 std::vector<hsize_t> existing_hs(existing_space.getSimpleExtentNdims());
288 existing_space.getSimpleExtentDims(&existing_hs[0]);
293 std::vector<hsize_t> new_size(hs.size(), 0);
294 for (
int i = 0, n = new_size.size(); i < n; ++i)
295 new_size[i] = std::max(hs[i], existing_hs[i]);
296 new_size.front() = existing_hs.front() + hs.front();
298 glog.
is_debug2() &&
glog <<
"Extending dimensions to: " << dim_str(new_size) << std::endl;
299 dataset.extend(new_size.data());
301 auto& memspace = dataspace;
302 H5::DataSpace filespace(dataset.getSpace());
303 std::vector<hsize_t> offset(hs.size(), 0);
304 offset.front() = existing_hs.front();
306 glog.
is_debug2() &&
glog <<
"Selecting offset of: " << dim_str(offset) << std::endl;
308 filespace.selectHyperslab(H5S_SELECT_SET, hs.data(), offset.data());
310 dataset.write(&data[0], predicate<T>(), *memspace, filespace);
315 dataset.write(&data[0], predicate<T>());
318 const char* default_value_attr_name =
"default_value";
319 if (!dataset.attrExists(default_value_attr_name))
322 hsize_t att_hs[] = {1};
323 H5::DataSpace att_space(rank, att_hs, att_hs);
325 dataset.createAttribute(default_value_attr_name, predicate<T>(), att_space);
326 att.write(predicate<T>(), &default_value);