ritsuko
Helper utilities for ArtifactDB C++ code
Loading...
Searching...
No Matches
Stream1dArray.hpp
Go to the documentation of this file.
1#ifndef RITSUKO_CVLS_STREAM_1D_ARRAY_HPP
2#define RITSUKO_CVLS_STREAM_1D_ARRAY_HPP
3
4#include <vector>
5#include <string>
6#include <stdexcept>
7#include <cstdint>
8#include <cassert>
9
10#include "H5Cpp.h"
11#include "sanisizer/sanisizer.hpp"
12
13#include "../hdf5/get_name.hpp"
14#include "../hdf5/strnlen.hpp"
15
16#include "Pointer.hpp"
17
23namespace ritsuko {
24
25namespace cvls {
26
38template<typename Offset_, typename Length_, typename DataSetPointer_ = const H5::DataSet*>
40public:
49 Stream1dArray(DataSetPointer_ pointers_ptr, hsize_t length, DataSetPointer_ heap_ptr) :
50 my_pointers_ptr(std::move(pointers_ptr)),
51 my_heap_ptr(std::move(heap_ptr)),
52 my_pointer_full_length(length),
53 my_heap_full_length([&]{
54 hsize_t output;
55 my_heap_ptr->getSpace().getSimpleExtentDims(&output);
56 return output;
57 }()),
58 my_pointer_block_size([&]{
59 assert(my_pointers_ptr->getSpace().getSimpleExtentNdims() == 1);
60 hsize_t output;
61 const auto& plist = my_pointers_ptr->getCreatePlist();
62 if (plist.getLayout() == H5D_CHUNKED) {
63 plist.getChunk(1, &output);
64 } else {
65 // Hard-coding the upper bound to save ourselves from processing an extra argument.
66 output = sanisizer::min(my_pointer_full_length, 10000);
67 }
68 return output;
69 }()),
70 my_pointer_mspace(1, &my_pointer_block_size),
71 my_pointer_dspace(1, &my_pointer_full_length),
72 my_heap_dspace(1, &my_heap_full_length),
74 my_pointer_buffer(sanisizer::cast<I<decltype(my_pointer_buffer.size())> >(my_pointer_block_size))
75 {
76 // Check that maximum allocation is possible, so we don't have to check casts for individual string lengths.
77 sanisizer::cast<I<decltype(my_heap_buffer.size())> >(my_heap_full_length);
78 }
79
80public:
84 hsize_t chunk_size() const {
85 return my_pointer_block_size;
86 }
87
98 hsize_t load(std::string* buffer) {
99 my_last_loaded += my_available;
100 my_available = std::min(my_pointer_full_length - my_last_loaded, my_pointer_block_size);
101 if (my_available == 0) {
102 return 0;
103 }
104
105 constexpr hsize_t zero = 0;
106 my_pointer_mspace.selectHyperslab(H5S_SELECT_SET, &my_available, &zero);
107 my_pointer_dspace.selectHyperslab(H5S_SELECT_SET, &my_available, &my_last_loaded);
108 my_heap_dspace.selectNone();
109 my_pointers_ptr->read(my_pointer_buffer.data(), my_pointer_dtype, my_pointer_mspace, my_pointer_dspace);
110
111 for (size_t i = 0; i < my_available; ++i) {
112 const auto& val = my_pointer_buffer[i];
113 if (is_Pointer_out_of_range(val, my_heap_full_length)) {
114 throw std::runtime_error("compressed VLS array pointers at '" +
115 hdf5::get_name(*my_pointers_ptr) +
116 "' are out of range of the heap at '" +
117 hdf5::get_name(*my_heap_ptr) +
118 "'"
119 );
120 }
121
122 auto& curstr = buffer[i];
123 curstr.clear();
124
125 if (val.length) {
126 // Casts are safe if the pointers are within range.
127 const hsize_t start = val.offset;
128 const hsize_t count = val.length;
129
130 // Don't attempt to batch these reads as we aren't guaranteed
131 // that they are non-overlapping or ordered. Hopefully HDF5 is
132 // keeping enough things in cache for repeated reads.
133 my_heap_mspace.setExtentSimple(1, &count);
134 my_heap_mspace.selectAll();
135 my_heap_dspace.selectHyperslab(H5S_SELECT_SET, &count, &start);
136 my_heap_buffer.resize(count);
137 my_heap_ptr->read(my_heap_buffer.data(), H5::PredType::NATIVE_UINT8, my_heap_mspace, my_heap_dspace);
138 const char* text_ptr = reinterpret_cast<const char*>(my_heap_buffer.data());
139 curstr.insert(curstr.end(), text_ptr, text_ptr + hdf5::strnlen(text_ptr, count));
140 }
141 }
142
143 return my_available;
144 }
145
153 hsize_t start() const {
154 return my_last_loaded;
155 }
156
157private:
158 DataSetPointer_ my_pointers_ptr;
159 DataSetPointer_ my_heap_ptr;
160 hsize_t my_pointer_full_length, my_heap_full_length;
161 hsize_t my_pointer_block_size;
162 H5::DataSpace my_pointer_mspace, my_pointer_dspace;
163 H5::DataSpace my_heap_mspace, my_heap_dspace;
164
165 H5::DataType my_pointer_dtype;
166 std::vector<Pointer<Offset_, Length_> > my_pointer_buffer;
167 std::vector<std::uint8_t> my_heap_buffer;
168
169 hsize_t my_last_loaded = 0;
170 hsize_t my_available = 0;
171
172 static_assert(std::is_base_of<H5::DataSet, I<decltype(*my_pointers_ptr)> >::value);
173 static_assert(std::is_base_of<H5::DataSet, I<decltype(*my_heap_ptr)> >::value);
174};
175
176}
177
178}
179
180#endif
Compound datatype of the compresed VLS heap pointer.
Stream a 1-dimensional compressed VLS array into memory.
Definition Stream1dArray.hpp:39
hsize_t load(std::string *buffer)
Definition Stream1dArray.hpp:98
hsize_t chunk_size() const
Definition Stream1dArray.hpp:84
Stream1dArray(DataSetPointer_ pointers_ptr, hsize_t length, DataSetPointer_ heap_ptr)
Definition Stream1dArray.hpp:49
hsize_t start() const
Definition Stream1dArray.hpp:153
Get the name of a HDF5 object.
H5::CompType define_pointer_datatype()
Definition Pointer.hpp:69
bool is_Pointer_out_of_range(const Pointer< Offset_, Length_ > &ptr, const hsize_t heap_length)
Definition Pointer.hpp:148
std::string get_name(const Object_ &obj)
Definition get_name.hpp:29
std::size_t strnlen(const char *ptr, std::size_t max)
Definition strnlen.hpp:25
Helper functions for ArtifactDB parsing and validation.
Definition Pointer.hpp:21
Determine the length of a fixed-size string.