#![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(feature = "bench", feature(test))]
extern crate ref_slice;
use std::{mem, slice};
use self::NTreeVariant::{Branch, Bucket};
#[cfg(test)]
mod test;
pub trait Region<P>: Clone {
fn contains(&self, &P) -> bool;
fn split(&self) -> Vec<Self>;
fn overlaps(&self, other: &Self) -> bool;
}
pub struct NTree<R, P> {
region: R,
kind: NTreeVariant<R, P>
}
enum NTreeVariant<R, P> {
Bucket {
points: Vec<P>,
bucket_limit: u8
},
Branch {
subregions: Vec<NTree<R, P>>
}
}
impl<P, R: Region<P>> NTree<R, P> {
pub fn new(region: R, size: u8) -> NTree<R, P> {
NTree {
kind: Branch {
subregions: region
.split()
.into_iter()
.map(|r| NTree {
region: r,
kind: Bucket { points: vec![], bucket_limit: size }
})
.collect(),
},
region: region
}
}
pub fn insert(&mut self, point: P) -> bool {
if !self.region.contains(&point) { return false }
match self.kind {
Bucket { ref mut points, ref bucket_limit } => {
if points.len() as u8 != *bucket_limit {
points.push(point);
return true
}
},
Branch { ref mut subregions } => {
match subregions.iter_mut().find(|r| r.contains(&point)) {
Some(ref mut subregion) => return subregion.insert(point),
None => return false
}
}
};
split_and_insert(self, point);
true
}
pub fn range_query<'t, 'q>(&'t self, query: &'q R) -> RangeQuery<'t, 'q, R, P> {
RangeQuery {
query: query,
points: (&[]).iter(),
stack: vec![ref_slice::ref_slice(self).iter()],
}
}
pub fn contains(&self, point: &P) -> bool {
self.region.contains(point)
}
pub fn nearby<'a>(&'a self, point: &P) -> Option<&'a[P]> {
if self.region.contains(point) {
match self.kind {
Bucket { ref points, .. } => Some(points.as_slice()),
Branch { ref subregions } => {
subregions
.iter()
.find(|r| r.contains(point))
.and_then(|r| r.nearby(point))
}
}
} else {
None
}
}
}
fn split_and_insert<P, R: Region<P>>(bucket: &mut NTree<R, P>, point: P) {
let old_points;
let old_bucket_limit;
match bucket.kind {
Bucket { ref mut points, bucket_limit } => {
old_points = mem::replace(points, vec![]);
old_bucket_limit = bucket_limit;
},
Branch { .. } => unreachable!()
}
*bucket = NTree::new(bucket.region.clone(), old_bucket_limit);
for old_point in old_points.into_iter() {
bucket.insert(old_point);
}
bucket.insert(point);
}
pub struct RangeQuery<'t,'q, R: 'q + 't, P: 't> {
query: &'q R,
points: slice::Iter<'t, P>,
stack: Vec<slice::Iter<'t, NTree<R, P>>>
}
impl<'t, 'q, R: Region<P>, P> Iterator for RangeQuery<'t, 'q, R, P> {
type Item = &'t P;
fn next(&mut self) -> Option<&'t P> {
'outer: loop {
for p in &mut self.points {
if self.query.contains(p) {
return Some(p)
}
}
'region_search: loop {
let mut children_iter = match self.stack.pop() {
Some(x) => x,
None => return None,
};
'children: loop {
match children_iter.next() {
None => continue 'region_search,
Some(value) => {
if value.region.overlaps(self.query) {
self.stack.push(children_iter);
match value.kind {
Bucket { ref points, .. } => {
self.points = points.iter();
continue 'outer;
}
Branch { ref subregions } => children_iter = subregions.iter()
}
}
}
}
}
}
}
}
}