2023-11-30 23:56:01 +01:00
extern crate test ;
use std ::{
2023-12-03 16:25:25 +01:00
fmt ::Debug ,
2023-11-30 23:56:01 +01:00
hash ::Hash ,
2023-12-03 16:25:25 +01:00
iter ::Step ,
2023-12-10 21:50:02 +01:00
ops ::{ Add , AddAssign , Index } ,
2023-11-30 23:56:01 +01:00
} ;
2023-12-10 22:08:38 +01:00
use crate ::common ::Inc ;
2023-11-30 23:56:01 +01:00
2023-12-03 16:25:25 +01:00
#[ derive(Hash, PartialEq, Eq, Debug, Clone, Copy) ]
pub struct PositionND < I , const DIMS : usize > ( pub [ I ; DIMS ] ) ;
2023-11-30 23:56:01 +01:00
2023-12-03 16:25:25 +01:00
pub type Position2D < I > = PositionND < I , 2 > ;
2023-11-30 23:56:01 +01:00
pub const fn num_neighbors ( d : usize ) -> usize {
3 usize . pow ( d as u32 ) - 1
}
2023-12-03 16:25:25 +01:00
impl < I : Inc + Add < I , Output = I > + AddAssign + Debug , const DIMS : usize > PositionND < I , DIMS > {
pub fn zero ( ) -> Self {
PositionND ( [ I ::default ( ) ; DIMS ] )
2023-11-30 23:56:01 +01:00
}
2023-12-03 16:25:25 +01:00
pub fn from_padded ( slice : & [ I ] ) -> PositionND < I , DIMS > {
let mut points = [ I ::default ( ) ; DIMS ] ;
2023-11-30 23:56:01 +01:00
#[ allow(clippy::manual_memcpy) ]
for i in 0 .. ( DIMS . min ( slice . len ( ) ) ) {
points [ i ] = slice [ i ] ;
}
PositionND ( points )
}
2023-12-03 16:25:25 +01:00
pub fn neighbors ( & self ) -> [ PositionND < I , DIMS > ; num_neighbors ( DIMS ) ]
where [ PositionND < I , DIMS > ; num_neighbors ( DIMS ) + 1 ] : Sized {
let ns = neighbor_vectors ::< I , DIMS > ( ) ;
2023-11-30 23:56:01 +01:00
let mut out = [ * self ; num_neighbors ( DIMS ) ] ;
2023-12-03 16:25:25 +01:00
for ( out , dir ) in out . iter_mut ( ) . zip ( IntoIterator ::into_iter ( ns ) . filter ( | n | n ! = & [ I ::default ( ) ; DIMS ] ) ) {
* out = * out + PositionND ( dir ) ;
2023-11-30 23:56:01 +01:00
}
out
}
}
2023-12-03 16:25:25 +01:00
impl < I , const D : usize > Add < PositionND < I , D > > for PositionND < I , D >
where I : AddAssign < I > + Copy
{
type Output = PositionND < I , D > ;
fn add ( mut self , rhs : PositionND < I , D > ) -> Self ::Output {
for ( x , y ) in self . 0. iter_mut ( ) . zip ( rhs . 0 ) {
* x + = y ;
}
self
2023-11-30 23:56:01 +01:00
}
2023-12-03 16:25:25 +01:00
}
2023-11-30 23:56:01 +01:00
2023-12-10 21:50:02 +01:00
impl < I , const D : usize > Index < usize > for PositionND < I , D > {
type Output = I ;
fn index ( & self , index : usize ) -> & Self ::Output {
& self . 0 [ index ]
}
}
2023-12-03 16:25:25 +01:00
impl < I : Copy + Default + Step > PositionND < I , 2 > {
pub fn neighbors_no_diagonals ( & self ) -> [ PositionND < I , 2 > ; 4 ] {
let PositionND ( [ x , y ] ) = * self ;
[ PositionND ( [ x . inc ( ) , y ] ) , PositionND ( [ x , y . inc ( ) ] ) , PositionND ( [ x . dec ( ) , y ] ) , PositionND ( [ x , y . dec ( ) ] ) ]
2023-11-30 23:56:01 +01:00
}
}
macro_rules ! dim {
2023-12-03 16:25:25 +01:00
( $d : expr , $i :ty ) = > { {
let zero : $i = Default ::default ( ) ;
let mut out = [ [ zero ; D ] ; num_neighbors ( D ) + 1 ] ;
2023-11-30 23:56:01 +01:00
let mut i = 0 ;
2023-12-03 16:25:25 +01:00
for offset in zero . dec ( ) ..= zero . inc ( ) {
for inner in neighbor_vectors ::< $i , $d > ( ) {
2023-11-30 23:56:01 +01:00
out [ i ] [ 0 ] = offset ;
let mut j = 1 ;
for e in inner {
out [ i ] [ j ] = e ;
j + = 1 ;
}
i + = 1 ;
}
}
out
} } ;
}
2023-12-03 16:25:25 +01:00
fn neighbor_vectors < I : Inc , const D : usize > ( ) -> [ [ I ; D ] ; num_neighbors ( D ) + 1 ] {
2023-11-30 23:56:01 +01:00
// I would love to just call neighbor_vectors::<D-1>(), but it seems to be impossible to get the
// correct constraints for that.
match D {
0 = > unreachable! ( ) ,
1 = > {
2023-12-03 16:25:25 +01:00
let zero = I ::default ( ) ;
let mut out = [ [ zero ; D ] ; num_neighbors ( D ) + 1 ] ;
out [ 0 ] = [ zero . dec ( ) ; D ] ;
out [ 1 ] = [ zero ; D ] ;
out [ 2 ] = [ zero . inc ( ) ; D ] ;
2023-11-30 23:56:01 +01:00
out
}
2023-12-03 16:25:25 +01:00
2 = > dim! ( 1 , I ) ,
3 = > dim! ( 2 , I ) ,
4 = > dim! ( 3 , I ) ,
5 = > dim! ( 4 , I ) ,
6 = > dim! ( 5 , I ) ,
7 = > dim! ( 6 , I ) ,
2023-11-30 23:56:01 +01:00
// Adding more causes a stackoverflow. How curious.
_ = > unimplemented! ( ) ,
}
}
#[ cfg(test) ]
mod tests {
use super ::* ;
#[ test ]
fn test_neighbors_2d ( ) {
let p = PositionND ( [ 0 , 0 ] ) ;
let n = p . neighbors ( ) ;
assert_eq! (
n ,
[
PositionND ( [ - 1 , - 1 ] ) ,
PositionND ( [ - 1 , 0 ] ) ,
PositionND ( [ - 1 , 1 ] ) ,
PositionND ( [ 0 , - 1 ] ) ,
PositionND ( [ 0 , 1 ] ) ,
PositionND ( [ 1 , - 1 ] ) ,
PositionND ( [ 1 , 0 ] ) ,
PositionND ( [ 1 , 1 ] ) ,
]
) ;
let p = PositionND ( [ 1 , 1 ] ) ;
let n = p . neighbors ( ) ;
assert_eq! (
n ,
[
PositionND ( [ 0 , 0 ] ) ,
PositionND ( [ 0 , 1 ] ) ,
PositionND ( [ 0 , 2 ] ) ,
PositionND ( [ 1 , 0 ] ) ,
PositionND ( [ 1 , 2 ] ) ,
PositionND ( [ 2 , 0 ] ) ,
PositionND ( [ 2 , 1 ] ) ,
PositionND ( [ 2 , 2 ] ) ,
]
)
}
#[ test ]
fn test_neighbors_3d ( ) {
let p = PositionND ( [ 0 , 0 , 0 ] ) ;
let n = p . neighbors ( ) ;
assert_eq! (
n ,
[
PositionND ( [ - 1 , - 1 , - 1 ] ) ,
PositionND ( [ - 1 , - 1 , 0 ] ) ,
PositionND ( [ - 1 , - 1 , 1 ] ) ,
PositionND ( [ - 1 , 0 , - 1 ] ) ,
PositionND ( [ - 1 , 0 , 0 ] ) ,
PositionND ( [ - 1 , 0 , 1 ] ) ,
PositionND ( [ - 1 , 1 , - 1 ] ) ,
PositionND ( [ - 1 , 1 , 0 ] ) ,
PositionND ( [ - 1 , 1 , 1 ] ) ,
PositionND ( [ 0 , - 1 , - 1 ] ) ,
PositionND ( [ 0 , - 1 , 0 ] ) ,
PositionND ( [ 0 , - 1 , 1 ] ) ,
PositionND ( [ 0 , 0 , - 1 ] ) ,
PositionND ( [ 0 , 0 , 1 ] ) ,
PositionND ( [ 0 , 1 , - 1 ] ) ,
PositionND ( [ 0 , 1 , 0 ] ) ,
PositionND ( [ 0 , 1 , 1 ] ) ,
PositionND ( [ 1 , - 1 , - 1 ] ) ,
PositionND ( [ 1 , - 1 , 0 ] ) ,
PositionND ( [ 1 , - 1 , 1 ] ) ,
PositionND ( [ 1 , 0 , - 1 ] ) ,
PositionND ( [ 1 , 0 , 0 ] ) ,
PositionND ( [ 1 , 0 , 1 ] ) ,
PositionND ( [ 1 , 1 , - 1 ] ) ,
PositionND ( [ 1 , 1 , 0 ] ) ,
PositionND ( [ 1 , 1 , 1 ] ) ,
]
) ;
}
#[ test ]
fn test_neighbor_vectors ( ) {
2023-12-03 20:21:13 +01:00
let n = neighbor_vectors ::< i32 , 2 > ( ) ;
2023-11-30 23:56:01 +01:00
assert_eq! ( n , [ [ - 1 , - 1 ] , [ - 1 , 0 ] , [ - 1 , 1 ] , [ 0 , - 1 ] , [ 0 , 0 ] , [ 0 , 1 ] , [ 1 , - 1 ] , [ 1 , 0 ] , [ 1 , 1 ] , ] ) ;
}
#[ bench ]
fn bench_neighbor_vectors_2d ( b : & mut test ::Bencher ) {
2023-12-03 20:21:13 +01:00
b . iter ( | | test ::black_box ( neighbor_vectors ::< i32 , 2 > ( ) ) )
2023-11-30 23:56:01 +01:00
}
#[ bench ]
fn bench_neighbor_vectors_3d ( b : & mut test ::Bencher ) {
2023-12-03 20:21:13 +01:00
b . iter ( | | test ::black_box ( neighbor_vectors ::< i32 , 3 > ( ) ) )
2023-11-30 23:56:01 +01:00
}
#[ bench ]
fn bench_neighbor_vectors_4d ( b : & mut test ::Bencher ) {
2023-12-03 20:21:13 +01:00
b . iter ( | | test ::black_box ( neighbor_vectors ::< i32 , 4 > ( ) ) )
2023-11-30 23:56:01 +01:00
}
#[ bench ]
fn bench_neighbor_vectors_5d ( b : & mut test ::Bencher ) {
2023-12-03 20:21:13 +01:00
b . iter ( | | test ::black_box ( neighbor_vectors ::< i32 , 5 > ( ) ) )
2023-11-30 23:56:01 +01:00
}
}