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