1#[cfg(feature = "mem_dbg")]
10use mem_dbg::{MemDbg, MemSize};
11
12use crate::prelude::{
13 Codes, bit_len_vbyte, len_delta, len_exp_golomb, len_gamma, len_golomb, len_omega, len_pi,
14 len_rice, len_zeta,
15};
16use core::fmt::Debug;
17
18#[cfg(feature = "std")]
19use crate::dispatch::{CodesRead, CodesWrite};
20#[cfg(feature = "std")]
21use crate::prelude::Endianness;
22#[cfg(feature = "std")]
23use crate::prelude::{DynamicCodeRead, DynamicCodeWrite, StaticCodeRead, StaticCodeWrite};
24#[cfg(feature = "std")]
25use std::sync::Mutex;
26
27#[cfg(feature = "serde")]
28use alloc::string::ToString;
29#[cfg(feature = "alloc")]
30use alloc::{vec, vec::Vec};
31
32#[derive(Debug, Copy, Clone, PartialEq, Eq)]
44#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
45pub struct CodesStats<
46 const ZETA: usize = 10,
48 const GOLOMB: usize = 10,
50 const EXP_GOLOMB: usize = 10,
52 const RICE: usize = 10,
54 const PI: usize = 10,
56> {
57 pub total: u64,
59 pub unary: u64,
62 pub gamma: u64,
65 pub delta: u64,
68 pub omega: u64,
71 pub vbyte: u64,
74 pub zeta: [u64; ZETA],
77 pub golomb: [u64; GOLOMB],
81 pub exp_golomb: [u64; EXP_GOLOMB],
86 pub rice: [u64; RICE],
90 pub pi: [u64; PI],
93}
94
95impl<
96 const ZETA: usize,
97 const GOLOMB: usize,
98 const EXP_GOLOMB: usize,
99 const RICE: usize,
100 const PI: usize,
101> core::default::Default for CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
102{
103 fn default() -> Self {
104 Self {
105 total: 0,
106 unary: 0,
107 gamma: 0,
108 delta: 0,
109 omega: 0,
110 vbyte: 0,
111 zeta: [0; ZETA],
112 golomb: [0; GOLOMB],
113 exp_golomb: [0; EXP_GOLOMB],
114 rice: [0; RICE],
115 pi: [0; PI],
116 }
117 }
118}
119
120impl<
121 const ZETA: usize,
122 const GOLOMB: usize,
123 const EXP_GOLOMB: usize,
124 const RICE: usize,
125 const PI: usize,
126> CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
127{
128 pub fn update(&mut self, n: u64) -> u64 {
131 self.update_many(n, 1)
132 }
133
134 #[inline]
136 pub fn update_many(&mut self, n: u64, count: u64) -> u64 {
137 self.total += count;
138 self.unary += (n + 1) * count;
139 self.gamma += len_gamma(n) as u64 * count;
140 self.delta += len_delta(n) as u64 * count;
141 self.omega += len_omega(n) as u64 * count;
142 self.vbyte += bit_len_vbyte(n) as u64 * count;
143
144 for (k, val) in self.zeta.iter_mut().enumerate() {
145 *val += (len_zeta(n, (k + 1) as _) as u64) * count;
146 }
147 for (b, val) in self.golomb.iter_mut().enumerate() {
148 *val += (len_golomb(n, (b + 1) as _) as u64) * count;
149 }
150 for (k, val) in self.exp_golomb.iter_mut().enumerate() {
151 *val += (len_exp_golomb(n, k as _) as u64) * count;
152 }
153 for (log2_b, val) in self.rice.iter_mut().enumerate() {
154 *val += (len_rice(n, log2_b as _) as u64) * count;
155 }
156 for (k, val) in self.pi.iter_mut().enumerate() {
158 *val += (len_pi(n, (k + 2) as _) as u64) * count;
159 }
160 n
161 }
162
163 pub fn add(&mut self, rhs: &Self) {
165 self.total += rhs.total;
166 self.unary += rhs.unary;
167 self.gamma += rhs.gamma;
168 self.delta += rhs.delta;
169 self.omega += rhs.omega;
170 self.vbyte += rhs.vbyte;
171 for (a, b) in self.zeta.iter_mut().zip(rhs.zeta.iter()) {
172 *a += *b;
173 }
174 for (a, b) in self.golomb.iter_mut().zip(rhs.golomb.iter()) {
175 *a += *b;
176 }
177 for (a, b) in self.exp_golomb.iter_mut().zip(rhs.exp_golomb.iter()) {
178 *a += *b;
179 }
180 for (a, b) in self.rice.iter_mut().zip(rhs.rice.iter()) {
181 *a += *b;
182 }
183 for (a, b) in self.pi.iter_mut().zip(rhs.pi.iter()) {
184 *a += *b;
185 }
186 }
187
188 #[must_use]
193 pub fn best_code(&self) -> (Codes, u64) {
194 let mut best = (Codes::Unary, self.unary);
195 if self.gamma < best.1 {
196 best = (Codes::Gamma, self.gamma);
197 }
198 if self.delta < best.1 {
199 best = (Codes::Delta, self.delta);
200 }
201 if self.omega < best.1 {
202 best = (Codes::Omega, self.omega);
203 }
204 if self.vbyte < best.1 {
205 best = (Codes::VByteBe, self.vbyte);
206 }
207 for (k, val) in self.zeta.iter().enumerate() {
208 if *val < best.1 {
209 best = (Codes::Zeta((k + 1) as _), *val);
210 }
211 }
212 for (b, val) in self.golomb.iter().enumerate() {
213 if *val < best.1 {
214 best = (Codes::Golomb((b + 1) as _), *val);
215 }
216 }
217 for (k, val) in self.exp_golomb.iter().enumerate() {
218 if *val < best.1 {
219 best = (Codes::ExpGolomb(k as _), *val);
220 }
221 }
222 for (log2_b, val) in self.rice.iter().enumerate() {
223 if *val < best.1 {
224 best = (Codes::Rice(log2_b as _), *val);
225 }
226 }
227 for (k, val) in self.pi.iter().enumerate() {
228 if *val < best.1 {
229 best = (Codes::Pi((k + 2) as _), *val);
230 }
231 }
232 best
233 }
234
235 #[cfg(feature = "alloc")]
237 #[must_use]
238 pub fn get_codes(&self) -> Vec<(Codes, u64)> {
239 let mut codes = vec![
240 (Codes::Unary, self.unary),
241 (Codes::Gamma, self.gamma),
242 (Codes::Delta, self.delta),
243 (Codes::Omega, self.omega),
244 (Codes::VByteBe, self.vbyte),
245 ];
246 for (k, val) in self.zeta.iter().enumerate() {
247 codes.push((Codes::Zeta((k + 1) as _), *val));
248 }
249 for (b, val) in self.golomb.iter().enumerate() {
250 codes.push((Codes::Golomb((b + 1) as _), *val));
251 }
252 for (k, val) in self.exp_golomb.iter().enumerate() {
253 codes.push((Codes::ExpGolomb(k as _), *val));
254 }
255 for (log2_b, val) in self.rice.iter().enumerate() {
256 codes.push((Codes::Rice(log2_b as _), *val));
257 }
258 for (k, val) in self.pi.iter().enumerate() {
259 codes.push((Codes::Pi((k + 2) as _), *val));
260 }
261 codes.sort_by_key(|&(_, len)| len);
263 codes
264 }
265
266 #[must_use]
268 pub fn bits_for(&self, code: Codes) -> Option<u64> {
269 match code {
270 Codes::Unary => Some(self.unary),
271 Codes::Gamma => Some(self.gamma),
272 Codes::Delta => Some(self.delta),
273 Codes::Omega => Some(self.omega),
274 Codes::VByteBe | Codes::VByteLe => Some(self.vbyte),
275 Codes::Zeta(k) => self.zeta.get(k.checked_sub(1)?).copied(),
276 Codes::Golomb(b) => self.golomb.get(b.checked_sub(1)? as usize).copied(),
277 Codes::ExpGolomb(k) => self.exp_golomb.get(k).copied(),
278 Codes::Rice(log2_b) => self.rice.get(log2_b).copied(),
279 Codes::Pi(k) => self.pi.get(k.checked_sub(2)?).copied(),
280 }
281 }
282}
283
284impl<
285 const ZETA: usize,
286 const GOLOMB: usize,
287 const EXP_GOLOMB: usize,
288 const RICE: usize,
289 const PI: usize,
290> core::ops::AddAssign for CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
291{
292 fn add_assign(&mut self, rhs: Self) {
294 self.add(&rhs);
295 }
296}
297
298impl<
299 const ZETA: usize,
300 const GOLOMB: usize,
301 const EXP_GOLOMB: usize,
302 const RICE: usize,
303 const PI: usize,
304> core::ops::Add for CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
305{
306 type Output = Self;
307
308 fn add(self, rhs: Self) -> Self {
310 let mut res = self;
311 res += rhs;
312 res
313 }
314}
315
316impl<
318 const ZETA: usize,
319 const GOLOMB: usize,
320 const EXP_GOLOMB: usize,
321 const RICE: usize,
322 const PI: usize,
323> core::iter::Sum for CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
324{
325 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
326 iter.fold(Self::default(), |a, b| a + b)
327 }
328}
329
330#[cfg(feature = "serde")]
331impl<
332 const ZETA: usize,
333 const GOLOMB: usize,
334 const EXP_GOLOMB: usize,
335 const RICE: usize,
336 const PI: usize,
337> serde::Serialize for CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
338{
339 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
340 use serde::ser::SerializeStruct;
341
342 let mut state = serializer.serialize_struct("CodesStats", 11)?;
343 state.serialize_field("total", &self.total)?;
344 state.serialize_field("unary", &self.unary)?;
345 state.serialize_field("gamma", &self.gamma)?;
346 state.serialize_field("delta", &self.delta)?;
347 state.serialize_field("omega", &self.omega)?;
348 state.serialize_field("vbyte", &self.vbyte)?;
349 state.serialize_field("zeta", &self.zeta.as_slice())?;
351 state.serialize_field("golomb", &self.golomb.as_slice())?;
352 state.serialize_field("exp_golomb", &self.exp_golomb.as_slice())?;
353 state.serialize_field("rice", &self.rice.as_slice())?;
354 state.serialize_field("pi", &self.pi.as_slice())?;
355 state.end()
356 }
357}
358
359#[cfg(feature = "serde")]
360impl<
361 'de,
362 const ZETA: usize,
363 const GOLOMB: usize,
364 const EXP_GOLOMB: usize,
365 const RICE: usize,
366 const PI: usize,
367> serde::Deserialize<'de> for CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
368{
369 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
370 use serde::de::{MapAccess, Visitor};
371
372 struct CodesStatsVisitor<
373 const ZETA: usize,
374 const GOLOMB: usize,
375 const EXP_GOLOMB: usize,
376 const RICE: usize,
377 const PI: usize,
378 >;
379
380 impl<
381 'de,
382 const ZETA: usize,
383 const GOLOMB: usize,
384 const EXP_GOLOMB: usize,
385 const RICE: usize,
386 const PI: usize,
387 > Visitor<'de> for CodesStatsVisitor<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
388 {
389 type Value = CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>;
390
391 fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
392 formatter.write_str("struct CodesStats")
393 }
394
395 fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> Result<Self::Value, V::Error> {
396 let mut total = None;
397 let mut unary = None;
398 let mut gamma = None;
399 let mut delta = None;
400 let mut omega = None;
401 let mut vbyte = None;
402 let mut zeta: Option<[u64; ZETA]> = None;
403 let mut golomb: Option<[u64; GOLOMB]> = None;
404 let mut exp_golomb: Option<[u64; EXP_GOLOMB]> = None;
405 let mut rice: Option<[u64; RICE]> = None;
406 let mut pi: Option<[u64; PI]> = None;
407
408 fn vec_to_array<E: serde::de::Error, const N: usize>(
410 v: Vec<u64>,
411 ) -> Result<[u64; N], E> {
412 v.try_into().map_err(|v: Vec<u64>| {
413 serde::de::Error::invalid_length(v.len(), &N.to_string().as_str())
414 })
415 }
416
417 while let Some(key) = map.next_key::<&str>()? {
418 match key {
419 "total" => total = Some(map.next_value()?),
420 "unary" => unary = Some(map.next_value()?),
421 "gamma" => gamma = Some(map.next_value()?),
422 "delta" => delta = Some(map.next_value()?),
423 "omega" => omega = Some(map.next_value()?),
424 "vbyte" => vbyte = Some(map.next_value()?),
425 "zeta" => zeta = Some(vec_to_array(map.next_value()?)?),
426 "golomb" => golomb = Some(vec_to_array(map.next_value()?)?),
427 "exp_golomb" => exp_golomb = Some(vec_to_array(map.next_value()?)?),
428 "rice" => rice = Some(vec_to_array(map.next_value()?)?),
429 "pi" => pi = Some(vec_to_array(map.next_value()?)?),
430 _ => {
431 let _ = map.next_value::<serde::de::IgnoredAny>()?;
432 }
433 }
434 }
435
436 Ok(CodesStats {
437 total: total.unwrap_or_default(),
438 unary: unary.unwrap_or_default(),
439 gamma: gamma.unwrap_or_default(),
440 delta: delta.unwrap_or_default(),
441 omega: omega.unwrap_or_default(),
442 vbyte: vbyte.unwrap_or_default(),
443 zeta: zeta.unwrap_or([0; ZETA]),
444 golomb: golomb.unwrap_or([0; GOLOMB]),
445 exp_golomb: exp_golomb.unwrap_or([0; EXP_GOLOMB]),
446 rice: rice.unwrap_or([0; RICE]),
447 pi: pi.unwrap_or([0; PI]),
448 })
449 }
450 }
451
452 deserializer.deserialize_struct(
453 "CodesStats",
454 &[
455 "total",
456 "unary",
457 "gamma",
458 "delta",
459 "omega",
460 "vbyte",
461 "zeta",
462 "golomb",
463 "exp_golomb",
464 "rice",
465 "pi",
466 ],
467 CodesStatsVisitor::<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>,
468 )
469 }
470}
471
472#[derive(Debug)]
476#[cfg_attr(feature = "mem_dbg", derive(MemDbg, MemSize))]
477#[cfg(feature = "std")]
478pub struct CodesStatsWrapper<
479 W,
480 const ZETA: usize = 10,
482 const GOLOMB: usize = 10,
484 const EXP_GOLOMB: usize = 10,
486 const RICE: usize = 10,
488 const PI: usize = 10,
490> {
491 stats: Mutex<CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>>,
495 wrapped: W,
496}
497
498#[cfg(feature = "std")]
499impl<
500 W,
501 const ZETA: usize,
502 const GOLOMB: usize,
503 const EXP_GOLOMB: usize,
504 const RICE: usize,
505 const PI: usize,
506> CodesStatsWrapper<W, ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
507{
508 #[must_use]
510 pub fn new(wrapped: W) -> Self {
511 Self {
512 stats: Mutex::new(CodesStats::default()),
513 wrapped,
514 }
515 }
516
517 pub const fn stats(&self) -> &Mutex<CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>> {
519 &self.stats
520 }
521
522 #[must_use]
524 pub fn into_inner(self) -> (W, CodesStats<ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>) {
525 (
526 self.wrapped,
527 self.stats.into_inner().expect("mutex is not poisoned"),
528 )
529 }
530}
531
532#[cfg(feature = "std")]
533impl<
534 W: DynamicCodeRead,
535 const ZETA: usize,
536 const GOLOMB: usize,
537 const EXP_GOLOMB: usize,
538 const RICE: usize,
539 const PI: usize,
540> DynamicCodeRead for CodesStatsWrapper<W, ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
541{
542 #[inline]
543 fn read<E: Endianness, CR: CodesRead<E> + ?Sized>(
544 &self,
545 reader: &mut CR,
546 ) -> Result<u64, CR::Error> {
547 let res = self.wrapped.read(reader)?;
548 self.stats.lock().unwrap().update(res);
549 Ok(res)
550 }
551}
552
553#[cfg(feature = "std")]
554impl<
555 W: StaticCodeRead<E, CR>,
556 const ZETA: usize,
557 const GOLOMB: usize,
558 const EXP_GOLOMB: usize,
559 const RICE: usize,
560 const PI: usize,
561 E: Endianness,
562 CR: CodesRead<E> + ?Sized,
563> StaticCodeRead<E, CR> for CodesStatsWrapper<W, ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
564{
565 #[inline]
566 fn read(&self, reader: &mut CR) -> Result<u64, CR::Error> {
567 let res = self.wrapped.read(reader)?;
568 self.stats.lock().unwrap().update(res);
569 Ok(res)
570 }
571}
572
573#[cfg(feature = "std")]
574impl<
575 W: DynamicCodeWrite,
576 const ZETA: usize,
577 const GOLOMB: usize,
578 const EXP_GOLOMB: usize,
579 const RICE: usize,
580 const PI: usize,
581> DynamicCodeWrite for CodesStatsWrapper<W, ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
582{
583 #[inline]
584 fn write<E: Endianness, CW: CodesWrite<E> + ?Sized>(
585 &self,
586 writer: &mut CW,
587 n: u64,
588 ) -> Result<usize, CW::Error> {
589 let res = self.wrapped.write(writer, n)?;
590 self.stats.lock().unwrap().update(n);
591 Ok(res)
592 }
593}
594
595#[cfg(feature = "std")]
596impl<
597 W: StaticCodeWrite<E, CW>,
598 const ZETA: usize,
599 const GOLOMB: usize,
600 const EXP_GOLOMB: usize,
601 const RICE: usize,
602 const PI: usize,
603 E: Endianness,
604 CW: CodesWrite<E> + ?Sized,
605> StaticCodeWrite<E, CW> for CodesStatsWrapper<W, ZETA, GOLOMB, EXP_GOLOMB, RICE, PI>
606{
607 #[inline]
608 fn write(&self, writer: &mut CW, n: u64) -> Result<usize, CW::Error> {
609 let res = self.wrapped.write(writer, n)?;
610 self.stats.lock().unwrap().update(n);
611 Ok(res)
612 }
613}
614
615#[cfg(test)]
616#[cfg(feature = "serde")]
617mod serde_tests {
618 use super::*;
619
620 #[test]
621 fn test_serde_code_stats() -> serde_json::Result<()> {
622 let mut stats: CodesStats = CodesStats::default();
623 for i in 0..100 {
624 stats.update(i);
625 }
626 let json = serde_json::to_string(&stats)?;
627 let deserialized: CodesStats = serde_json::from_str(&json)?;
628 assert_eq!(stats, deserialized);
629 Ok(())
630 }
631
632 #[test]
633 fn test_roundtrip_different_sizes() -> serde_json::Result<()> {
634 let mut stats: CodesStats<10, 20, 5, 8, 6> = CodesStats::default();
635 for i in 0..1000 {
636 stats.update(i);
637 }
638 let json = serde_json::to_string_pretty(&stats)?;
639 let deserialized: CodesStats<10, 20, 5, 8, 6> = serde_json::from_str(&json)?;
640 assert_eq!(stats, deserialized);
641 Ok(())
642 }
643
644 #[test]
645 #[should_panic]
646 fn test_mismatched_sizes() {
647 let mut stats: CodesStats<10, 20, 5, 8, 6> = CodesStats::default();
648 for i in 0..1000 {
649 stats.update(i);
650 }
651 let json = serde_json::to_string_pretty(&stats).unwrap();
652 let _deserialized: CodesStats<10, 21, 5, 8, 6> = serde_json::from_str(&json).unwrap();
654 }
655}