use crate::bucket_array::{
hash::Insert, hash::KeyValueBucketArray, mem::BucketArrayMemory, mem::Uninit,
};
use crate::collision::{self, PackedCollision};
use crate::solution::{self, EQUIHASH_N, HashValue, Solution, SolutionArray, SolutionItem};
use arrayvec::ArrayVec;
use hashx::HashX;
type Layer0<'k, 'v> =
KeyValueBucketArray<'k, 'v, 256, 336, u16, HashValue, HashValue, SolutionItem>;
type Layer0KeyMem = BucketArrayMemory<256, 336, HashValue>;
type Layer0ValueMem = BucketArrayMemory<256, 336, SolutionItem>;
type Layer0Collision = PackedCollision<u32, 8, 9>;
type Layer1<'k, 'v> = KeyValueBucketArray<'k, 'v, 256, 336, u16, u64, u64, u32>;
type Layer1KeyMem = BucketArrayMemory<256, 336, u64>;
type Layer1ValueMem = BucketArrayMemory<256, 336, u32>;
type Layer1Collision = PackedCollision<u32, 8, 9>;
type Layer2<'k, 'v> = KeyValueBucketArray<'k, 'v, 256, 336, u16, u32, u32, u32>;
type Layer2KeyMem = BucketArrayMemory<256, 336, u32>;
type Layer2ValueMem = BucketArrayMemory<256, 336, u32>;
type TempMem = BucketArrayMemory<128, 12, u16>;
#[derive(Copy, Clone)]
struct SolverMemoryInner {
temp: TempMem,
overlay: Overlay,
layer0_values: Layer0ValueMem,
layer1_values: Layer1ValueMem,
layer1_keys: Layer1KeyMem,
}
unsafe impl Uninit for SolverMemoryInner {}
#[derive(Copy, Clone)]
union Overlay {
first: OverlayFirst,
second: OverlaySecond,
}
impl Overlay {
fn first(&mut self) -> &mut OverlayFirst {
unsafe { &mut self.first }
}
fn second(&mut self) -> &mut OverlaySecond {
unsafe { &mut self.second }
}
}
#[derive(Copy, Clone)]
struct OverlayFirst {
layer0_keys: Layer0KeyMem,
}
#[derive(Copy, Clone)]
struct OverlaySecond {
layer2_keys: Layer2KeyMem,
layer2_values: Layer2ValueMem,
}
pub(crate) fn find_solutions(func: &HashX, mem: &mut SolverMemory, results: &mut SolutionArray) {
let overlay = mem.heap.overlay.first();
let mut layer0 = Layer0::new(&mut overlay.layer0_keys, &mut mem.heap.layer0_values);
for item in SolutionItem::MIN..=SolutionItem::MAX {
let hash = solution::item_hash(func, item);
let _ = layer0.insert(hash, item);
}
let layer1_n = EQUIHASH_N / 4;
let mut layer1 = Layer1::new(&mut mem.heap.layer1_keys, &mut mem.heap.layer1_values);
collision::search(&layer0, &mut mem.heap.temp, layer1_n, |sum, loc| {
let _ = layer1.insert(sum, Layer0Collision::pack(&loc).into_inner());
});
let layer0 = layer0.drop_key_storage();
let overlay = mem.heap.overlay.second();
let layer2_n = EQUIHASH_N / 2;
let mut layer2 = Layer2::new(&mut overlay.layer2_keys, &mut overlay.layer2_values);
collision::search(
&layer1,
&mut mem.heap.temp,
layer2_n - layer1_n,
|sum, loc| {
let _ = layer2.insert(sum as u32, Layer1Collision::pack(&loc).into_inner());
},
);
let layer3_n = EQUIHASH_N;
collision::search(
&layer2,
&mut mem.heap.temp,
layer3_n - layer2_n,
|_sum, loc| {
let mut items = ArrayVec::<SolutionItem, { Solution::NUM_ITEMS }>::new();
loc.pair(&layer2).into_iter().for_each(|loc| {
Layer1Collision::new(loc)
.unpack()
.pair(&layer1)
.into_iter()
.for_each(|loc| {
Layer0Collision::new(loc)
.unpack()
.pair(&layer0)
.into_iter()
.for_each(|item| items.push(item));
});
});
let solution = Solution::sort_from_array(
items
.into_inner()
.expect("always collected a full SolutionItem tree"),
);
if results.last() != Some(&solution) {
let _ = results.try_push(solution);
}
},
);
}
pub struct SolverMemory {
heap: Box<SolverMemoryInner>,
}
impl SolverMemory {
pub const SIZE: usize = std::mem::size_of::<SolverMemoryInner>();
pub fn new() -> Self {
Self {
heap: SolverMemoryInner::alloc(),
}
}
}
impl Default for SolverMemory {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod test {
#[test]
fn solver_memory_size() {
let size = super::SolverMemory::SIZE;
assert_eq!(size, 1_895_424);
}
}