dsi_bitstream/codes/
gamma.rs1use super::gamma_tables;
31use crate::traits::*;
32
33#[must_use]
35#[inline(always)]
36pub const fn len_gamma_param<const USE_TABLE: bool>(mut n: u64) -> usize {
37 debug_assert!(n < u64::MAX);
38 if USE_TABLE {
39 if n < gamma_tables::LEN.len() as u64 {
41 return gamma_tables::LEN[n as usize] as usize;
42 }
43 }
44 n += 1;
45 let λ = n.ilog2();
46 2 * λ as usize + 1
47}
48
49#[must_use]
52#[inline(always)]
53pub const fn len_gamma(n: u64) -> usize {
54 #[cfg(target_arch = "arm")]
55 return len_gamma_param::<false>(n);
56 #[cfg(not(target_arch = "arm"))]
57 return len_gamma_param::<true>(n);
58}
59
60pub trait GammaRead<E: Endianness>: BitRead<E> {
64 fn read_gamma(&mut self) -> Result<u64, Self::Error>;
65}
66
67pub trait GammaReadParam<E: Endianness>: BitRead<E> {
76 fn read_gamma_param<const USE_TABLE: bool>(&mut self) -> Result<u64, Self::Error>;
77}
78
79#[inline(always)]
82fn default_read_gamma<E: Endianness, B: BitRead<E>>(backend: &mut B) -> Result<u64, B::Error> {
83 let len = backend.read_unary()?;
84 debug_assert!(len < 64);
85 Ok(backend.read_bits(len as usize)? + (1 << len) - 1)
86}
87
88impl<B: BitRead<BE>> GammaReadParam<BE> for B {
89 #[inline(always)]
90 fn read_gamma_param<const USE_TABLE: bool>(&mut self) -> Result<u64, Self::Error> {
91 const {
92 if USE_TABLE {
93 gamma_tables::check_read_table(B::PEEK_BITS)
94 }
95 }
96 if USE_TABLE {
97 if let Some((res, _)) = gamma_tables::read_table_be(self) {
98 return Ok(res);
99 }
100 }
101 default_read_gamma(self)
102 }
103}
104
105impl<B: BitRead<LE>> GammaReadParam<LE> for B {
106 #[inline(always)]
107 fn read_gamma_param<const USE_TABLE: bool>(&mut self) -> Result<u64, Self::Error> {
108 const {
109 if USE_TABLE {
110 gamma_tables::check_read_table(B::PEEK_BITS)
111 }
112 }
113 if USE_TABLE {
114 if let Some((res, _)) = gamma_tables::read_table_le(self) {
115 return Ok(res);
116 }
117 }
118 default_read_gamma(self)
119 }
120}
121
122pub trait GammaWrite<E: Endianness>: BitWrite<E> {
126 fn write_gamma(&mut self, n: u64) -> Result<usize, Self::Error>;
127}
128
129pub trait GammaWriteParam<E: Endianness>: BitWrite<E> {
138 fn write_gamma_param<const USE_TABLE: bool>(&mut self, n: u64) -> Result<usize, Self::Error>;
139}
140
141impl<B: BitWrite<BE>> GammaWriteParam<BE> for B {
142 #[inline(always)]
143 #[allow(clippy::collapsible_if)]
144 fn write_gamma_param<const USE_TABLE: bool>(&mut self, n: u64) -> Result<usize, Self::Error> {
145 if USE_TABLE {
146 if let Some(len) = gamma_tables::write_table_be(self, n)? {
147 return Ok(len);
148 }
149 }
150 default_write_gamma(self, n)
151 }
152}
153
154impl<B: BitWrite<LE>> GammaWriteParam<LE> for B {
155 #[inline(always)]
156 #[allow(clippy::collapsible_if)]
157 fn write_gamma_param<const USE_TABLE: bool>(&mut self, n: u64) -> Result<usize, Self::Error> {
158 if USE_TABLE {
159 if let Some(len) = gamma_tables::write_table_le(self, n)? {
160 return Ok(len);
161 }
162 }
163 default_write_gamma(self, n)
164 }
165}
166
167#[inline(always)]
170fn default_write_gamma<E: Endianness, B: BitWrite<E>>(
171 backend: &mut B,
172 mut n: u64,
173) -> Result<usize, B::Error> {
174 debug_assert!(n < u64::MAX);
175 n += 1;
176 let λ = n.ilog2();
177
178 #[cfg(feature = "checks")]
179 {
180 n ^= 1 << λ;
182 }
183
184 Ok(backend.write_unary(λ as _)? + backend.write_bits(n, λ as _)?)
185}