use core::hash::{Hash, Hasher};
use core::borrow::Borrow;
use core::marker::PhantomData;
use array_init::array_init;
use crate::LookUpError;
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
struct Patch<T>{
contents: [T;512]
}
impl<T> Copy for Patch<T> where T: Copy{}
impl<T> Clone for Patch<T> where T: Clone{
fn clone(&self) -> Self {
Self{contents: self.contents.clone()}
}
}
impl<T> PartialEq for Patch<T> where T: PartialEq{
fn eq(&self, other: &Self) -> bool {
self.contents.eq(&other.contents)
}
}
impl<T> Eq for Patch<T> where T: Eq{}
impl<T> Hash for Patch<T> where T: Hash{
fn hash<H: Hasher>(&self, state: &mut H) {
for item in &self.contents {
item.hash(state);
}
}
}
impl<T> Patch<T> {
fn get(&self, x: usize, y:usize, z:usize) -> &T {
return &self.contents[zorder_4bit_to_12bit(
x as u8 & 0x07, y as u8 & 0x07, z as u8 & 0x07) as usize];
}
fn set(&mut self, x: usize, y:usize, z:usize, new_val: T) {
let i = zorder_4bit_to_12bit(
x as u8 & 0x07, y as u8 & 0x07, z as u8 & 0x07) as usize;
self.contents[i] = new_val;
}
}
fn patch_index(x: usize, y:usize, z:usize, pxsize: usize, pysize: usize) -> usize{
return (x >> 3) + pxsize * ((y >> 3) + (pysize * (z >> 3)));
}
fn patch_coords(pxsize: usize, pysize: usize, pindex: usize) -> [(usize, usize, usize); 512] {
let mut outbuffer = [(0usize, 0usize, 0usize); 512];
let bx = (pindex % pxsize) << 3;
let by = ((pindex / pxsize) % pysize) << 3;
let bz = (pindex / (pxsize * pysize)) << 3;
for i in 0..512 {
let bitmask = REVERSE_ZLUT[i];
let dx = bitmask & 0b00000111u16;
let dy = (bitmask >> 3u16) & 0b00000111u16;
let dz = (bitmask >> 6u16) & 0b00000111u16;
outbuffer[i] = (bx + dx as usize, by + dy as usize, bz + dz as usize);
}
return outbuffer;
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ZArray3D<T> {
xsize: usize,
ysize: usize,
zsize: usize,
pxsize: usize,
pysize: usize,
patches: Vec<Patch<T>>,
_phantomdata: PhantomData<T>,
}
impl<T> Clone for ZArray3D<T> where T: Clone{
fn clone(&self) -> Self {
Self{
xsize: self.xsize,
ysize: self.ysize,
zsize: self.zsize,
pxsize: self.pxsize,
pysize: self.pysize,
patches: self.patches.clone(),
_phantomdata: self._phantomdata
}
}
}
impl<T> PartialEq for ZArray3D<T> where T: PartialEq{
fn eq(&self, other: &Self) -> bool {
self.xsize == other.xsize
&& self.ysize == other.ysize
&& self.zsize == other.zsize
&& self.pxsize == other.pxsize
&& self.pysize == other.pysize
&& self.patches == other.patches
}
}
impl<T> Eq for ZArray3D<T> where T: Eq{}
impl<T> Hash for ZArray3D<T> where T: Hash{
fn hash<H: Hasher>(&self, state: &mut H) {
for patch in &self.patches {
patch.hash(state);
}
}
}
impl<T> ZArray3D<T> where T: Default {
pub fn new_with_default(xsize: usize, ysize: usize, zsize: usize) -> ZArray3D<T> {
let px = ((xsize-1) >> 3) + 1;
let py = ((ysize-1) >> 3) + 1;
let pz = ((zsize-1) >> 3) + 1;
let patch_count = px * py * pz;
let mut p = Vec::with_capacity(patch_count);
for _ in 0..patch_count {
let default_contents: [T; 512] = array_init(|_|T::default());
p.push(Patch { contents: default_contents });
}
return ZArray3D { xsize, ysize, zsize, pxsize: px, pysize: py,
patches: p, _phantomdata: PhantomData};
}
}
impl<T> ZArray3D<T> where T: Copy {
pub fn new(xsize: usize, ysize: usize, zsize: usize, default_val: T) -> ZArray3D<T>{
let px = ((xsize-1) >> 3) + 1;
let py = ((ysize-1) >> 3) + 1;
let pz = ((zsize-1) >> 3) + 1;
let patch_count = px * py * pz;
let mut p = Vec::with_capacity(patch_count);
for _ in 0..patch_count{
p.push(Patch{contents: [default_val; 512]});
}
return ZArray3D { xsize, ysize, zsize, pxsize: px, pysize: py,
patches: p, _phantomdata: PhantomData};
}
}
impl<T> ZArray3D<T> where T: Clone {
pub fn fill(&mut self, x1: usize, y1: usize, z1: usize, x2: usize, y2: usize, z2: usize, new_val: impl Borrow<T>) -> Result<(), LookUpError> {
for y in y1..y2{ for x in x1..x2{ for z in z1..z2{
self.set(x, y, z, new_val.borrow().clone())?;
} } }
Ok(())
}
pub fn wrapped_fill(&mut self, x1: isize, y1: isize, z1: isize,
x2: isize, y2: isize, z2: isize, new_val: impl Borrow<T>) {
for y in y1..y2{ for x in x1..x2{ for z in z1..z2{
self.wrapped_set(x, y, z, new_val.borrow().clone());
} } }
}
pub fn bounded_fill(&mut self, x1: isize, y1: isize, z1: isize,
x2: isize, y2: isize, z2: isize, new_val: impl Borrow<T>) {
for y in y1..y2{ for x in x1..x2{ for z in z1..z2{
self.bounded_set(x, y, z, new_val.borrow().clone());
} } }
}
}
impl<T> ZArray3D<T> {
pub fn new_with_constructor(xsize: usize, ysize: usize, zsize: usize, constructor: impl Fn((usize, usize, usize)) -> T) -> ZArray3D<T> {
let px = ((xsize-1) >> 3) + 1;
let py = ((ysize-1) >> 3) + 1;
let pz = ((zsize-1) >> 3) + 1;
let patch_count = px * py * pz;
let mut p = Vec::with_capacity(patch_count);
for pindex in 0..patch_count {
let lookup_table = patch_coords(px, py, pindex);
let initial_contents: [T; 512] = array_init(|i| constructor(lookup_table[i]));
p.push(Patch { contents: initial_contents });
}
return ZArray3D { xsize, ysize, zsize, pxsize: px, pysize: py,
patches: p, _phantomdata: PhantomData};
}
pub fn dimensions(&self) -> (usize, usize, usize){
return (self.xsize, self.ysize, self.zsize);
}
pub fn xsize(&self) -> usize {
return self.xsize;
}
pub fn width(&self) -> usize {
return self.xsize();
}
pub fn ysize(&self) -> usize {
return self.ysize;
}
pub fn height(&self) -> usize {
return self.ysize();
}
pub fn zsize(&self) -> usize {
return self.zsize;
}
pub fn depth(&self) -> usize {
return self.zsize();
}
pub fn get(&self, x: usize, y: usize, z: usize) -> Result<&T,LookUpError>{
if x < self.xsize && y < self.ysize && z < self.zsize {
Ok(self.patches[patch_index(x, y, z, self.pxsize, self.pysize)].get(x, y, z))
} else {
Err(LookUpError{coord: vec![x, y, z],
bounds: vec![self.xsize, self.ysize, self.zsize]})
}
}
pub fn set(&mut self, x: usize, y: usize, z: usize, new_val: T) -> Result<(),LookUpError>{
if x < self.xsize && y < self.ysize && z < self.zsize {
Ok(self.patches[patch_index(x, y, z, self.pxsize, self.pysize)]
.set(x, y, z, new_val))
} else {
Err(LookUpError{coord: vec![x, y, z],
bounds: vec![self.xsize, self.ysize, self.zsize]})
}
}
pub fn get_unchecked(&self, x: usize, y: usize, z: usize) -> &T {
return self.patches[patch_index(x, y, z, self.pxsize, self.pysize)].get(x, y, z);
}
pub fn set_unchecked(&mut self, x: usize, y: usize, z: usize, new_val: T) {
self.patches[patch_index(x, y, z, self.pxsize, self.pysize)]
.set(x, y, z, new_val);
}
pub fn wrapped_get(&self, x: isize, y: isize, z: isize) -> &T{
let x = (self.xsize as isize + (x % self.xsize as isize)) as usize % self.xsize;
let y = (self.ysize as isize + (y % self.ysize as isize)) as usize % self.ysize;
let z = (self.zsize as isize + (z % self.zsize as isize)) as usize % self.zsize;
return &self.patches[patch_index(x, y, z, self.pxsize, self.pysize)].get(x, y, z);
}
pub fn wrapped_set(&mut self, x: isize, y: isize, z: isize, new_val: T) {
let x = (self.xsize as isize + (x % self.xsize as isize)) as usize % self.xsize;
let y = (self.ysize as isize + (y % self.ysize as isize)) as usize % self.ysize;
let z = (self.zsize as isize + (z % self.zsize as isize)) as usize % self.zsize;
self.patches[patch_index(x, y, z, self.pxsize, self.pysize)].set(x, y, z, new_val);
}
pub fn bounded_get(&self, x: isize, y: isize, z: isize) -> Option<&T>{
if x >= 0 && y >= 0 && z >= 0
&& x < self.xsize as isize && y < self.ysize as isize && z < self.zsize as isize {
return Some(&self.patches[
patch_index(x as usize, y as usize, z as usize, self.pxsize, self.pysize)]
.get(x as usize, y as usize, z as usize));
} else {
return None;
}
}
pub fn bounded_set(&mut self, x: isize, y: isize, z: isize, new_val: T) {
if x >= 0 && y >= 0 && z >= 0
&& x < self.xsize as isize && y < self.ysize as isize && z < self.zsize as isize {
self.patches[
patch_index(x as usize, y as usize, z as usize, self.pxsize, self.pysize)]
.set(x as usize, y as usize, z as usize, new_val);
} else {
}
}
pub fn iter(&self) -> ZArray3DIterator<T> {
ZArray3DIterator::new(self)
}
pub fn transform(&mut self, transform_fn: impl Fn((usize, usize, usize), &T) -> T) {
for pindex in 0..self.patches.len() {
let patch_coords = patch_coords(self.pxsize, self.pysize, pindex);
for coord in patch_coords {
if coord.0 < self.xsize && coord.1 < self.ysize && coord.2 < self.zsize {
let old_val = self.get_unchecked(coord.0, coord.1, coord.2);
self.set_unchecked(coord.0, coord.1, coord.2, transform_fn(coord, old_val));
}
}
}
}
pub fn coords(&self) -> Vec<(usize, usize, usize)> {
let mut out: Vec<(usize, usize, usize)> = Vec::with_capacity(self.xsize * self.ysize * self.zsize);
for pindex in 0..self.patches.len() {
let patch_coords = patch_coords(self.pxsize, self.pysize, pindex);
for coord in patch_coords {
if coord.0 < self.xsize && coord.1 < self.ysize && coord.2 < self.zsize {
out.push(coord);
}
}
}
return out;
}
}
#[test]
fn check_patch_count_3d() {
let arr = ZArray3D::new(1, 1, 1, 0u8);
assert_eq!(arr.patches.len(), 1, "Allocated wrong number of patches for array of size {}x{}x{}", arr.xsize, arr.ysize, arr.zsize);
let arr = ZArray3D::new(8, 8, 8, 0u8);
assert_eq!(arr.patches.len(), 1, "Allocated wrong number of patches for array of size {}x{}x{}", arr.xsize, arr.ysize, arr.zsize);
let arr = ZArray3D::new(9, 8, 8, 0u8);
assert_eq!(arr.patches.len(), 2, "Allocated wrong number of patches for array of size {}x{}x{}", arr.xsize, arr.ysize, arr.zsize);
let arr = ZArray3D::new(8, 9, 8, 0u8);
assert_eq!(arr.patches.len(), 2, "Allocated wrong number of patches for array of size {}x{}x{}", arr.xsize, arr.ysize, arr.zsize);
let arr = ZArray3D::new(8, 8, 9, 0u8);
assert_eq!(arr.patches.len(), 2, "Allocated wrong number of patches for array of size {}x{}x{}", arr.xsize, arr.ysize, arr.zsize);
let arr = ZArray3D::new(9, 9, 9, 0u8);
assert_eq!(arr.patches.len(), 8, "Allocated wrong number of patches for array of size {}x{}x{}", arr.xsize, arr.ysize, arr.zsize);
}
const ZLUT: [u16; 16] = [
0b0000000000000000,
0b0000000000000001,
0b0000000000001000,
0b0000000000001001,
0b0000000001000000,
0b0000000001000001,
0b0000000001001000,
0b0000000001001001,
0b0000001000000000,
0b0000001000000001,
0b0000001000001000,
0b0000001000001001,
0b0000001001000000,
0b0000001001000001,
0b0000001001001000,
0b0000001001001001
];
pub fn zorder_4bit_to_12bit(x: u8, y: u8, z: u8) -> u16 {
let x_bits = ZLUT[(x & 0x0F) as usize];
let y_bits = ZLUT[(y & 0x0F) as usize] << 1;
let z_bits = ZLUT[(z & 0x0F) as usize] << 2;
return z_bits | y_bits | x_bits;
}
pub fn zorder_8bit_to_24bit(x:u8, y:u8, z: u8) -> u32 {
return ((zorder_4bit_to_12bit(x >> 4, y >> 4, z >> 4) as u32) << 12)
| zorder_4bit_to_12bit(x, y, z) as u32
}
const REVERSE_ZLUT: [u16; 512] = [
0, 1, 8, 9, 64, 65, 72, 73, 2, 3, 10, 11, 66, 67, 74, 75,
16, 17, 24, 25, 80, 81, 88, 89, 18, 19, 26, 27, 82, 83, 90, 91,
128, 129, 136, 137, 192, 193, 200, 201, 130, 131, 138, 139, 194, 195, 202, 203,
144, 145, 152, 153, 208, 209, 216, 217, 146, 147, 154, 155, 210, 211, 218, 219,
4, 5, 12, 13, 68, 69, 76, 77, 6, 7, 14, 15, 70, 71, 78, 79,
20, 21, 28, 29, 84, 85, 92, 93, 22, 23, 30, 31, 86, 87, 94, 95,
132, 133, 140, 141, 196, 197, 204, 205, 134, 135, 142, 143, 198, 199, 206, 207,
148, 149, 156, 157, 212, 213, 220, 221, 150, 151, 158, 159, 214, 215, 222, 223,
32, 33, 40, 41, 96, 97, 104, 105, 34, 35, 42, 43, 98, 99, 106, 107,
48, 49, 56, 57, 112, 113, 120, 121, 50, 51, 58, 59, 114, 115, 122, 123,
160, 161, 168, 169, 224, 225, 232, 233, 162, 163, 170, 171, 226, 227, 234, 235,
176, 177, 184, 185, 240, 241, 248, 249, 178, 179, 186, 187, 242, 243, 250, 251,
36, 37, 44, 45, 100, 101, 108, 109, 38, 39, 46, 47, 102, 103, 110, 111,
52, 53, 60, 61, 116, 117, 124, 125, 54, 55, 62, 63, 118, 119, 126, 127,
164, 165, 172, 173, 228, 229, 236, 237, 166, 167, 174, 175, 230, 231, 238, 239,
180, 181, 188, 189, 244, 245, 252, 253, 182, 183, 190, 191, 246, 247, 254, 255,
256, 257, 264, 265, 320, 321, 328, 329, 258, 259, 266, 267, 322, 323, 330, 331,
272, 273, 280, 281, 336, 337, 344, 345, 274, 275, 282, 283, 338, 339, 346, 347,
384, 385, 392, 393, 448, 449, 456, 457, 386, 387, 394, 395, 450, 451, 458, 459,
400, 401, 408, 409, 464, 465, 472, 473, 402, 403, 410, 411, 466, 467, 474, 475,
260, 261, 268, 269, 324, 325, 332, 333, 262, 263, 270, 271, 326, 327, 334, 335,
276, 277, 284, 285, 340, 341, 348, 349, 278, 279, 286, 287, 342, 343, 350, 351,
388, 389, 396, 397, 452, 453, 460, 461, 390, 391, 398, 399, 454, 455, 462, 463,
404, 405, 412, 413, 468, 469, 476, 477, 406, 407, 414, 415, 470, 471, 478, 479,
288, 289, 296, 297, 352, 353, 360, 361, 290, 291, 298, 299, 354, 355, 362, 363,
304, 305, 312, 313, 368, 369, 376, 377, 306, 307, 314, 315, 370, 371, 378, 379,
416, 417, 424, 425, 480, 481, 488, 489, 418, 419, 426, 427, 482, 483, 490, 491,
432, 433, 440, 441, 496, 497, 504, 505, 434, 435, 442, 443, 498, 499, 506, 507,
292, 293, 300, 301, 356, 357, 364, 365, 294, 295, 302, 303, 358, 359, 366, 367,
308, 309, 316, 317, 372, 373, 380, 381, 310, 311, 318, 319, 374, 375, 382, 383,
420, 421, 428, 429, 484, 485, 492, 493, 422, 423, 430, 431, 486, 487, 494, 495,
436, 437, 444, 445, 500, 501, 508, 509, 438, 439, 446, 447, 502, 503, 510, 511,
];
#[derive(Debug)]
pub struct ZArray3DIteratorItem<'a, T> {
pub x: usize,
pub y: usize,
pub z: usize,
pub value: &'a T
}
enum IterState {
Start, Processing, Done
}
pub struct ZArray3DIterator<'a, T> {
array: &'a ZArray3D<T>,
patch: usize,
index: usize,
state: IterState
}
impl<'a, T> ZArray3DIterator<'a, T> {
fn new(array: &'a ZArray3D<T>) -> ZArray3DIterator<'a, T> {
if array.xsize == 0 || array.ysize == 0 || array.zsize == 0 {
ZArray3DIterator{array, patch: 0, index: 0, state: IterState::Done} } else {
ZArray3DIterator{array, patch: 0, index: 0, state: IterState::Start}
}
}
}
impl<'a, T> Iterator for ZArray3DIterator<'a, T> {
type Item = ZArray3DIteratorItem<'a, T>;
fn next(&mut self) -> Option<Self::Item> {
match &self.state {
IterState::Done=> None,
IterState::Start=> {
self.state = IterState::Processing;
Some(ZArray3DIteratorItem{x: 0, y: 0, z: 0, value: &self.array.patches[0].contents[0]})
},
IterState::Processing => {
let mut x ; let mut y ; let mut z ;
loop {
self.index += 1;
if self.index >= 512 {
self.index = 0;
self.patch += 1;
}
let zyx_lower_pits = REVERSE_ZLUT[self.index];
x = ((self.patch % self.array.pxsize) << 3) | (zyx_lower_pits & 0x07) as usize;
y = (((self.patch / self.array.pxsize) % self.array.pysize ) << 3) | ((zyx_lower_pits >> 3) & 0x07) as usize;
z = ( (self.patch / (self.array.pysize * self.array.pxsize)) << 3) | ((zyx_lower_pits >> 6) & 0x07) as usize;
if x < self.array.xsize && y < self.array.ysize && z < self.array.zsize {
break;
}
if self.patch >= self.array.patches.len() {
self.state = IterState::Done;
return None;
}
}
Some(ZArray3DIteratorItem{x, y, z, value: &self.array.patches[self.patch].contents[self.index]})
}
}
}
}
#[test]
fn print_3d_zorder() {
let mut array = ZArray3D::new(8, 8, 8, 0usize);
for z in 0..8usize {
for y in 0..8usize {
for x in 0..8usize {
array.set_unchecked(x, y, z, (z << 6) | (y << 3) | x);
}
}
}
println!("[");
for i in 0..array.patches[0].contents.len() {
print!("{:?}, ", array.patches[0].contents[i]);
if i % 16 == 15{println!()}
}
println!("]");
}