dsi_bitstream/codes/
params.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 LGPL-2.1-or-later
7 */
8
9/*!
10
11Mechanisms for selecting parameters.
12
13Traits and structures in this file are of no interest for the standard
14user. Their purpose is to provide a systematic way, and in particular
15a default way, to select parameters for parameterized traits
16such as [`GammaReadParam`] and [`GammaWriteParam`].
17
18The traits and structure in this module work closely with the
19bitstream readers and writers in [`impls`](crate::impls), which have an
20additional type parameter `RP`/`WP` that must
21implement marker traits [`ReadParams`] or [`WriteParams`], respectively.
22The type is then used as a selector type to provide blanket implementations
23of parameterless traits in [`codes`](crate::codes) such as [`GammaRead`],
24[`GammaWrite`], [`DeltaRead`], [`DeltaWrite`], and so on.
25
26This module provides default selector types [`DefaultReadParams`] and [`DefaultWriteParams`]
27which are also the default value for the parameter `RP`/`WP` in the bitstream
28readers and writers in [`crate::impls`]. Type-selected blanket implementations
29of all parameterless traits in [`crate::codes`] are provided for the bitstream
30readers and writers in [`impls`](crate::impls). Thus, if you not specify a value for the
31parameter `RP`/`WP`, you will obtain automatically
32the blanket implementations for parameterless traits contained in this module.
33
34However, you can also create new selector types implementing [`ReadParams`]/[`WriteParams`] and
35write blanket implementations for the bitstream readers and writers in [`crate::impls`]
36where `RP`/`WP` is set to your selector types. Then, by specifying your type as value of the
37parameter `RP`/`WP` when creating such readers and writers you will use
38automatically your blanket implementations instead of the ones provided by this module.
39
40Note that the default implementations provided by this module are targeted at
41`u32` read words and `u64` write words. If you use different word sizes,
42you may want to write your own selector types.
43
44*/
45
46use crate::codes::*;
47use crate::impls::*;
48use crate::traits::*;
49use common_traits::*;
50use core::error::Error;
51#[cfg(feature = "mem_dbg")]
52use mem_dbg::{MemDbg, MemSize};
53
54/// Marker trait for read-parameters selector types.
55///
56/// Note that in principle marker traits are not necessary to use
57/// selector types, but they are useful to avoid that the user specifies
58/// a nonsensical type, and to document the meaning of type parameters.
59pub trait ReadParams {}
60
61/// A selector type for read parameters providing reasonable defaults.
62///
63/// If you want to optimize these choices for your architecture, we suggest to
64/// run the benchmarks in the `benchmarks` directory and write your
65/// own implementation.
66#[derive(Debug, Clone)]
67#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
68pub struct DefaultReadParams;
69impl ReadParams for DefaultReadParams {}
70
71macro_rules! impl_default_read_codes {
72    ($($endianess:ident),*) => {$(
73        impl<WR: WordRead> GammaRead<$endianess>
74            for BufBitReader<$endianess, WR, DefaultReadParams>
75        where
76            WR:: Word: DoubleType + UpcastableInto<u64>,
77            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
78        {
79            #[inline(always)]
80            fn read_gamma(&mut self) -> Result<u64, Self::Error> {
81                // From our tests on all architectures ɣ codes are faster
82                // without tables
83                self.read_gamma_param::<false>()
84            }
85        }
86
87        impl<WR: WordRead> DeltaRead<$endianess>
88            for BufBitReader<$endianess, WR, DefaultReadParams>
89        where
90            WR:: Word: DoubleType + UpcastableInto<u64>,
91            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
92        {
93            #[inline(always)]
94            fn read_delta(&mut self) -> Result<u64, Self::Error> {
95                self.read_delta_param::<false, true>()
96            }
97        }
98
99        impl<WR: WordRead> OmegaRead<$endianess>
100            for BufBitReader<$endianess, WR, DefaultReadParams>
101        where
102            WR:: Word: DoubleType + UpcastableInto<u64>,
103            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
104        {
105            #[inline(always)]
106            fn read_omega(&mut self) -> Result<u64, Self::Error> {
107                self.read_omega_param::<true>()
108            }
109        }
110
111        impl<WR: WordRead> ZetaRead<$endianess>
112            for BufBitReader<$endianess, WR, DefaultReadParams>
113        where
114            WR:: Word: DoubleType + UpcastableInto<u64>,
115            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
116        {
117            #[inline(always)]
118            fn read_zeta(&mut self, k: usize) -> Result<u64, Self::Error> {
119                self.read_zeta_param(k)
120            }
121
122            #[inline(always)]
123            fn read_zeta3(&mut self) -> Result<u64, Self::Error> {
124                self.read_zeta3_param::<true>()
125            }
126        }
127
128        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> GammaRead<$endianess>
129            for BitReader<$endianess, WR, DefaultReadParams>
130        where
131            WR:: Word: DoubleType + UpcastableInto<u64>,
132            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
133        {
134            #[inline(always)]
135            fn read_gamma(&mut self) -> Result<u64, Self::Error> {
136                // From our tests, the ARM architecture is faster
137                // without tables for ɣ codes.
138                self.read_gamma_param::<false>()
139            }
140        }
141
142        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> DeltaRead<$endianess>
143            for BitReader<$endianess, WR, DefaultReadParams>
144        where
145            WR:: Word: DoubleType + UpcastableInto<u64>,
146            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
147        {
148            #[inline(always)]
149            fn read_delta(&mut self) -> Result<u64, Self::Error> {
150                self.read_delta_param::<false, true>()
151            }
152        }
153
154        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> OmegaRead<$endianess>
155            for BitReader<$endianess, WR, DefaultReadParams>
156        where
157            WR:: Word: DoubleType + UpcastableInto<u64>,
158            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
159        {
160            #[inline(always)]
161            fn read_omega(&mut self) -> Result<u64, Self::Error> {
162                self.read_omega_param::<true>()
163            }
164        }
165
166        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> ZetaRead<$endianess>
167            for BitReader<$endianess, WR, DefaultReadParams>
168        where
169            WR:: Word: DoubleType + UpcastableInto<u64>,
170            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
171        {
172            #[inline(always)]
173            fn read_zeta(&mut self, k: usize) -> Result<u64, Self::Error> {
174                self.read_zeta_param(k)
175            }
176
177            #[inline(always)]
178            fn read_zeta3(&mut self) -> Result<u64, Self::Error> {
179                self.read_zeta3_param::<true>()
180            }
181        }
182    )*};
183}
184
185impl_default_read_codes! {LittleEndian, BigEndian}
186
187/// Marker trait for write-parameters selector types.
188///
189/// Note that in principle marker traits are not necessary to use
190/// selector types, but they are useful to avoid that the user specifies
191/// a nonsensical type, and to document the meaning of type parameters.
192pub trait WriteParams {}
193
194/// A selector type for write parameters providing reasonable defaults.
195///
196/// If you want to optimize these choices for your architecture, we suggest to
197/// run the benchmarks in the `benchmarks` directory and write your
198/// own implementation.
199#[derive(Debug, Clone)]
200#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
201pub struct DefaultWriteParams;
202impl WriteParams for DefaultWriteParams {}
203
204macro_rules! impl_default_write_codes {
205    ($($endianess:ident),*) => {$(
206        impl<WR: WordWrite> GammaWrite<$endianess>
207            for BufBitWriter<$endianess, WR, DefaultWriteParams>
208            where u64: CastableInto<WR::Word>,
209        {
210            #[inline(always)]
211            fn write_gamma(&mut self, value: u64) -> Result<usize, Self::Error> {
212                self.write_gamma_param::<true>(value)
213            }
214        }
215
216        impl<WR: WordWrite, DC: WriteParams> DeltaWrite<$endianess>
217            for BufBitWriter<$endianess, WR, DC>
218            where u64: CastableInto<WR::Word>,
219        {
220            #[inline(always)]
221            fn write_delta(&mut self, value: u64) -> Result<usize, Self::Error> {
222                self.write_delta_param::<true, true>(value)
223            }
224        }
225
226        impl<WR: WordWrite, WP: WriteParams> OmegaWrite<$endianess>
227            for BufBitWriter<$endianess, WR, WP>
228            where u64: CastableInto<WR::Word>,
229        {
230            #[inline(always)]
231            fn write_omega(&mut self, value: u64) -> Result<usize, Self::Error> {
232                self.write_omega_param::<true>(value)
233            }
234        }
235
236        impl<WR: WordWrite, DC: WriteParams> ZetaWrite<$endianess>
237            for BufBitWriter<$endianess, WR, DC>
238            where u64: CastableInto<WR::Word>,
239        {
240            #[inline(always)]
241            fn write_zeta(&mut self, value: u64, k: usize) -> Result<usize, Self::Error> {
242                self.write_zeta_param::<true>(value, k)
243            }
244
245            #[inline(always)]
246            fn write_zeta3(&mut self, value: u64) -> Result<usize, Self::Error> {
247                self.write_zeta3_param::<true>(value)
248            }
249        }
250
251    )*};
252}
253
254impl_default_write_codes! {LittleEndian, BigEndian}