diff --git a/examples/cpp_port/packed/packed_kpuzzle.rs b/examples/cpp_port/packed/packed_kpuzzle.rs index dacc47fd..07dd5268 100644 --- a/examples/cpp_port/packed/packed_kpuzzle.rs +++ b/examples/cpp_port/packed/packed_kpuzzle.rs @@ -1,3 +1,5 @@ +use std::{alloc::Layout, sync::Arc}; + use cubing::{ alg::Move, kpuzzle::{InvalidAlgError, InvalidDefinitionError, KPuzzle, KPuzzleOrbitName}, @@ -6,9 +8,10 @@ use cubing::{ use super::{PackedKState, PackedKTransformation}; #[derive(Debug, Clone)] -pub struct PackedKPuzzleOrbitData { +pub struct PackedKPuzzleOrbitInfo { pub name: KPuzzleOrbitName, - pub bytes_offset: usize, + pub pieces_or_pemutations_offset: usize, + pub orientations_offset: usize, pub num_pieces: usize, pub num_orientations: u8, pub unknown_orientation_value: u8, @@ -20,15 +23,16 @@ pub struct PackedKPuzzleData { pub kpuzzle: KPuzzle, // Private cached values. pub num_bytes: usize, - pub orbit_iteration_info: Vec, + pub orbit_iteration_info: Vec, + pub layout: Layout, } const X: u8 = 255; #[derive(Debug, Clone)] pub struct PackedKPuzzle { - // pub data: Arc, // TODO - pub data: PackedKPuzzleData, + pub data: Arc, // TODO + // pub data: PackedKPuzzleData, } impl TryFrom for PackedKPuzzle { @@ -40,7 +44,7 @@ impl TryFrom for PackedKPuzzle { let orbit_ordering = orbit_ordering.as_ref().ok_or_else(|| InvalidDefinitionError{ description: "Constructing a `PackedKPuzzle` from a `KPuzzle` requires the `orbitOrdering` field.".to_owned()})?; let mut bytes_offset = 0; - let mut orbit_iteration_info: Vec = vec![]; + let mut orbit_iteration_info: Vec = vec![]; for orbit_name in orbit_ordering { let orbit_definition = kpuzzle.definition().orbits.get(orbit_name); @@ -66,11 +70,13 @@ impl TryFrom for PackedKPuzzle { } }; orbit_iteration_info.push({ - PackedKPuzzleOrbitData { + PackedKPuzzleOrbitInfo { name: orbit_name.clone(), num_pieces: orbit_definition.num_pieces, num_orientations, - bytes_offset, + pieces_or_pemutations_offset: bytes_offset, + orientations_offset: bytes_offset + + std::convert::Into::::into(orbit_definition.num_pieces), unknown_orientation_value, table, } @@ -79,10 +85,13 @@ impl TryFrom for PackedKPuzzle { } Ok(Self { - data: (PackedKPuzzleData { + data: Arc::new(PackedKPuzzleData { kpuzzle, num_bytes: bytes_offset, orbit_iteration_info, + layout: Layout::array::(bytes_offset).map_err(|_| InvalidDefinitionError { + description: "Could not construct packed layout.".to_owned(), + })?, }), }) } @@ -99,59 +108,24 @@ fn usize_to_u8(n: usize) -> u8 { n.try_into().expect("Value too large!") // TODO } -#[macro_export] -macro_rules! set_packed_piece_or_permutation { - ($bytes:expr, $orbit_info:expr, $i:expr, $value: expr) => { - $bytes[$orbit_info.bytes_offset + $i] = ($value) - }; -} - -#[macro_export] -macro_rules! set_packed_orientation { - ($bytes:expr, $orbit_info:expr, $i:expr, $value: expr) => { - $bytes[$orbit_info.bytes_offset + $orbit_info.num_pieces + $i] = ($value) - }; -} - -#[macro_export] -macro_rules! set_packed_piece_or_permutation_and_orientation { - ($bytes:expr, $orbit_info:expr, $i:expr, $piece_or_permutation: expr, $orientation: expr) => { - set_packed_piece_or_permutation!($bytes, $orbit_info, $i, $piece_or_permutation); - set_packed_orientation!($bytes, $orbit_info, $i, $orientation); - }; -} - -#[macro_export] -macro_rules! get_packed_piece_or_permutation { - ($bytes:expr, $orbit_info:expr, $i:expr) => { - $bytes[$orbit_info.bytes_offset + $i] - }; -} - -// Applies to both states and transformations. -#[macro_export] -macro_rules! get_packed_orientation { - ($bytes:expr, $orbit_info:expr, $i:expr) => { - $bytes[$orbit_info.bytes_offset + $orbit_info.num_pieces + $i] - }; -} - impl PackedKPuzzle { pub fn start_state(&self) -> PackedKState { let kstate_start_state_data = self.data.kpuzzle.start_state().state_data; - let mut bytes: [u8; 52] = [0; 52]; + let new_state = PackedKState::new(self.clone()); for orbit_info in &self.data.orbit_iteration_info { let kstate_orbit_data = kstate_start_state_data .get(&orbit_info.name) .expect("Missing orbit!"); - let num_pieces = orbit_info.num_pieces; - for i in 0..num_pieces { - set_packed_piece_or_permutation_and_orientation!( - bytes, + for i in 0..orbit_info.num_pieces { + new_state.set_piece_or_permutation( orbit_info, i, usize_to_u8(kstate_orbit_data.pieces[i]), + ); + new_state.set_orientation( + orbit_info, + i, match &kstate_orbit_data.orientation_mod { None => usize_to_u8(kstate_orbit_data.orientation[i]), Some(orientation_mod) => { @@ -161,12 +135,12 @@ impl PackedKPuzzle { _ => panic!("Unsupported!"), // TODO } } - } + }, ); } } - PackedKState { bytes } + new_state } // TODO: implement this as a `TryFrom`? @@ -176,7 +150,7 @@ impl PackedKPuzzle { ) -> Result { let unpacked_ktransformation = self.data.kpuzzle.transformation_from_move(key_move)?; - let mut bytes: Vec = vec![0; self.data.num_bytes]; + let new_transformation = PackedKTransformation::new(self.clone()); for orbit_info in &self.data.orbit_iteration_info { let unpacked_orbit_data = unpacked_ktransformation .transformation_data @@ -186,16 +160,14 @@ impl PackedKPuzzle { description: format!("Missing orbit: {}", orbit_info.name), })?; for i in 0..orbit_info.num_pieces { - set_packed_piece_or_permutation_and_orientation!( - bytes, + new_transformation.set_piece_or_permutation( orbit_info, i, usize_to_u8(unpacked_orbit_data.permutation[i]), - usize_to_u8(unpacked_orbit_data.orientation[i]) ); } } - Ok(PackedKTransformation { bytes }) + Ok(new_transformation) } } diff --git a/examples/cpp_port/packed/packed_kstate.rs b/examples/cpp_port/packed/packed_kstate.rs index 231e66a2..dc2a8bb8 100644 --- a/examples/cpp_port/packed/packed_kstate.rs +++ b/examples/cpp_port/packed/packed_kstate.rs @@ -1,16 +1,61 @@ -use crate::{ - get_packed_orientation, get_packed_piece_or_permutation, set_packed_orientation, - set_packed_piece_or_permutation, set_packed_piece_or_permutation_and_orientation, -}; +use std::alloc::{alloc, dealloc}; -use super::{PackedKPuzzle, PackedKTransformation}; +use super::{packed_kpuzzle::PackedKPuzzleOrbitInfo, PackedKPuzzle, PackedKTransformation}; pub struct PackedKState { - // pub packed_kpuzzle: PackedKPuzzle, - pub bytes: [u8; 52], + pub packed_kpuzzle: PackedKPuzzle, + // pub bytes: [u8; 52], + pub bytes: *mut u8, +} + +impl Drop for PackedKState { + fn drop(&mut self) { + unsafe { dealloc(self.bytes, self.packed_kpuzzle.data.layout) } + } } impl PackedKState { + pub fn new(packed_kpuzzle: PackedKPuzzle) -> Self { + let bytes = unsafe { alloc(packed_kpuzzle.data.layout) }; + Self { + packed_kpuzzle, + bytes, + } + } + + pub fn get_piece_or_permutation(&self, orbit_info: &PackedKPuzzleOrbitInfo, i: usize) -> u8 { + unsafe { + self.bytes + .add(orbit_info.pieces_or_pemutations_offset + i) + .read() + } + } + + pub fn get_orientation(&self, orbit_info: &PackedKPuzzleOrbitInfo, i: usize) -> u8 { + unsafe { self.bytes.add(orbit_info.orientations_offset + i).read() } + } + + pub fn set_piece_or_permutation( + &self, + orbit_info: &PackedKPuzzleOrbitInfo, + i: usize, + value: u8, + ) { + unsafe { + self.bytes + .add(orbit_info.pieces_or_pemutations_offset + i) + .write(value) + } + } + + pub fn set_orientation(&self, orbit_info: &PackedKPuzzleOrbitInfo, i: usize, value: u8) { + unsafe { + self.bytes + .add(orbit_info.orientations_offset + i) + .write(value) + } + } + // Adapted from https://github.com/cubing/cubing.rs/blob/b737c6a36528e9984b45b29f9449a9a330c272fb/src/kpuzzle/state.rs#L31-L82 // TODO: dedup the implementation (but avoid runtime overhead for the shared abstraction). pub fn apply_transformation( @@ -18,36 +63,33 @@ impl PackedKState { packed_kpuzzle: &PackedKPuzzle, transformation: &PackedKTransformation, ) -> PackedKState { - let mut bytes: [u8; 52] = [0; 52]; + let new_state = PackedKState::new(self.packed_kpuzzle.clone()); for orbit_info in &packed_kpuzzle.data.orbit_iteration_info { // TODO: optimization when either value is the identity. for i in 0..orbit_info.num_pieces { - let transformation_idx = std::convert::Into::::into( - get_packed_piece_or_permutation!(transformation.bytes, orbit_info, i), + let transformation_idx = transformation.get_piece_or_permutation(orbit_info, i); + + let new_piece_permutation = self.get_piece_or_permutation( + orbit_info, + std::convert::Into::::into(transformation_idx), ); + self.set_piece_or_permutation(orbit_info, i, new_piece_permutation); - let new_piece_permutation = - get_packed_piece_or_permutation!(self.bytes, orbit_info, transformation_idx); - let previous_piece_orientation = - get_packed_orientation!(self.bytes, orbit_info, transformation_idx); - let new_piece_orientation = orbit_info.table[std::convert::Into::::into( - previous_piece_orientation - + get_packed_orientation!(transformation.bytes, orbit_info, i), - )]; - set_packed_piece_or_permutation_and_orientation!( - bytes, + let previous_piece_orientation = self.get_orientation( orbit_info, - i, - new_piece_permutation, - new_piece_orientation + std::convert::Into::::into(transformation_idx), ); + let new_piece_orientation = orbit_info.table[std::convert::Into::::into( + previous_piece_orientation + transformation.get_orientation(orbit_info, i), + )]; + self.set_orientation(orbit_info, i, new_piece_orientation); } } - PackedKState { bytes } + new_state } - pub fn hash(&self) -> u64 { - cityhash::city_hash_64(&self.bytes) - } + // pub fn hash(&self) -> u64 { + // cityhash::city_hash_64(&self.bytes) + // } } diff --git a/examples/cpp_port/packed/packed_ktransformation.rs b/examples/cpp_port/packed/packed_ktransformation.rs index 5dfc5c6e..c220ce41 100644 --- a/examples/cpp_port/packed/packed_ktransformation.rs +++ b/examples/cpp_port/packed/packed_ktransformation.rs @@ -1,3 +1,59 @@ +use std::alloc::{alloc, dealloc}; + +use super::{packed_kpuzzle::PackedKPuzzleOrbitInfo, PackedKPuzzle}; pub struct PackedKTransformation { - pub bytes: Vec, + pub packed_kpuzzle: PackedKPuzzle, + pub bytes: *mut u8, +} + +impl Drop for PackedKTransformation { + fn drop(&mut self) { + unsafe { dealloc(self.bytes, self.packed_kpuzzle.data.layout) } + } +} + +impl PackedKTransformation { + pub fn new(packed_kpuzzle: PackedKPuzzle) -> Self { + let bytes = unsafe { alloc(packed_kpuzzle.data.layout) }; + Self { + packed_kpuzzle, + bytes, + } + } + // TODO: dedup with PackedKTransformation, or at least implement as a trait? + pub fn get_piece_or_permutation(&self, orbit_info: &PackedKPuzzleOrbitInfo, i: usize) -> u8 { + unsafe { + self.bytes + .add(orbit_info.pieces_or_pemutations_offset + i) + .read() + } + } + + // TODO: dedup with PackedKTransformation, or at least implement as a trait? + pub fn get_orientation(&self, orbit_info: &PackedKPuzzleOrbitInfo, i: usize) -> u8 { + unsafe { self.bytes.add(orbit_info.orientations_offset + i).read() } + } + + // TODO: dedup with PackedKTransformation, or at least implement as a trait? + pub fn set_piece_or_permutation( + &self, + orbit_info: &PackedKPuzzleOrbitInfo, + i: usize, + value: u8, + ) { + unsafe { + self.bytes + .add(orbit_info.pieces_or_pemutations_offset + i) + .write(value) + } + } + + // TODO: dedup with PackedKTransformation, or at least implement as a trait? + pub fn set_orientation(&self, orbit_info: &PackedKPuzzleOrbitInfo, i: usize, value: u8) { + unsafe { + self.bytes + .add(orbit_info.orientations_offset + i) + .write(value) + } + } } diff --git a/examples/test-cpp_port.rs b/examples/test-cpp_port.rs index 5390ad2e..c871b161 100644 --- a/examples/test-cpp_port.rs +++ b/examples/test-cpp_port.rs @@ -56,18 +56,18 @@ fn test_packed(num_moves: usize) { num_moves, duration ); - let mut state = packed_kpuzzle.start_state(); - let start = Instant::now(); - for i in 0..num_moves { - state = state.apply_transformation(&packed_kpuzzle, &move_transformations[i % 18]); - _ = state.hash(); - } - println!("{:?}", state.bytes); - let duration = start.elapsed(); - println!( - "Time elapsed for {} moves (packed) with hashing:: {:?}", - num_moves, duration - ); + // let mut state = packed_kpuzzle.start_state(); + // let start = Instant::now(); + // for i in 0..num_moves { + // state = state.apply_transformation(&packed_kpuzzle, &move_transformations[i % 18]); + // // _ = state.hash(); + // } + // println!("{:?}", state.bytes); + // let duration = start.elapsed(); + // println!( + // "Time elapsed for {} moves (packed) with hashing:: {:?}", + // num_moves, duration + // ); } fn test_unpacked(num_moves: usize) {