ph_temp/fmph/
goindexing.rs1use std::convert::{TryFrom, TryInto};
4use std::ops::Mul;
5use binout::{AsIs, Serializer};
6use bitm::{BitAccess, ceiling_div};
7use crate::seeds::{to_io_error, Bits, TwoToPowerBitsStatic};
8use crate::utils::{map32_to_32, map64_to_64};
9
10#[inline(always)]
13pub fn group_nr(hash: u64, level_size_groups: usize) -> usize {
14 map64_to_64(hash, level_size_groups as u64) as usize }
19
20#[inline(always)]
28fn mix32(mut x: u32) -> u32 {
29 x = (x ^ (x >> 16)).wrapping_mul(0x21f0aaad);
30 x = (x ^ (x >> 15)).wrapping_mul(0xd35a2d97);
31 x ^ (x >> 15)
32}
33
34pub trait GroupSize: Sized + Mul<usize, Output=usize> + Copy + Into<u8> + TryFrom<u8, Error=&'static str> {
51
52 fn validate(&self) -> Result<Self, &'static str> { Ok(*self) }
53
54 #[inline(always)]
56 fn hash_to_group(&self, hash: u32) -> u8 {
57 map32_to_32(hash as u32, Into::<u8>::into(*self) as u32) as u8
58 }
60
61 #[inline(always)]
64 fn in_group_index(&self, hash: u64, group_seed: u16) -> u8 {
65 self.hash_to_group(mix32((hash as u32) ^ (group_seed as u32)))
67
68 }
72
73 #[inline]
76 fn bit_index_for_seed(&self, hash: u64, group_seed: u16, group: usize) -> usize {
77 (*self * group as usize) + self.in_group_index(hash, group_seed) as usize
78 }
79
80 fn level_size_groups_segments(&self, mut desired_total_size: usize) -> (usize, usize) {
82 let remainder = desired_total_size % 64;
83 if remainder != 0 { desired_total_size += 64 - remainder; } let group_size = Into::<u8>::into(*self) as usize;
85 while desired_total_size % group_size != 0 { desired_total_size += 64; } return (desired_total_size / group_size, desired_total_size / 64);
87 }
88
89 #[inline(always)] fn copy_group_if_better<CB>(&self, dst: &mut [u64], src: &[u64], group_index: usize, callback: CB)
103 where CB: FnOnce()
104 {
105 dst.conditionally_copy_fragment(src, |best, new|
106 if best.count_ones() < new.count_ones() {
107 callback();
108 true
109 } else { false }, group_index, (*self).into())
110 }
111
112 #[inline] fn write_size_bytes(&self) -> usize {
114 std::mem::size_of::<u8>()
115 }
116
117 fn write(&self, output: &mut dyn std::io::Write) -> std::io::Result<()> {
119 AsIs::write(output, (*self).into())
120 }
121
122 fn read(input: &mut dyn std::io::Read) -> std::io::Result<Self> {
124 let group_size: u8 = AsIs::read(input)?;
125 let result = TryInto::<Self>::try_into(group_size).map_err(to_io_error)?;
126 result.validate().map_err(to_io_error)
127 }
128}
129
130#[derive(Copy, Clone)]
132pub struct TwoToPowerBits {
133 log2size: u8,
134 mask: u8
135}
136
137impl TwoToPowerBits {
138 pub fn new(log2size: u8) -> Self {
140 assert!(log2size <= 7);
141 Self { log2size, mask: (1u8<<log2size)-1 }
142 }
143
144 }
149
150impl Mul<usize> for TwoToPowerBits {
151 type Output = usize;
152
153 #[inline(always)] fn mul(self, rhs: usize) -> Self::Output {
154 rhs << self.log2size
155 }
156}
157
158impl Into<u8> for TwoToPowerBits {
159 #[inline(always)] fn into(self) -> u8 {
160 1<<self.log2size
161 }
162}
163
164impl TryFrom<u8> for TwoToPowerBits {
165 type Error = &'static str;
166
167 fn try_from(value: u8) -> Result<Self, Self::Error> {
168 if value.is_power_of_two() && value <= 128 {
169 Ok(Self::new(value.trailing_zeros() as u8))
170 } else {
171 Err("group size must be the power of two, not greater than 128")
172 }
173 }
174}
175
176impl GroupSize for TwoToPowerBits {
177 #[inline(always)] fn hash_to_group(&self, hash: u32) -> u8 {
178 hash as u8 & self.mask
179 }
180
181 fn level_size_groups_segments(&self, desired_total_size: usize) -> (usize, usize) {
182 let level_size_segments;
183 let level_size_groups;
184 if self.log2size > 6 {
185 level_size_groups = ceiling_div(desired_total_size, 1usize<<self.log2size);
188 level_size_segments = (level_size_groups as usize) << (self.log2size - 6);
189 } else {
190 level_size_segments = ceiling_div(desired_total_size, 64);
191 level_size_groups = level_size_segments << (6 - self.log2size);
192 }
193 (level_size_groups, level_size_segments)
194 }
195
196 }
207
208impl GroupSize for Bits {
209 fn validate(&self) -> Result<Self, &'static str> {
210 if self.0 <= 63 { Ok(*self) } else { Err("group sizes grater than 63 are not supported by Bits") }
211 }
212}
213
214impl<const LOG2_BITS: u8> GroupSize for TwoToPowerBitsStatic<LOG2_BITS> {
215 #[inline(always)] fn hash_to_group(&self, hash: u32) -> u8 {
216 hash as u8 & Self::LOG2_MASK
217 }
218
219 fn level_size_groups_segments(&self, desired_total_size: usize) -> (usize, usize) {
220 let level_size_segments;
221 let level_size_groups;
222 if LOG2_BITS > 6 {
223 level_size_groups = ceiling_div(desired_total_size, 1usize<<LOG2_BITS);
226 level_size_segments = (level_size_groups as usize) << (LOG2_BITS - 6);
227 } else {
228 level_size_segments = ceiling_div(desired_total_size, 64);
229 level_size_groups = level_size_segments << (6 - LOG2_BITS);
230 }
231 (level_size_groups, level_size_segments)
232 }
233
234 #[inline(always)] fn copy_group_if_better<CB>(&self, dst: &mut [u64], src: &[u64], group_index: usize, callback: CB)
235 where CB: FnOnce()
236 {
237 let vec_index = group_index / Self::VALUES_PER_64 as usize;
238 let shift = Self::shift_for(group_index);
239 let dst_v = &mut dst[vec_index];
240 let best = (*dst_v >> shift) & Self::MASK64;
241 let new = (src[vec_index] >> shift) & Self::MASK64;
242 if best.count_ones() < new.count_ones() {
243 callback();
244 *dst_v &= !(Self::MASK64 << shift);
245 *dst_v |= new << shift;
246 }
247 }
248}