Shrink numeric types

This commit is contained in:
Pyrex 2024-04-07 20:30:35 -07:00
parent f76be1b112
commit 4edf6831d0
5 changed files with 48 additions and 45 deletions

View File

@ -5,14 +5,14 @@ use crate::{constants::{MAGIC, TILE_SZ, TILE_SZ2}, protocol::{self, ProtocolWrit
struct PixelTile { struct PixelTile {
// i32: representation that supports Walsh-Hadamard // i32: representation that supports Walsh-Hadamard
pixels: [i32; TILE_SZ2] pixels: [i16; TILE_SZ2]
} }
struct CoefTile { struct CoefTile {
coefs: [i32; TILE_SZ2] coefs: [i16; TILE_SZ2]
} }
struct QuantTile { struct QuantTile {
quants: [i32; TILE_SZ2] quants: [i16; TILE_SZ2]
} }
@ -75,7 +75,7 @@ impl PixelTile {
let src_y = y0 + y; let src_y = y0 + y;
pixels[y * TILE_SZ + x] = pixels[y * TILE_SZ + x] =
if src_x < width && src_y < height { if src_x < width && src_y < height {
layer[src_y * width + src_x] as i32 layer[src_y * width + src_x] as i16
} else { } else {
0 0
}; };
@ -112,13 +112,13 @@ impl QuantTile {
} }
fn write_zero<W: Write>(&self, writer: &mut ProtocolWriter<W>) -> ProtocolWriterResult<()> { fn write_zero<W: Write>(&self, writer: &mut ProtocolWriter<W>) -> ProtocolWriterResult<()> {
writer.write_i32_packed(self.quants[0])?; writer.write_i16_wide(self.quants[0])?;
Ok(()) Ok(())
} }
fn write_rest<W: Write>(&self, writer: &mut ProtocolWriter<W>) -> ProtocolWriterResult<()> { fn write_rest<W: Write>(&self, writer: &mut ProtocolWriter<W>) -> ProtocolWriterResult<()> {
for i in 1..self.quants.len() { for i in 1..self.quants.len() {
writer.write_i32_packed(self.quants[i])?; writer.write_i16_packed(self.quants[i])?;
} }
Ok(()) Ok(())
} }

View File

@ -4,17 +4,17 @@ use crate::{constants::{MAGIC, TILE_SZ, TILE_SZ2}, protocol::{ProtocolReader, Pr
struct PixelTile { struct PixelTile {
// i32: representation that supports Walsh-Hadamard // i32: representation that supports Walsh-Hadamard
pixels: [i32; TILE_SZ2] pixels: [i16; TILE_SZ2]
} }
#[derive(Clone)] #[derive(Clone)]
struct CoefTile { struct CoefTile {
coefs: [i32; TILE_SZ2] coefs: [i16; TILE_SZ2]
} }
#[derive(Clone)] #[derive(Clone)]
struct QuantTile { struct QuantTile {
quants: [i32; TILE_SZ2] quants: [i16; TILE_SZ2]
} }
pub fn decompress<R: Read>( pub fn decompress<R: Read>(
@ -93,11 +93,11 @@ impl PixelTile {
} }
} }
fn clip(&self, x: i32) -> u8 { fn clip(&self, x: i16) -> u8 {
if x > u8::MAX as i32 { if x > u8::MAX as i16 {
return u8::MAX return u8::MAX
} }
if x < u8::MIN as i32 { if x < u8::MIN as i16 {
return u8::MIN; return u8::MIN;
} }
return x as u8; return x as u8;
@ -116,13 +116,13 @@ impl QuantTile {
} }
fn load_zero<R: Read>(&mut self, reader: &mut ProtocolReader<R>) -> ProtocolReaderResult<()> { fn load_zero<R: Read>(&mut self, reader: &mut ProtocolReader<R>) -> ProtocolReaderResult<()> {
self.quants[0] = reader.read_i32_packed()?; self.quants[0] = reader.read_i16_wide()?;
Ok(()) Ok(())
} }
fn load_rest<R: Read>(&mut self, reader: &mut ProtocolReader<R>) -> ProtocolReaderResult<()> { fn load_rest<R: Read>(&mut self, reader: &mut ProtocolReader<R>) -> ProtocolReaderResult<()> {
for i in 1..self.quants.len() { for i in 1..self.quants.len() {
self.quants[i] = reader.read_i32_packed()?; self.quants[i] = reader.read_i16_packed()?;
} }
Ok(()) Ok(())
} }

View File

@ -61,21 +61,19 @@ impl<W: Write> ProtocolWriter<W> {
self.writer.write_all(&value.to_le_bytes())?; self.writer.write_all(&value.to_le_bytes())?;
Ok(()) Ok(())
} }
pub fn write_i32_packed(&mut self, value: i32) -> ProtocolWriterResult<()> { pub fn write_i16_wide(&mut self, value: i16) -> ProtocolWriterResult<()> {
self.writer.write_all(&value.to_le_bytes())?;
Ok(())
}
pub fn write_i16_packed(&mut self, value: i16) -> ProtocolWriterResult<()> {
// We reserve i8::MAX and i16::MAX as signal values that `value` is too big // We reserve i8::MAX and i16::MAX as signal values that `value` is too big
// for each respective type // for each respective type
if (i8::MIN as i32..i8::MAX as i32).contains(&value) { if (i8::MIN as i16..i8::MAX as i16).contains(&value) {
self.writer.write_all(&(value as i8).to_le_bytes())?; self.writer.write_all(&(value as i8).to_le_bytes())?;
return Ok(()) return Ok(())
} }
self.writer.write_all(&(i8::MAX).to_le_bytes())?; self.writer.write_all(&(i8::MAX).to_le_bytes())?;
self.writer.write_all(&(value as i16).to_le_bytes())?;
if (i16::MIN as i32..i16::MAX as i32).contains(&value) {
self.writer.write_all(&(value as i16).to_le_bytes())?;
return Ok(())
}
self.writer.write_all(&(i16::MAX).to_le_bytes())?;
self.writer.write_all(&value.to_le_bytes())?;
Ok(()) Ok(())
} }
} }
@ -105,21 +103,23 @@ impl<R: Read> ProtocolReader<R> {
Ok(u32::from_le_bytes(u32_buf)) Ok(u32::from_le_bytes(u32_buf))
} }
pub fn read_i32_packed(&mut self) -> ProtocolReaderResult<i32> { pub fn read_i16_wide(&mut self) -> ProtocolReaderResult<i16> {
let mut i16_buf = [0; 2];
self.read_exact(&mut i16_buf)?;
Ok(i16::from_le_bytes(i16_buf))
}
pub fn read_i16_packed(&mut self) -> ProtocolReaderResult<i16> {
let mut i8_buf = [0; 1]; let mut i8_buf = [0; 1];
self.read_exact(&mut i8_buf)?; self.read_exact(&mut i8_buf)?;
let i8_value = i8::from_le_bytes(i8_buf); let i8_value = i8::from_le_bytes(i8_buf);
if i8_value != i8::MAX { return Ok(i8_value as i32) } if i8_value != i8::MAX { return Ok(i8_value as i16) }
let mut i16_buf = [0; 2]; let mut i16_buf = [0; 2];
self.read_exact(&mut i16_buf)?; self.read_exact(&mut i16_buf)?;
let i16_value = i16::from_le_bytes(i16_buf); let i16_value = i16::from_le_bytes(i16_buf);
if i16_value != i16::MAX { return Ok(i16_value as i32) } Ok(i16_value as i16)
let mut i32_buf = [0; 4];
self.read_exact(&mut i32_buf)?;
let i32_value = i32::from_le_bytes(i32_buf);
Ok(i32_value)
} }
// wrap UnexpectedEof, since that's an error for other Io clients, // wrap UnexpectedEof, since that's an error for other Io clients,

