dsi_bitstream/codes/mod.rs
1/*
2 * SPDX-FileCopyrightText: 2023 Tommaso Fontana
3 * SPDX-FileCopyrightText: 2023 Inria
4 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
5 *
6 * SPDX-License-Identifier: Apache-2.0 OR MIT
7 */
8
9//! Traits for reading and writing instantaneous codes.
10//!
11//! This module contains code for reading and writing instantaneous codes.
12//! Codewords are uniformly indexed from 0 for all codes. For example, the first
13//! few words of [unary], [γ], and [δ] codes are:
14//!
15//! | Arg | unary | γ | δ |
16//! |-----|---------:|--------:|---------:|
17//! | 0 | 1 | 1 | 1 |
18//! | 1 | 01 | 010 | 0100 |
19//! | 2 | 001 | 011 | 0101 |
20//! | 3 | 0001 | 00100 | 01100 |
21//! | 4 | 00001 | 00101 | 01101 |
22//! | 5 | 000001 | 00110 | 01110 |
23//! | 6 | 0000001 | 00111 | 01111 |
24//! | 7 | 00000001 | 0001000 | 00100000 |
25//!
26//! If you need to encode signed integers, please use the [`ToInt`] and
27//! [`ToNat`] traits, which provide a bijection between signed integers and
28//! natural numbers.
29//!
30//! Each code is implemented as a pair of traits for reading and writing (e.g.,
31//! [`GammaReadParam`] and [`GammaWriteParam`]). The traits for reading depend
32//! on [`BitRead`], whereas the traits for writing depend on [`BitWrite`]. Note
33//! that most codes cannot write the number [`u64::MAX`] because of overflow
34//! issues, which could be avoided with tests, but at the price of a significant
35//! performance drop.
36//!
37//! The traits ending with `Param` make it possible to specify parameters—for
38//! example, whether to use decoding tables. Usually, one would instead pull
39//! into scope non-parametric traits such as [`GammaRead`] and [`GammaWrite`],
40//! for which defaults are provided using the mechanism described in the
41//! [`params`] module.
42//!
43//! # Decoding untrusted input
44//!
45//! For performance, the decoders assume a well-formed stream produced by the
46//! corresponding encoder: some derived codeword lengths are guarded only by a
47//! `debug_assert!`, and other reachable arithmetic (shifts, `quotient * b`) is
48//! unchecked. A malformed or adversarial bit stream (for example one read
49//! through [`BufBitReader`] over an untrusted source) may therefore panic or
50//! return an incorrect value, depending on the code and on the
51//! `debug-assertions`/`overflow-checks` settings, instead of returning an
52//! error. The [VByte] decoders additionally check, in debug builds only, that a
53//! code terminates within the maximum length of a `u64` code and that its value
54//! fits a `u64`. Validate untrusted input, or restrict decoding to a trusted
55//! producer, before use; the [`Codes`] descriptor is itself validated when
56//! parsed or deserialized.
57//!
58//! # Big-endian vs. little-endian
59//!
60//! As discussed in the [traits module], in general reversing the bits of a
61//! big-endian bit stream will not yield a little-endian bit stream containing
62//! the same sequence of fixed-width integers. The same is true for codes,
63//! albeit the situation is more complex.
64//!
65//! The only code that can be safely reversed is the unary code. All other codes
66//! contain some value, and that value is written without reversing its bits.
67//! Thus, reversing the bits of a big-endian bit stream containing a sequence of
68//! instantaneous codes will not yield a little-endian bit stream containing the
69//! same sequence of codes (again, with the exception of unary codes).
70//! Technically, the codes written for the little-endian case are different from
71//! those written for the big-endian case.
72//!
73//! For example, the [γ code] of 4 is `00101` in big-endian order, but it is
74//! `01100` in little-endian order, so that upon reading the unary code for 2 we
75//! can read the `01` part without a bit reversal.
76//!
77//! The case of [minimal binary codes] is even more convoluted: for example, the
78//! code with upper bound 7 has codewords `00`, `010`, `011`, `100`, `101`,
79//! `110`, and `111`. To decode such a code without peeking at more bits than
80//! necessary, one first reads two bits, and then decides, based on their value,
81//! whether to read a further bit and add it on the right. But this means that
82//! we have to encode 2 as `011` in the big-endian case, and as `101` in the
83//! little-endian case, because we need to read the first two bits to decide
84//! whether to read the third one.
85//!
86//! In some cases, we resort to completely *ad hoc* solutions: for example, in
87//! the case of the [ω code], for the little-endian case instead of reversing
88//! the bits written at each recursive call (which in principle would be
89//! necessary), we simply rotate them to the left by one position, exposing the
90//! most significant bit as first bit. This is sufficient to make the decoding
91//! possible, and the rotation is a much faster operation than bit reversal.
92//!
93//! # Dispatch
94//!
95//! The basic method for accessing codes is through traits like [`GammaRead`]
96//! and [`GammaWrite`]. This approach, however, forces a choice of code in the
97//! source. To pass a choice of code dynamically, please have a look at the
98//! [`dispatch`] module.
99//!
100//! [unary]: crate::traits::BitRead::read_unary
101//! [γ]: gamma
102//! [δ]: delta
103//! [`GammaReadParam`]: gamma::GammaReadParam
104//! [`GammaWriteParam`]: gamma::GammaWriteParam
105//! [`BitRead`]: crate::traits::BitRead
106//! [`BitWrite`]: crate::traits::BitWrite
107//! [`BufBitReader`]: crate::impls::BufBitReader
108//! [VByte]: vbyte
109//! [`Codes`]: crate::dispatch::Codes
110//! [traits module]: crate::traits
111//! [γ code]: gamma
112//! [minimal binary codes]: minimal_binary
113//! [ω code]: omega
114//! [`dispatch`]: crate::dispatch
115
116use num_primitive::{PrimitiveNumberAs, PrimitiveSigned, PrimitiveUnsigned};
117
118pub mod params;
119
120pub mod gamma;
121pub use gamma::{GammaRead, GammaWrite, len_gamma};
122
123pub mod delta;
124pub use delta::{DeltaRead, DeltaWrite, len_delta};
125
126pub mod omega;
127pub use omega::{OmegaRead, OmegaWrite, len_omega};
128
129pub mod minimal_binary;
130pub use minimal_binary::{MinimalBinaryRead, MinimalBinaryWrite, len_minimal_binary};
131
132pub mod zeta;
133pub use zeta::{ZetaRead, ZetaWrite, len_zeta};
134
135pub mod pi;
136pub use pi::{PiRead, PiWrite, len_pi};
137
138pub mod golomb;
139pub use golomb::{GolombRead, GolombWrite, len_golomb};
140
141pub mod rice;
142pub use rice::{RiceRead, RiceWrite, len_rice};
143
144pub mod exp_golomb;
145pub use exp_golomb::{ExpGolombRead, ExpGolombWrite, len_exp_golomb};
146
147pub mod vbyte;
148pub use vbyte::{
149 VByteBeRead, VByteBeWrite, VByteLeRead, VByteLeWrite, bit_len_vbyte, byte_len_vbyte,
150};
151#[cfg(feature = "std")]
152pub use vbyte::{
153 vbyte_read, vbyte_read_be, vbyte_read_le, vbyte_write, vbyte_write_be, vbyte_write_le,
154};
155
156pub mod delta_tables;
157pub mod gamma_tables;
158pub mod omega_tables;
159pub mod pi_tables;
160pub mod zeta_tables;
161
162/// Extension trait mapping natural numbers bijectively to integers.
163///
164/// The method [`to_int`] will map a natural number `x` to `x / 2` if `x` is
165/// even, and to `−(x + 1) / 2` if `x` is odd. The inverse transformation is
166/// provided by the [`ToNat`] trait.
167///
168/// This pair of bijections makes it possible to use instantaneous codes for
169/// signed integers by mapping them to natural numbers and back.
170///
171/// This bijection is best known as the “ZigZag” transformation in Google's
172/// [Protocol Buffers], albeit it has been used by [WebGraph] since 2003, and
173/// most likely in other software, for the same purpose. Note that the
174/// compression standards H.264/H.265 use a different transformation for
175/// exponential Golomb codes, mapping a positive integer `x` to `2x − 1` and a
176/// zero or negative integer `x` to `−2x`.
177///
178/// The implementation uses a blanket implementation for all primitive
179/// unsigned integer types.
180///
181/// [`to_int`]: #method.to_int
182/// [Protocol Buffers]: https://protobuf.dev/
183/// [WebGraph]: http://webgraph.di.unimi.it/
184pub trait ToInt {
185 type Signed;
186 #[must_use]
187 fn to_int(self) -> Self::Signed;
188}
189
190impl<U: PrimitiveUnsigned + PrimitiveNumberAs<U::Signed>> ToInt for U
191where
192 U::Signed: PrimitiveSigned,
193{
194 type Signed = U::Signed;
195 #[inline]
196 fn to_int(self) -> U::Signed {
197 (self >> 1u32).as_to::<U::Signed>() ^ -((self & U::from(1u8)).as_to::<U::Signed>())
198 }
199}
200
201/// Extension trait mapping signed integers bijectively to natural numbers.
202///
203/// The method [`to_nat`] will map a nonnegative integer `x` to `2x` and a
204/// negative integer `x` to `−2x − 1`. The inverse transformation is provided by
205/// the [`ToInt`] trait.
206///
207/// This pair of bijections makes it possible to use instantaneous codes
208/// for signed integers by mapping them to natural numbers and back.
209///
210/// This bijection is best known as the “ZigZag” transformation in Google's
211/// [Protocol Buffers], albeit it has been used by [WebGraph] since 2003, and
212/// most likely in other software, for the same purpose. Note that the
213/// compression standards H.264/H.265 use a different transformation for
214/// exponential Golomb codes, mapping a positive integer `x` to `2x − 1` and a
215/// zero or negative integer `x` to `−2x`.
216///
217/// The implementation uses a blanket implementation for all primitive
218/// signed integer types.
219///
220/// [`to_nat`]: #method.to_nat
221/// [Protocol Buffers]: https://protobuf.dev/
222/// [WebGraph]: http://webgraph.di.unimi.it/
223pub trait ToNat {
224 type Unsigned;
225 #[must_use]
226 fn to_nat(self) -> Self::Unsigned;
227}
228
229impl<S: PrimitiveSigned + PrimitiveNumberAs<S::Unsigned>> ToNat for S
230where
231 S::Unsigned: PrimitiveUnsigned,
232{
233 type Unsigned = S::Unsigned;
234 #[inline]
235 fn to_nat(self) -> S::Unsigned {
236 (self << 1u32).as_to::<S::Unsigned>() ^ (self >> (S::BITS - 1)).as_to::<S::Unsigned>()
237 }
238}