From 3d28a25d2279aca9014d0f6d82479ba83cc9c3bc Mon Sep 17 00:00:00 2001 From: Reinier Maas Date: Wed, 1 Feb 2017 15:25:00 +0100 Subject: [PATCH 1/9] WIP: iterator building --- src/lib.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 6 ++++ 2 files changed, 85 insertions(+) create mode 100644 src/main.rs diff --git a/src/lib.rs b/src/lib.rs index 5f9ff4b..fb3c085 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,85 @@ #[cfg(test)] extern crate rand; #[cfg(test)] extern crate test; +pub struct MortonChunk<'m, T: 'm> { + morton_chunk: &'m mut [T], + side_length: usize, +} + +impl<'m, T> MortonChunk<'m, T> { + pub fn new(morton_chunk: &mut [T], side_length: usize) -> MortonChunk { + assert!(morton_chunk.len() == side_length * side_length); + MortonChunk { + morton_chunk: morton_chunk, + side_length: side_length, + } + } +} +pub struct Morton<'m, T: 'm> { + morton_chunks: Vec>, + width: usize, + height: usize, + side_length: usize, +} + +impl<'m, T> Morton<'m, T> { + pub fn new(width: usize, height: usize, data: &mut Vec) -> Morton<'m, T> { + assert!(data.len() == width * height); + // greatest common single digit diviser + let mut side_length = 1; + { + let mut width = width; + let mut height = height; + while { + width >>= 1; + height >>= 1; + width > 0 && height > 0 + } { side_length <<= 1; } + // side_length is minimum of both most significant bits + // side_length is now an upper bound of the binary gcd + } + while (width / side_length) * side_length < width || (height / side_length) * side_length < height { + side_length >>= 1; + } + // side_length divides width and height in side_length equal parts + + // convert data from linear to morton chunks + // need to create the vector with nones explicitly because T is not copyable + let mut backing_data: Vec> = Vec::with_capacity(width * height); + for _ in 0..width * height { + backing_data.push(None); + } + for (idx, element) in data.into_iter().enumerate() { + // calculate x and y coördinate of element + let x = idx % width; + let y = idx / width; + // which location should be assigned? + let start_index = (y / side_length) * side_length * width + (x / side_length) * side_length; + let morton_idx = interleave_morton((x % side_length) as u32, (y % side_length) as u32) as usize; + println!("x: {}, y: {}, start_index: {}, morton_idx: {}", x, y, start_index, morton_idx); + backing_data[start_index + morton_idx] = Some(element); + } + // make backing data of type T instead of Option + let mut backing_data: Vec = backing_data + .into_iter() + .map(|element| element.unwrap()) + .collect(); + // split morton chunks for easy iteration + let mut morton_chunks: Vec> = backing_data + .chunks_mut(side_length * side_length) + .map(|morton_chunk| MortonChunk::new(morton_chunk, side_length)) + .collect(); + assert!(morton_chunks.len() == (width / side_length) * (height / side_length)); + Morton { + morton_chunks: morton_chunks, + width: width, + height: height, + side_length: side_length, + } + } +} + + // http://graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN #[inline] pub fn interleave_morton(x: u32, y: u32) -> u32 { diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..50c6fc4 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,6 @@ +extern crate morton; +use morton::Morton; + +fn main() { + let morton32 = Morton::new(4, 8, vec![0; 32]); +} \ No newline at end of file From 0b13b30b105faf14509aba0b1c164f7d8774a6d4 Mon Sep 17 00:00:00 2001 From: Reinier Maas Date: Wed, 1 Feb 2017 15:29:31 +0100 Subject: [PATCH 2/9] WIP: iterator building --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index fb3c085..4886fcf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ pub struct Morton<'m, T: 'm> { } impl<'m, T> Morton<'m, T> { - pub fn new(width: usize, height: usize, data: &mut Vec) -> Morton<'m, T> { + pub fn new(width: usize, height: usize, mut data: Vec) -> Morton<'m, T> { assert!(data.len() == width * height); // greatest common single digit diviser let mut side_length = 1; From d5ce852b0fdf50db0e4409074285e236bedcd43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Wed, 1 Feb 2017 15:58:13 +0100 Subject: [PATCH 3/9] Make things compile --- src/lib.rs | 15 ++++++--------- src/main.rs | 3 ++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4886fcf..5467774 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ pub struct Morton<'m, T: 'm> { } impl<'m, T> Morton<'m, T> { - pub fn new(width: usize, height: usize, mut data: Vec) -> Morton<'m, T> { + pub fn new(width: usize, height: usize, data: Vec, backing_data: &'m mut Vec) -> Morton<'m, T> { assert!(data.len() == width * height); // greatest common single digit diviser let mut side_length = 1; @@ -47,9 +47,9 @@ impl<'m, T> Morton<'m, T> { // convert data from linear to morton chunks // need to create the vector with nones explicitly because T is not copyable - let mut backing_data: Vec> = Vec::with_capacity(width * height); + let mut backing_data_opt: Vec> = Vec::with_capacity(width * height); for _ in 0..width * height { - backing_data.push(None); + backing_data_opt.push(None); } for (idx, element) in data.into_iter().enumerate() { // calculate x and y coördinate of element @@ -59,15 +59,12 @@ impl<'m, T> Morton<'m, T> { let start_index = (y / side_length) * side_length * width + (x / side_length) * side_length; let morton_idx = interleave_morton((x % side_length) as u32, (y % side_length) as u32) as usize; println!("x: {}, y: {}, start_index: {}, morton_idx: {}", x, y, start_index, morton_idx); - backing_data[start_index + morton_idx] = Some(element); + backing_data_opt[start_index + morton_idx] = Some(element); } // make backing data of type T instead of Option - let mut backing_data: Vec = backing_data - .into_iter() - .map(|element| element.unwrap()) - .collect(); + backing_data.extend(backing_data_opt.into_iter().map(|element| element.unwrap())); // split morton chunks for easy iteration - let mut morton_chunks: Vec> = backing_data + let mut morton_chunks: Vec> = backing_data .chunks_mut(side_length * side_length) .map(|morton_chunk| MortonChunk::new(morton_chunk, side_length)) .collect(); diff --git a/src/main.rs b/src/main.rs index 50c6fc4..a5bbcb9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,5 +2,6 @@ extern crate morton; use morton::Morton; fn main() { - let morton32 = Morton::new(4, 8, vec![0; 32]); + let mut backing_data = Vec::new(); + let morton32 = Morton::new(4, 8, vec![0; 32], &mut backing_data); } \ No newline at end of file From 28db91dd8779b57d75d4018c07be45bc8f9d32c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Ochagav=C3=ADa?= Date: Wed, 1 Feb 2017 16:07:15 +0100 Subject: [PATCH 4/9] Clear backing_data before extending it --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 5467774..579ad95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,7 @@ impl<'m, T> Morton<'m, T> { backing_data_opt[start_index + morton_idx] = Some(element); } // make backing data of type T instead of Option + backing_data.clear(); backing_data.extend(backing_data_opt.into_iter().map(|element| element.unwrap())); // split morton chunks for easy iteration let mut morton_chunks: Vec> = backing_data From e08994e5587ce04ba5a9decc69ebf215ed434f24 Mon Sep 17 00:00:00 2001 From: Reinier Maas Date: Wed, 1 Feb 2017 16:18:54 +0100 Subject: [PATCH 5/9] add travis --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..fb8032e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: rust +rust: + - stable + - beta + - nightly \ No newline at end of file From b74f2fa3e1559995fa5dc33e4ed1c54de21bf8af Mon Sep 17 00:00:00 2001 From: Reinier Maas Date: Wed, 1 Feb 2017 17:20:35 +0100 Subject: [PATCH 6/9] improved the interface to only require the user to provide the data that is inserted in the morton structure --- src/lib.rs | 26 ++++++++++++++++++-------- src/main.rs | 10 ++++++++-- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 579ad95..2e16558 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #[cfg(test)] extern crate rand; #[cfg(test)] extern crate test; +#[derive(Debug)] pub struct MortonChunk<'m, T: 'm> { morton_chunk: &'m mut [T], side_length: usize, @@ -17,7 +18,10 @@ impl<'m, T> MortonChunk<'m, T> { } } } + +#[derive(Debug)] pub struct Morton<'m, T: 'm> { + backing_data: std::cell::UnsafeCell>, // holds the data that is used by morton chunks morton_chunks: Vec>, width: usize, height: usize, @@ -25,7 +29,7 @@ pub struct Morton<'m, T: 'm> { } impl<'m, T> Morton<'m, T> { - pub fn new(width: usize, height: usize, data: Vec, backing_data: &'m mut Vec) -> Morton<'m, T> { + pub fn new(width: usize, height: usize, data: Vec) -> Morton<'m, T> { assert!(data.len() == width * height); // greatest common single digit diviser let mut side_length = 1; @@ -62,15 +66,21 @@ impl<'m, T> Morton<'m, T> { backing_data_opt[start_index + morton_idx] = Some(element); } // make backing data of type T instead of Option - backing_data.clear(); - backing_data.extend(backing_data_opt.into_iter().map(|element| element.unwrap())); - // split morton chunks for easy iteration - let mut morton_chunks: Vec> = backing_data - .chunks_mut(side_length * side_length) - .map(|morton_chunk| MortonChunk::new(morton_chunk, side_length)) - .collect(); + // backing data needs to be saved with the morton struct while the mut references are used by the chunks + let mut backing_data: std::cell::UnsafeCell> = std::cell::UnsafeCell::new(Vec::with_capacity(width * height)); + let mut morton_chunks: Vec> = Vec::with_capacity((width / side_length) * (height / side_length)); + unsafe{ + let ref mut backing_data = *backing_data.get(); + backing_data.extend(backing_data_opt.into_iter().map(|element| element.unwrap())); + // split morton chunks for easy iteration + morton_chunks = backing_data + .chunks_mut(side_length * side_length) + .map(|morton_chunk| MortonChunk::new(morton_chunk, side_length)) + .collect(); + } assert!(morton_chunks.len() == (width / side_length) * (height / side_length)); Morton { + backing_data: backing_data, morton_chunks: morton_chunks, width: width, height: height, diff --git a/src/main.rs b/src/main.rs index a5bbcb9..29122f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,12 @@ extern crate morton; use morton::Morton; fn main() { - let mut backing_data = Vec::new(); - let morton32 = Morton::new(4, 8, vec![0; 32], &mut backing_data); + let mut vector = Vec::with_capacity(8 * 4); + for y in 0..8 { + for x in 0..4 { + vector.push((x,y)); + } + } + let morton4_1x2 = Morton::new(4, 8, vector); + println!("{:?}", morton4_1x2); } \ No newline at end of file From f0c79d8d95d5e1b985fbf569aef04b2f51f9c026 Mon Sep 17 00:00:00 2001 From: Reinier Maas Date: Mon, 6 Feb 2017 19:26:52 +0100 Subject: [PATCH 7/9] WIP: iterator implementation --- src/lib.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 2e16558..85c9705 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,25 @@ impl<'m, T> MortonChunk<'m, T> { } } +#[derive(Debug)] +pub struct MortonChunkIterator<'m, T: 'm> { + morton_chunk: &'m MortonChunk<'m, T>, + morton_index: usize, +} + +impl<'m, T> Iterator for MortonChunkIterator<'m, T> { + type Item = &'m T; + fn next(&mut self) -> Option { + let result = if self.morton_index < self.morton_chunk.morton_chunk.len() { + Some(&self.morton_chunk.morton_chunk[self.morton_index]) + } else { + None + }; + self.morton_index += 1; + result + } +} + #[derive(Debug)] pub struct Morton<'m, T: 'm> { backing_data: std::cell::UnsafeCell>, // holds the data that is used by morton chunks @@ -89,6 +108,25 @@ impl<'m, T> Morton<'m, T> { } } +#[derive(Debug)] +pub struct MortonIterator<'m, T: 'm> { + morton_chunk: &'m Morton<'m, T>, + morton_index: usize, +} + +impl<'m, T> Iterator for MortonIterator<'m, T> { + type Item = &'m T; + fn next(&mut self) -> Option { + let result = if self.morton_index < self.morton_chunk.morton_chunk.len() { + Some(&self.morton_chunk.morton_chunk[self.morton_index]) + } else { + None + }; + self.morton_index += 1; + result + } +} + // http://graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN #[inline] From 7ab7699b5466f4815165aa65517c27aae0109b04 Mon Sep 17 00:00:00 2001 From: Reinier Maas Date: Mon, 6 Feb 2017 21:03:45 +0100 Subject: [PATCH 8/9] data structure for iterator --- src/lib.rs | 119 ++++++++++++++++++++++++++++------------------------- 1 file changed, 62 insertions(+), 57 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2bdf477..4338d31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,37 +6,39 @@ #[derive(Debug)] pub struct MortonChunk<'m, T: 'm> { morton_chunk: &'m mut [T], - side_length: usize, + x: usize, + y: usize, } impl<'m, T> MortonChunk<'m, T> { - pub fn new(morton_chunk: &mut [T], side_length: usize) -> MortonChunk { - assert!(morton_chunk.len() == side_length * side_length); + pub fn new(morton_chunk: &mut [T], x: usize, y: usize) -> MortonChunk { + assert!(morton_chunk.len() == (((morton_chunk.len() as f64).sqrt() as usize) as f64).powi(2) as usize); MortonChunk { morton_chunk: morton_chunk, - side_length: side_length, + x: x, + y: y, } } } -#[derive(Debug)] -pub struct MortonChunkIterator<'m, T: 'm> { - morton_chunk: &'m MortonChunk<'m, T>, - morton_index: usize, -} - -impl<'m, T> Iterator for MortonChunkIterator<'m, T> { - type Item = &'m T; - fn next(&mut self) -> Option { - let result = if self.morton_index < self.morton_chunk.morton_chunk.len() { - Some(&self.morton_chunk.morton_chunk[self.morton_index]) - } else { - None - }; - self.morton_index += 1; - result - } -} +//#[derive(Debug)] +//pub struct MortonChunkIterator<'m, T: 'm> { +// morton_chunk: &'m MortonChunk<'m, T>, +// morton_index: usize, +//} +// +//impl<'m, T> Iterator for MortonChunkIterator<'m, T> { +// type Item = &'m T; +// fn next(&mut self) -> Option { +// let result = if self.morton_index < self.morton_chunk.morton_chunk.len() { +// Some(&self.morton_chunk.morton_chunk[self.morton_index]) +// } else { +// None +// }; +// self.morton_index += 1; +// result +// } +//} #[derive(Debug)] pub struct Morton<'m, T: 'm> { @@ -44,29 +46,29 @@ pub struct Morton<'m, T: 'm> { morton_chunks: Vec>, width: usize, height: usize, - side_length: usize, + morton_side_length: usize, } impl<'m, T> Morton<'m, T> { pub fn new(width: usize, height: usize, data: Vec) -> Morton<'m, T> { assert!(data.len() == width * height); // greatest common single digit diviser - let mut side_length = 1; + let mut morton_side_length = 1; { let mut width = width; let mut height = height; while { width >>= 1; height >>= 1; - width > 0 && height > 0 - } { side_length <<= 1; } - // side_length is minimum of both most significant bits - // side_length is now an upper bound of the binary gcd + width > 0 && height > 0 && morton_side_length <= (std::u16::MAX as usize) // To make sure something % morton_side_length fits in an u16 + } { morton_side_length <<= 1; } + // morton_side_length is minimum of both most significant bits + // morton_side_length is now an upper bound of the binary gcd } - while (width / side_length) * side_length < width || (height / side_length) * side_length < height { - side_length >>= 1; + while (width / morton_side_length) * morton_side_length < width || (height / morton_side_length) * morton_side_length < height { + morton_side_length >>= 1; } - // side_length divides width and height in side_length equal parts + // morton_side_length divides width and height in morton_side_length equal parts // convert data from linear to morton chunks // need to create the vector with nones explicitly because T is not copyable @@ -79,53 +81,56 @@ impl<'m, T> Morton<'m, T> { let x = idx % width; let y = idx / width; // which location should be assigned? - let start_index = (y / side_length) * side_length * width + (x / side_length) * side_length; - let morton_idx = interleave_morton((x % side_length) as u32, (y % side_length) as u32) as usize; + let start_index = (y / morton_side_length) * morton_side_length * width + (x / morton_side_length) * morton_side_length; + let morton_idx = interleave_morton((x % morton_side_length) as u16, (y % morton_side_length) as u16) as usize; println!("x: {}, y: {}, start_index: {}, morton_idx: {}", x, y, start_index, morton_idx); backing_data_opt[start_index + morton_idx] = Some(element); } // make backing data of type T instead of Option // backing data needs to be saved with the morton struct while the mut references are used by the chunks - let mut backing_data: std::cell::UnsafeCell> = std::cell::UnsafeCell::new(Vec::with_capacity(width * height)); - let mut morton_chunks: Vec> = Vec::with_capacity((width / side_length) * (height / side_length)); + let backing_data: std::cell::UnsafeCell> = std::cell::UnsafeCell::new(Vec::with_capacity(width * height)); + let morton_chunks: Vec>; unsafe{ let ref mut backing_data = *backing_data.get(); backing_data.extend(backing_data_opt.into_iter().map(|element| element.unwrap())); // split morton chunks for easy iteration + let morton_width = width / morton_side_length; + morton_chunks = backing_data - .chunks_mut(side_length * side_length) - .map(|morton_chunk| MortonChunk::new(morton_chunk, side_length)) + .chunks_mut(morton_side_length * morton_side_length) + .enumerate() + .map(|(morton_idx, morton_chunk)| MortonChunk::new(morton_chunk, morton_idx % morton_width, morton_idx / morton_width)) .collect(); } - assert!(morton_chunks.len() == (width / side_length) * (height / side_length)); + assert!(morton_chunks.len() == (width / morton_side_length) * (height / morton_side_length)); Morton { backing_data: backing_data, morton_chunks: morton_chunks, width: width, height: height, - side_length: side_length, + morton_side_length: morton_side_length, } } } -#[derive(Debug)] -pub struct MortonIterator<'m, T: 'm> { - morton_chunk: &'m Morton<'m, T>, - morton_index: usize, -} - -impl<'m, T> Iterator for MortonIterator<'m, T> { - type Item = &'m T; - fn next(&mut self) -> Option { - let result = if self.morton_index < self.morton_chunk.morton_chunk.len() { - Some(&self.morton_chunk.morton_chunk[self.morton_index]) - } else { - None - }; - self.morton_index += 1; - result - } -} +//#[derive(Debug)] +//pub struct MortonIterator<'m, T: 'm> { +// morton_chunk: &'m Morton<'m, T>, +// morton_index: usize, +//} +// +//impl<'m, T> Iterator for MortonIterator<'m, T> { +// type Item = &'m T; +// fn next(&mut self) -> Option { +// let result = if self.morton_index < self.morton_chunk.morton_chunk.len() { +// Some(&self.morton_chunk.morton_chunk[self.morton_index]) +// } else { +// None +// }; +// self.morton_index += 1; +// result +// } +//} // http://graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN From 728ecbe09a2cf49a7d8de3211dceefea6508612c Mon Sep 17 00:00:00 2001 From: Reinier Maas Date: Thu, 2 Mar 2017 22:34:22 +0100 Subject: [PATCH 9/9] fix travis --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fb8032e..333888d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,8 @@ language: rust rust: - stable - beta - - nightly \ No newline at end of file + - nightly +matrix: + allow_failures: + - rust: stable + - rust: beta \ No newline at end of file