View File

@ -12,9 +12,9 @@ const ZIGZAG: [u8; TILE_SZ2] = [
]; ];
pub fn to_quantized( pub fn to_quantized(
coefs: [i32; TILE_SZ2] coefs: [i16; TILE_SZ2]
) -> [i32; TILE_SZ2] { ) -> [i16; TILE_SZ2] {
let mut quant: [i32; TILE_SZ2] = [0; TILE_SZ2]; let mut quant: [i16; TILE_SZ2] = [0; TILE_SZ2];
for cf_ix in 0..TILE_SZ2 { for cf_ix in 0..TILE_SZ2 {
let div = divisor(cf_ix); let div = divisor(cf_ix);
@ -35,21 +35,21 @@ pub fn to_quantized(
} }
pub fn from_quantized( pub fn from_quantized(
quant: [i32; TILE_SZ2] quant: [i16; TILE_SZ2]
) -> [i32; TILE_SZ2] { ) -> [i16; TILE_SZ2] {
let mut coefs: [i32; TILE_SZ2] = [0; TILE_SZ2]; let mut coefs: [i16; TILE_SZ2] = [0; TILE_SZ2];
for cf_ix in 0..TILE_SZ2 { for cf_ix in 0..TILE_SZ2 {
let div = divisor(cf_ix); let div = divisor(cf_ix);
coefs[cf_ix] = quant[ZIGZAG[cf_ix] as usize] * div; coefs[cf_ix] = quant[ZIGZAG[cf_ix] as usize].wrapping_mul(div);
} }
coefs coefs
} }
pub fn divisor(cf_ix: usize) -> i32 { pub fn divisor(cf_ix: usize) -> i16 {
if cf_ix == 0 { return 1; } if cf_ix == 0 { return 1; }
let x = cf_ix % 8; let x = cf_ix % 8;
let y = cf_ix / 8; let y = cf_ix / 8;
let div = 32 + (x as i32 + y as i32) * 12; let div = 32 + (x as i16 + y as i16) * 12;
if div==32 && cf_ix != 0 { if div==32 && cf_ix != 0 {
dbg!(cf_ix, x, y, div); dbg!(cf_ix, x, y, div);
} }

View File

@ -3,15 +3,15 @@ use crate::constants::TILE_SZ;
// This is the Walsh-Hadamard transform, specialized to 8px // This is the Walsh-Hadamard transform, specialized to 8px
// Ported from: // Ported from:
// - https://colab.research.google.com/drive/1WjtKwUcqxWafAumFO9ET74RsckZSsw6n#scrollTo=e3r9-RBpcgwH // - https://colab.research.google.com/drive/1WjtKwUcqxWafAumFO9ET74RsckZSsw6n#scrollTo=e3r9-RBpcgwH
pub fn encode(data: &mut [i32], zero: usize, stride: usize) { pub fn encode(data: &mut [i16], zero: usize, stride: usize) {
transform(data, zero, stride, 0, 0, 1) transform(data, zero, stride, 0, 0, 1)
} }
pub fn decode(data: &mut [i32], zero: usize, stride: usize) { pub fn decode(data: &mut [i16], zero: usize, stride: usize) {
transform(data, zero, stride, 0, 0, 8) transform(data, zero, stride, 0, 0, 8)
} }
fn transform(data: &mut [i32], zero: usize, stride: usize, offset_in: i32, offset_out: i32, divisor: i32) { fn transform(data: &mut [i16], zero: usize, stride: usize, offset_in: i16, offset_out: i16, divisor: i16) {
let ix = |t| zero + t * stride; let ix = |t| zero + t * stride;
let mut row = [0; TILE_SZ]; let mut row = [0; TILE_SZ];
@ -47,13 +47,16 @@ mod tests {
use crate::{constants::TILE_SZ, transform::{decode, encode}}; use crate::{constants::TILE_SZ, transform::{decode, encode}};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct Encodable { args: [i32; TILE_SZ] } struct Encodable { args: [i16; TILE_SZ] }
impl Arbitrary for Encodable { impl Arbitrary for Encodable {
fn arbitrary(g: &mut quickcheck::Gen) -> Self { fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let mut args = [0; TILE_SZ]; let mut args = [0; TILE_SZ];
for i in 0..TILE_SZ { for i in 0..TILE_SZ {
args[i] = i16::arbitrary(g) as i32; args[i] = (
i8::arbitrary(g).signum() as i32 *
(i32::arbitrary(g) % 255 * 16)
) as i16;
} }
return Encodable { args }; return Encodable { args };
} }