tract_linalg/frame/block_quant/
helpers.rs1use byteorder::{ReadBytesExt, WriteBytesExt, LE};
2use std::io::{Cursor, Read, Write};
3use tract_data::internal::*;
4
5pub struct NibbleReader<R> {
6 second_half: Option<i8>,
7 reader: R,
8}
9
10impl<'s> NibbleReader<Cursor<&'s [u8]>> {
11 pub fn for_slice(slice: &'s [u8]) -> Self {
12 NibbleReader::new(Cursor::new(slice))
13 }
14}
15
16impl<R: Read> NibbleReader<R> {
17 pub fn new(reader: R) -> NibbleReader<R> {
18 NibbleReader { reader, second_half: None }
19 }
20
21 pub fn read_f16(&mut self) -> f16 {
22 assert!(self.second_half.is_none());
23 f16::from_bits(self.reader.read_u16::<LE>().unwrap())
24 }
25
26 pub fn read_i4(&mut self) -> i8 {
27 if let Some(second) = self.second_half.take() {
28 second
29 } else {
30 let byte = self.reader.read_u8().unwrap();
31 self.second_half = Some((byte >> 4) as i8);
32 (byte & 0x0F) as i8
33 }
34 }
35}
36
37pub struct NibbleWriter<W> {
38 first_half: Option<i8>,
39 writer: W,
40}
41
42impl<'s> NibbleWriter<Cursor<&'s mut [u8]>> {
43 pub fn for_slice(slice: &'s mut [u8]) -> Self {
44 NibbleWriter::new(Cursor::new(slice))
45 }
46}
47
48impl<W: Write> NibbleWriter<W> {
49 pub fn new(writer: W) -> NibbleWriter<W> {
50 NibbleWriter { writer, first_half: None }
51 }
52
53 pub fn write_f16(&mut self, f: f16) {
54 assert!(self.first_half.is_none());
55 self.writer.write_u16::<LE>(f.to_bits()).unwrap()
56 }
57
58 pub fn write_i4(&mut self, q: i8) {
59 if let Some(first) = self.first_half.take() {
60 self.writer.write_u8(first as u8 | ((q as u8) << 4)).unwrap()
61 } else {
62 self.first_half = Some(q);
63 }
64 }
65}