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
40*/
41
42use crate::codes::*;
43use crate::impls::*;
44use crate::traits::*;
45use common_traits::*;
46#[cfg(feature = "mem_dbg")]
47use mem_dbg::{MemDbg, MemSize};
48use std::error::Error;
49
50/// Marker trait for read-parameters selector types.
51///
52/// Note that in principle marker traits are not necessary to use
53/// selector types, but they are useful to avoid that the user specifies
54/// a nonsensical type, and to document the meaning of type parameters.
55pub trait ReadParams {}
56
57/// A selector type for read parameters providing reasonable defaults.
58///
59/// If you want to optimize these choices for your architecture, we suggest to
60/// run the benchmarks in the `benchmarks` directory and write your
61/// own implementation.
62#[derive(Debug, Clone)]
63#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
64pub struct DefaultReadParams;
65impl ReadParams for DefaultReadParams {}
66
67macro_rules! impl_default_read_codes {
68    ($($endianess:ident),*) => {$(
69        impl<WR: WordRead> GammaRead<$endianess>
70            for BufBitReader<$endianess, WR, DefaultReadParams>
71        where
72            WR:: Word: DoubleType + UpcastableInto<u64>,
73            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
74        {
75            #[inline(always)]
76            fn read_gamma(&mut self) -> Result<u64, Self::Error> {
77                // From our tests, the ARM architecture is faster
78                // without tables for ɣ codes.
79                self.read_gamma_param::<false>()
80            }
81        }
82
83        impl<WR: WordRead> DeltaRead<$endianess>
84            for BufBitReader<$endianess, WR, DefaultReadParams>
85        where
86            WR:: Word: DoubleType + UpcastableInto<u64>,
87            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
88        {
89            #[inline(always)]
90            fn read_delta(&mut self) -> Result<u64, Self::Error> {
91                self.read_delta_param::<false, true>()
92            }
93        }
94
95        impl<WR: WordRead> ZetaRead<$endianess>
96            for BufBitReader<$endianess, WR, DefaultReadParams>
97        where
98            WR:: Word: DoubleType + UpcastableInto<u64>,
99            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
100        {
101            #[inline(always)]
102            fn read_zeta(&mut self, k: usize) -> Result<u64, Self::Error> {
103                self.read_zeta_param(k)
104            }
105
106            #[inline(always)]
107            fn read_zeta3(&mut self) -> Result<u64, Self::Error> {
108                self.read_zeta3_param::<true>()
109            }
110        }
111
112        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> GammaRead<$endianess>
113            for BitReader<$endianess, WR, DefaultReadParams>
114        where
115            WR:: Word: DoubleType + UpcastableInto<u64>,
116            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
117        {
118            #[inline(always)]
119            fn read_gamma(&mut self) -> Result<u64, Self::Error> {
120                // From our tests, the ARM architecture is faster
121                // without tables for ɣ codes.
122                self.read_gamma_param::<false>()
123            }
124        }
125
126        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> DeltaRead<$endianess>
127            for BitReader<$endianess, WR, DefaultReadParams>
128        where
129            WR:: Word: DoubleType + UpcastableInto<u64>,
130            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
131        {
132            #[inline(always)]
133            fn read_delta(&mut self) -> Result<u64, Self::Error> {
134                self.read_delta_param::<false, true>()
135            }
136        }
137
138        impl<E: Error + Send + Sync + 'static, WR: WordRead<Error = E, Word = u64> + WordSeek<Error = E>> ZetaRead<$endianess>
139            for BitReader<$endianess, WR, DefaultReadParams>
140        where
141            WR:: Word: DoubleType + UpcastableInto<u64>,
142            <WR::Word as DoubleType>::DoubleType: CastableInto<u64>,
143        {
144            #[inline(always)]
145            fn read_zeta(&mut self, k: usize) -> Result<u64, Self::Error> {
146                self.read_zeta_param(k)
147            }
148
149            #[inline(always)]
150            fn read_zeta3(&mut self) -> Result<u64, Self::Error> {
151                self.read_zeta3_param::<true>()
152            }
153        }
154    )*};
155}
156
157impl_default_read_codes! {LittleEndian, BigEndian}
158
159/// Marker trait for write-parameters selector types.
160///
161/// Note that in principle marker traits are not necessary to use
162/// selector types, but they are useful to avoid that the user specifies
163/// a nonsensical type, and to document the meaning of type parameters.
164pub trait WriteParams {}
165
166/// A selector type for write parameters providing reasonable defaults.
167///
168/// If you want to optimize these choices for your architecture, we suggest to
169/// run the benchmarks in the `benchmarks` directory and write your
170/// own implementation.
171#[derive(Debug, Clone)]
172#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
173pub struct DefaultWriteParams;
174impl WriteParams for DefaultWriteParams {}
175
176macro_rules! impl_default_write_codes {
177    ($($endianess:ident),*) => {$(
178        impl<WR: WordWrite> GammaWrite<$endianess>
179            for BufBitWriter<$endianess, WR, DefaultWriteParams>
180            where u64: CastableInto<WR::Word>,
181        {
182            #[inline(always)]
183            fn write_gamma(&mut self, value: u64) -> Result<usize, Self::Error> {
184                self.write_gamma_param::<true>(value)
185            }
186        }
187
188        impl<WR: WordWrite, DC: WriteParams> DeltaWrite<$endianess>
189            for BufBitWriter<$endianess, WR, DC>
190            where u64: CastableInto<WR::Word>,
191        {
192            #[inline(always)]
193            fn write_delta(&mut self, value: u64) -> Result<usize, Self::Error> {
194                self.write_delta_param::<true, true>(value)
195            }
196        }
197
198        impl<WR: WordWrite, DC: WriteParams> ZetaWrite<$endianess>
199            for BufBitWriter<$endianess, WR, DC>
200            where u64: CastableInto<WR::Word>,
201        {
202            #[inline(always)]
203            fn write_zeta(&mut self, value: u64, k: usize) -> Result<usize, Self::Error> {
204                self.write_zeta_param::<true>(value, k)
205            }
206
207            #[inline(always)]
208            fn write_zeta3(&mut self, value: u64) -> Result<usize, Self::Error> {
209                self.write_zeta3_param::<true>(value)
210            }
211        }
212
213    )*};
214}
215
216impl_default_write_codes! {LittleEndian, BigEndian}