32constexpr size_t kBasketHeaderTail = 19;
35void byteswapAll(uint8_t*
data,
size_t count)
39 std::memcpy(&
v,
data +
i *
sizeof(T),
sizeof(T));
41 std::memcpy(
data +
i *
sizeof(T), &
v,
sizeof(T));
48 if constexpr (std::endian::native == std::endian::big) {
99void BranchDecoder::checkBaskets(
BranchInfo const& branch)
const
102 for (
auto&
b : branch.baskets) {
103 if (
b.firstEntry != next ||
b.nEntries < 0) {
104 throw CorruptData(mUrl,
b.seek,
"baskets of branch " + branch.
name +
" do not cover its entries contiguously");
114void BranchDecoder::forEachBasket(BranchInfo
const& branch,
bool parallel, F&& fn)
116 checkBaskets(branch);
117 auto task = [
this, &branch, &fn](
size_t i) {
118 auto const&
ref = branch.baskets[
i];
120 std::vector<uint8_t> storage;
123 values.border =
ref.embeddedPayload.size();
128 throw CorruptData(mUrl,
ref.seek,
"basket of branch " + branch.name +
" past the end of the file");
130 storage.resize(
ref.nbytes);
135 auto nbytes =
c.u32();
137 auto objlen =
c.u32();
139 auto keylen =
c.u16();
140 if (nbytes !=
ref.nbytes || keylen < kBasketHeaderTail || keylen > nbytes) {
141 c.fail(
"basket header of branch " + branch.name +
" does not match its TBranch");
143 c.seek(keylen - kBasketHeaderTail);
147 auto nevbuf =
c.i32();
149 if (nevbuf !=
ref.nEntries || last < keylen || (uint32_t)(last - keylen) > objlen) {
150 c.fail(
"basket header of branch " + branch.name +
" does not match its TBranch");
153 auto payload =
bytes.subspan(keylen);
154 if (objlen != nbytes - keylen) {
155 values.compressed.emplace(payload, objlen, mUrl,
ref.seek + keylen);
163 auto n = branch.baskets.size();
166 for (
size_t i = 0;
i <
n; ++
i) {
172 std::atomic<size_t> next = 0;
173 std::exception_ptr
error;
174 std::mutex errorMutex;
175 std::vector<std::thread> workers;
176 for (
int t = 0; t < threads; ++t) {
177 workers.emplace_back([&] {
178 for (
size_t i; (
i = next.fetch_add(1)) <
n;) {
182 std::lock_guard lock{errorMutex};
184 error = std::current_exception();
191 for (
auto&
w : workers) {
195 std::rethrow_exception(
error);
201void checkNeeded(std::string
const&
url, BranchInfo
const& branch, BasketRef
const&
ref,
size_t needed,
size_t border)
212 size_t rowBytes = elementSize * branch.
fixedLen;
213 if (nbytes != branch.
entries * rowBytes) {
218 size_t needed =
ref.nEntries * rowBytes;
219 checkNeeded(mUrl, branch,
ref, needed,
values.border);
220 auto* out =
dst +
ref.firstEntry * rowBytes;
221 values.readAll(out, needed);
232 if (nbytes != (
size_t)
offsets.back() * elementSize) {
242 size_t needed = (size_t)(
end - begin) * elementSize;
243 checkNeeded(mUrl, branch,
ref, needed,
values.border);
244 auto* out =
dst + (size_t)begin * elementSize;
245 values.readAll(out, needed);
253 if (nbytes * 8 < total) {
256 std::memset(bitmap, 0, nbytes);
263 size_t remaining = (size_t)
ref.nEntries * branch.
fixedLen;
264 checkNeeded(mUrl, branch,
ref, remaining,
values.border);
265 while (remaining > 0) {
266 auto k = std::min(remaining, window.size());
267 values.read(window.data(), k);
268 for (
size_t j = 0;
j < k; ++
j, ++
index) {
269 bitmap[
index / 8] |= (uint8_t)((window[
j] != 0) << (
index % 8));
289 if (total > INT32_MAX) {
char error[CURL_ERROR_SIZE]
void decodeVLAValues(BranchInfo const &branch, std::span< const int32_t > offsets, uint8_t *dst, size_t nbytes)
std::vector< int32_t > decodeOffsets(BranchInfo const &sizeBranch)
Decodes a <col>_size branch into entries + 1 int32 offsets.
void decodeValues(BranchInfo const &branch, uint8_t *dst, size_t nbytes)
BranchDecoder(ByteSource &source, Options const &options)
static constexpr size_t kBooleanWindow
Size of the boolean window, the only decode-side scratch memory.
void decodeBooleans(BranchInfo const &branch, uint8_t *bitmap, size_t nbytes)
virtual uint64_t size() const =0
virtual void readInto(uint64_t off, size_t len, void *dst)=0
Throws IoError, or CorruptData when the range is past the end of the file.
virtual std::span< const uint8_t > tryMap(uint64_t off, size_t len)
A view of the bytes without copying them, if the backend can provide it.
GLint GLint GLsizei GLint border
GLuint GLsizei const GLuint const GLintptr * offsets
GLboolean GLboolean GLboolean b
GLsizei GLsizei GLchar * source
GLenum GLsizei GLsizei GLint * values
GLubyte GLubyte GLubyte GLubyte w
size_t leafElementSize(char leafClass)
Size in bytes of one value of a leaf class on disk.
void byteswapInPlace(uint8_t *data, size_t count, size_t typeSize)
Byteswaps count big-endian values of typeSize bytes in place.
WorkflowSpec parallel(DataProcessorSpec original, size_t maxIndex, std::function< void(DataProcessorSpec &, size_t id)> amendCallback)
std::string to_string(gsl::span< T, Size > span)
void readAll(uint8_t *dst, size_t n)
The first n value bytes as the only read: lets zstd decode in place.
void read(uint8_t *dst, size_t n)
std::span< const uint8_t > plain
std::optional< PayloadDecompressor > compressed
std::vector< BasketRef > baskets