54 [[nodiscard]]
inline std::uint32_t
xxhash32(std::span< std::byte const > input, std::uint32_t seed = 0U)
noexcept
56 constexpr std::uint32_t prime1 = 0x9e3779b1U;
57 constexpr std::uint32_t prime2 = 0x85ebca77U;
58 constexpr std::uint32_t prime3 = 0xc2b2ae3dU;
59 constexpr std::uint32_t prime4 = 0x27d4eb2fU;
60 constexpr std::uint32_t prime5 = 0x165667b1U;
61 std::size_t position = 0U;
62 std::uint32_t hash = 0U;
63 if (input.size() >= 16U)
65 std::uint32_t lane1 = seed + prime1 + prime2;
66 std::uint32_t lane2 = seed + prime2;
67 std::uint32_t lane3 = seed;
68 std::uint32_t lane4 = seed - prime1;
69 while (position + 16U <= input.size())
83 hash +=
static_cast< std::uint32_t
>(input.size());
84 while (position + 4U <= input.size())
89 while (position < input.size())
91 hash =
rotate_left(hash + std::to_integer< std::uint8_t >(input[position]) * prime5, 11U) * prime1;
112 m_buffer[m_buffer_size++] =
value;
114 if (m_buffer_size == m_buffer.size())
116 m_lane1 = round(m_lane1,
read_word(m_buffer, 0U));
117 m_lane2 = round(m_lane2,
read_word(m_buffer, 4U));
118 m_lane3 = round(m_lane3,
read_word(m_buffer, 8U));
119 m_lane4 = round(m_lane4,
read_word(m_buffer, 12U));
128 [[nodiscard]] std::uint32_t
value() const noexcept
130 constexpr std::uint32_t prime1 = 0x9e3779b1U;
131 constexpr std::uint32_t prime2 = 0x85ebca77U;
132 constexpr std::uint32_t prime3 = 0xc2b2ae3dU;
133 constexpr std::uint32_t prime4 = 0x27d4eb2fU;
134 constexpr std::uint32_t prime5 = 0x165667b1U;
136 hash +=
static_cast< std::uint32_t
>(m_total_size);
137 std::size_t position = 0U;
138 std::span< std::byte const >
const remaining(m_buffer.data(), m_buffer_size);
139 while (position + 4U <= remaining.size())
144 while (position < remaining.size())
146 hash =
rotate_left(hash + std::to_integer< std::uint8_t >(remaining[position]) * prime5, 11U) * prime1;
164 [[nodiscard]]
static std::uint32_t round(std::uint32_t lane, std::uint32_t
value)
noexcept
166 constexpr std::uint32_t prime1 = 0x9e3779b1U;
167 constexpr std::uint32_t prime2 = 0x85ebca77U;
171 std::array< std::byte, 16U > m_buffer{};
172 std::size_t m_buffer_size = 0U;
173 std::size_t m_total_size = 0U;
174 std::uint32_t m_lane1 = 0x9e3779b1U + 0x85ebca77U;
175 std::uint32_t m_lane2 = 0x85ebca77U;
176 std::uint32_t m_lane3 = 0U;
177 std::uint32_t m_lane4 = 0U - 0x9e3779b1U;
201 [[nodiscard]]
inline std::vector< std::byte >
compress_block(std::span< std::byte const > input, std::int32_t level)
203 constexpr std::size_t no_position = std::numeric_limits< std::size_t >::max();
204 std::array< std::size_t, 65536U > heads{};
205 heads.fill(no_position);
206 std::vector< std::size_t > previous(input.size(), no_position);
207 std::vector< std::byte > output;
208 std::size_t anchor = 0U;
209 std::size_t position = 0U;
210 std::size_t
const search_depth = level == 0 ? 1U : 4U +
static_cast< std::size_t
>(level) * 16U;
211 auto hash_at = [&](std::size_t offset)
213 return static_cast< std::uint16_t
>((
read_word(input, offset) * 2654435761U) >> 16U);
216 while (position + 12U <= input.size())
218 std::uint16_t
const hash = hash_at(position);
219 std::size_t candidate = heads[hash];
220 previous[position] = candidate;
221 heads[hash] = position;
222 std::size_t best_length = 0U;
223 std::size_t best_distance = 0U;
224 std::size_t depth = 0U;
225 while (candidate != no_position && position - candidate <= 65535U && depth < search_depth)
229 std::size_t length = 4U;
230 std::size_t
const maximum_match_length = input.size() - position - 5U;
231 while (length < maximum_match_length && input[candidate + length] == input[position + length])
235 if (length > best_length)
237 best_length = length;
238 best_distance = position - candidate;
241 candidate = previous[candidate];
244 if (best_length < 4U)
250 std::size_t
const literal_length = position - anchor;
251 std::size_t
const match_length = best_length - 4U;
252 std::size_t
const token_position = output.size();
253 output.push_back(std::byte{0x00});
254 std::uint8_t token =
static_cast< std::uint8_t
>(std::min< std::size_t >(literal_length, 15U) << 4U);
255 token =
static_cast< std::uint8_t
>(token | std::min< std::size_t >(match_length, 15U));
256 output[token_position] =
static_cast< std::byte
>(token);
257 if (literal_length >= 15U)
261 output.insert(output.end(), input.begin() +
static_cast< std::ptrdiff_t
>(anchor), input.begin() +
static_cast< std::ptrdiff_t
>(position));
262 output.push_back(
static_cast< std::byte
>(best_distance & 0xffU));
263 output.push_back(
static_cast< std::byte
>((best_distance >> 8U) & 0xffU));
264 if (match_length >= 15U)
269 std::size_t
const match_end = position + best_length;
270 for (std::size_t inserted = position + 1U; inserted < match_end && inserted + 4U <= input.size(); ++inserted)
272 std::uint16_t
const inserted_hash = hash_at(inserted);
273 previous[inserted] = heads[inserted_hash];
274 heads[inserted_hash] = inserted;
276 position = match_end;
280 std::size_t
const literal_length = input.size() - anchor;
281 output.push_back(
static_cast< std::byte
>(std::min< std::size_t >(literal_length, 15U) << 4U));
282 if (literal_length >= 15U)
286 output.insert(output.end(), input.begin() +
static_cast< std::ptrdiff_t
>(anchor), input.end());
338 std::int32_t
const level = options.
level.value_or(0);
339 if (level < 0 || level > 12)
343 auto write_u32 = [&](std::uint32_t value)
345 for (std::uint8_t index = 0U; index < 4U; ++index)
350 write_u32(0x184d2204U);
351 std::array< std::byte, 2U >
const descriptor{std::byte{0x60}, std::byte{0x40}};
356 constexpr std::size_t block_limit = 64U * 1024U;
357 std::vector< std::byte > block;
358 block.reserve(block_limit);
359 while (first != last)
362 while (first != last && block.size() < block_limit)
368 if (encoded.size() < block.size())
370 write_u32(
static_cast< std::uint32_t
>(encoded.size()));
371 for (std::byte value : encoded)
378 write_u32(
static_cast< std::uint32_t
>(block.size()) | 0x80000000U);
379 for (std::byte value : block)
404 auto read_byte = [&]() -> std::byte
407 if (!reader.
read(value))
413 auto read_u32 = [&]() -> std::uint32_t
415 std::uint32_t value = 0U;
416 for (std::uint8_t index = 0U; index < 4U; ++index)
418 value |=
static_cast< std::uint32_t
>(std::to_integer< std::uint8_t >(read_byte())) << (index * 8U);
422 std::array< std::byte, 65536U > history{};
423 std::size_t total_output = 0U;
424 bool decoded_frame =
false;
431 if (read_u32() != 0x184d2204U)
435 std::array< std::byte, 10U > descriptor{};
436 std::size_t descriptor_size = 0U;
437 std::byte
const flags_byte = read_byte();
438 std::byte
const block_descriptor_byte = read_byte();
439 descriptor[descriptor_size++] = flags_byte;
440 descriptor[descriptor_size++] = block_descriptor_byte;
441 std::uint8_t
const flags = std::to_integer< std::uint8_t >(flags_byte);
442 std::uint8_t
const block_descriptor = std::to_integer< std::uint8_t >(block_descriptor_byte);
443 if ((flags & 0xc0U) != 0x40U || (flags & 0x02U) != 0U || (block_descriptor & 0x8fU) != 0U)
447 std::uint8_t
const block_size_code =
static_cast< std::uint8_t
>((block_descriptor >> 4U) & 0x07U);
448 if (block_size_code < 4U || block_size_code > 7U)
452 constexpr std::array< std::size_t, 4U > maximum_block_sizes{64U * 1024U, 256U * 1024U, 1024U * 1024U, 4U * 1024U * 1024U};
453 std::size_t
const maximum_block_size = maximum_block_sizes[block_size_code - 4U];
454 std::optional< std::uint64_t > content_size;
455 if ((flags & 0x08U) != 0U)
457 std::uint64_t size = 0U;
458 for (std::uint8_t index = 0U; index < 8U; ++index)
460 std::byte
const value = read_byte();
461 descriptor[descriptor_size++] = value;
462 size |=
static_cast< std::uint64_t
>(std::to_integer< std::uint8_t >(value)) << (index * 8U);
466 if ((flags & 0x01U) != 0U)
470 if (std::to_integer< std::uint8_t >(read_byte()) !=
static_cast< std::uint8_t
>((
xxhash32(std::span< std::byte const >(descriptor).first(descriptor_size)) >> 8U) & 0xffU))
475 std::size_t
const frame_begin = total_output;
476 std::size_t history_begin = frame_begin;
478 auto emit = [&](std::byte value)
484 history[total_output % history.size()] = value;
486 if ((flags & 0x04U) != 0U)
488 frame_checksum.
update(value);
495 std::uint32_t
const block_header = read_u32();
496 if (block_header == 0U)
500 bool const uncompressed = (block_header & 0x80000000U) != 0U;
501 std::size_t
const block_size = block_header & 0x7fffffffU;
502 if (block_size > maximum_block_size)
506 std::vector< std::byte > block;
507 block.reserve(block_size);
508 for (std::size_t index = 0U; index < block_size; ++index)
510 block.push_back(read_byte());
512 if ((flags & 0x10U) != 0U && read_u32() !=
xxhash32(block))
516 if ((flags & 0x20U) != 0U)
518 history_begin = total_output;
522 for (std::byte value : block)
529 std::size_t position = 0U;
530 while (position < block.size())
532 std::uint8_t
const token = std::to_integer< std::uint8_t >(block[position++]);
534 if (literal_length > block.size() - std::min(position, block.size()))
538 for (std::size_t index = 0U; index < literal_length; ++index)
540 emit(block[position++]);
542 if (position == block.size())
546 if (block.size() - position < 2U)
550 std::size_t
const distance = std::to_integer< std::uint8_t >(block[position]) | (
static_cast< std::size_t
>(std::to_integer< std::uint8_t >(block[position + 1U])) << 8U);
553 if (distance == 0U || distance > total_output - history_begin || distance > history.size())
557 for (std::size_t index = 0U; index < match_length; ++index)
559 emit(history[(total_output - distance) % history.size()]);
563 if ((flags & 0x04U) != 0U && read_u32() != frame_checksum.
value())
567 if (content_size.has_value() && total_output - frame_begin != *content_size)
571 decoded_frame =
true;
572 }
while (!reader.
empty());