// Byte counts of a block's literals, in one pass: the whole block's and
// those of the four streams it may be split into.
//
// Each step counts one byte of each of the four streams into that
// stream's own table, as zstd's HIST_count_parallel spreads its counts
// over four tables: consecutive increments go to different tables, so a
// run of one byte value does not make each increment wait for the store
// of the one before. Native and Wasm read four bytes of each stream at
// once, unchecked; JS and Wasm GC read byte by byte, checked.
///|
/// Counts `data[start:start + len]`, `len` at least 4, into `quarters`,
/// the stream of `HuffmanEncoder::write_literals` each byte goes to, and
/// their sum into `counts`. Every table has 256 entries.
fn count_quarters(
data : FixedArray[Byte],
start : Int32,
len : Int32,
counts : FixedArray[Int32],
quarters : FixedArray[FixedArray[Int32]],
) -> Unit {
let c0 = quarters[0]
let c1 = quarters[1]
let c2 = quarters[2]
let c3 = quarters[3]
c0.fill(0)
c1.fill(0)
c2.fill(0)
c3.fill(0)
// Three streams of `segment` bytes and a last one of `last`, at least 1
// byte since len >= 4, and at most `segment`.
let segment = (len + 3) / 4
let last = len - 3 * segment
let a = start
let b = a + segment
let c = b + segment
let d = c + segment
let j = count_four(data, a, b, c, d, last, c0, c1, c2, c3)
for k in j.. Int32 {
let bytes = data.unsafe_reinterpret_as_bytes()
let mut j = 0
while j + 4 <= n {
// j + 4 <= n <= every stream's length, and the streams lie within the
// caller's range of `data`: the four loads read valid bytes.
let wa = bytes.unsafe_read_uint32_le(a + j)
let wb = bytes.unsafe_read_uint32_le(b + j)
let wc = bytes.unsafe_read_uint32_le(c + j)
let wd = bytes.unsafe_read_uint32_le(d + j)
bump_word(c0, c1, c2, c3, wa, wb, wc, wd, 0)
bump_word(c0, c1, c2, c3, wa, wb, wc, wd, 8)
bump_word(c0, c1, c2, c3, wa, wb, wc, wd, 16)
bump_word(c0, c1, c2, c3, wa, wb, wc, wd, 24)
j += 4
}
j
}
///|
/// Counts the byte at `shift` of each stream's word into its table.
#cfg(any(target="native", target="wasm"))
#inline
fn bump_word(
c0 : FixedArray[Int32],
c1 : FixedArray[Int32],
c2 : FixedArray[Int32],
c3 : FixedArray[Int32],
wa : UInt32,
wb : UInt32,
wc : UInt32,
wd : UInt32,
shift : Int32,
) -> Unit {
bump_index(c0, ((wa >> shift) & 255).reinterpret_as_int())
bump_index(c1, ((wb >> shift) & 255).reinterpret_as_int())
bump_index(c2, ((wc >> shift) & 255).reinterpret_as_int())
bump_index(c3, ((wd >> shift) & 255).reinterpret_as_int())
}
///|
#cfg(not(any(target="native", target="wasm")))
fn count_four(
_data : FixedArray[Byte],
_a : Int32,
_b : Int32,
_c : Int32,
_d : Int32,
_n : Int32,
_c0 : FixedArray[Int32],
_c1 : FixedArray[Int32],
_c2 : FixedArray[Int32],
_c3 : FixedArray[Int32],
) -> Int32 {
0
}
///|
/// Adds one to the count of `byte`, in a table of 256.
#inline
fn bump(table : FixedArray[Int32], byte : Byte) -> Unit {
bump_index(table, byte.to_int())
}
///|
/// Adds one to `table[i]`; the caller's `i` is a byte value, below the
/// table's 256 entries.
#cfg(any(target="native", target="wasm"))
#inline
fn bump_index(table : FixedArray[Int32], i : Int32) -> Unit {
table.unsafe_set(i, table.unsafe_get(i) + 1)
}
///|
#cfg(not(any(target="native", target="wasm")))
#inline
fn bump_index(table : FixedArray[Int32], i : Int32) -> Unit {
table[i] += 1
}