Improve hashing algorithm slightly (see credits)

This commit is contained in:
Ivan Smirnov 2022-01-04 01:46:13 +03:00
parent 52cc56381e
commit c062c6b79b
2 changed files with 16 additions and 6 deletions

View file

@ -4,6 +4,8 @@ use core::convert::TryFrom;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::io::Write; use std::io::Write;
use bytemuck::Pod;
use crate::consts::{QOI_HEADER_SIZE, QOI_OP_INDEX, QOI_OP_RUN, QOI_PADDING, QOI_PADDING_SIZE}; use crate::consts::{QOI_HEADER_SIZE, QOI_OP_INDEX, QOI_OP_RUN, QOI_PADDING, QOI_PADDING_SIZE};
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::header::Header; use crate::header::Header;
@ -17,6 +19,7 @@ use crate::utils::{unlikely, BytesMut, Writer};
fn encode_impl<W: Writer, const N: usize>(mut buf: W, data: &[u8]) -> Result<usize> fn encode_impl<W: Writer, const N: usize>(mut buf: W, data: &[u8]) -> Result<usize>
where where
Pixel<N>: SupportedChannels, Pixel<N>: SupportedChannels,
[u8; N]: Pod,
{ {
let cap = buf.capacity(); let cap = buf.capacity();

View file

@ -1,6 +1,7 @@
use crate::consts::{QOI_OP_DIFF, QOI_OP_LUMA, QOI_OP_RGB, QOI_OP_RGBA}; use crate::consts::{QOI_OP_DIFF, QOI_OP_LUMA, QOI_OP_RGB, QOI_OP_RGBA};
use crate::error::Result; use crate::error::Result;
use crate::utils::Writer; use crate::utils::Writer;
use bytemuck::{cast, Pod};
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[repr(transparent)] #[repr(transparent)]
@ -107,12 +108,18 @@ impl<const N: usize> Pixel<N> {
} }
#[inline] #[inline]
pub const fn hash_index(self) -> u8 { pub fn hash_index(self) -> u8
let r = self.r().wrapping_mul(3); where
let g = self.g().wrapping_mul(5); [u8; N]: Pod,
let b = self.b().wrapping_mul(7); {
let a = self.a_or(0xff).wrapping_mul(11); // credits for the initial idea: @zakarumych
r.wrapping_add(g).wrapping_add(b).wrapping_add(a) % 64 let v = if N == 4 {
u32::from_ne_bytes(cast(self.0))
} else {
u32::from_ne_bytes([self.0[0], self.0[1], self.0[2], 0xff])
} as u64;
let s = ((v & 0xff00_ff00) << 32) | (v & 0x00ff_00ff);
s.wrapping_mul(0x0300_0700_0005_000b_u64).to_le().swap_bytes() as u8 & 63
} }
#[inline] #[inline]