diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 29ed87f2202..5b12e8b8eb1 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -31,6 +31,7 @@ pub mod util { pub mod interner; #[cfg(test)] pub mod parser_testing; + pub mod small_vector; } pub mod syntax { diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs new file mode 100644 index 00000000000..c6b223f7c15 --- /dev/null +++ b/src/libsyntax/util/small_vector.rs @@ -0,0 +1,213 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +use std::vec::MoveIterator; +use std::util; + +/// A vector type optimized for cases where the size is almost always 0 or 1 +pub enum SmallVector<T> { + priv Zero, + priv One(T), + priv Many(~[T]), +} + +impl<T> Container for SmallVector<T> { + fn len(&self) -> uint { + match *self { + Zero => 0, + One(*) => 1, + Many(ref vals) => vals.len() + } + } +} + +impl<T> FromIterator<T> for SmallVector<T> { + fn from_iterator<I: Iterator<T>>(iter: &mut I) -> SmallVector<T> { + let mut v = Zero; + for val in *iter { + v.push(val); + } + v + } +} + +impl<T> SmallVector<T> { + pub fn zero() -> SmallVector<T> { + Zero + } + + pub fn one(v: T) -> SmallVector<T> { + One(v) + } + + pub fn many(vs: ~[T]) -> SmallVector<T> { + Many(vs) + } + + pub fn push(&mut self, v: T) { + match *self { + Zero => *self = One(v), + One(*) => { + let mut tmp = Many(~[]); + util::swap(self, &mut tmp); + match *self { + Many(ref mut vs) => { + match tmp { + One(v1) => { + vs.push(v1); + vs.push(v); + } + _ => unreachable!() + } + } + _ => unreachable!() + } + } + Many(ref mut vs) => vs.push(v) + } + } + + pub fn get<'a>(&'a self, idx: uint) -> &'a T { + match *self { + One(ref v) if idx == 0 => v, + Many(ref vs) => &vs[idx], + _ => fail!("Out of bounds access") + } + } + + pub fn iter<'a>(&'a self) -> SmallVectorIterator<'a, T> { + SmallVectorIterator { + vec: self, + idx: 0 + } + } + + pub fn move_iter(self) -> SmallVectorMoveIterator<T> { + match self { + Zero => ZeroIterator, + One(v) => OneIterator(v), + Many(vs) => ManyIterator(vs.move_iter()) + } + } +} + +pub struct SmallVectorIterator<'vec, T> { + priv vec: &'vec SmallVector<T>, + priv idx: uint +} + +impl<'vec, T> Iterator<&'vec T> for SmallVectorIterator<'vec, T> { + fn next(&mut self) -> Option<&'vec T> { + if self.idx == self.vec.len() { + return None; + } + + self.idx += 1; + Some(self.vec.get(self.idx - 1)) + } + + fn size_hint(&self) -> (uint, Option<uint>) { + let rem = self.vec.len() - self.idx; + (rem, Some(rem)) + } +} + +pub enum SmallVectorMoveIterator<T> { + priv ZeroIterator, + priv OneIterator(T), + priv ManyIterator(MoveIterator<T>), +} + +impl<T> Iterator<T> for SmallVectorMoveIterator<T> { + fn next(&mut self) -> Option<T> { + match *self { + ZeroIterator => None, + OneIterator(*) => { + let mut replacement = ZeroIterator; + util::swap(self, &mut replacement); + match replacement { + OneIterator(v) => Some(v), + _ => unreachable!() + } + } + ManyIterator(ref mut inner) => inner.next() + } + } + + fn size_hint(&self) -> (uint, Option<uint>) { + match *self { + ZeroIterator => (0, Some(0)), + OneIterator(*) => (1, Some(1)), + ManyIterator(ref inner) => inner.size_hint() + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_len() { + let v: SmallVector<int> = SmallVector::zero(); + assert_eq!(0, v.len()); + + assert_eq!(1, SmallVector::one(1).len()); + assert_eq!(5, SmallVector::many(~[1, 2, 3, 4, 5]).len()); + } + + #[test] + fn test_push_get() { + let mut v = SmallVector::zero(); + v.push(1); + assert_eq!(1, v.len()); + assert_eq!(&1, v.get(0)); + v.push(2); + assert_eq!(2, v.len()); + assert_eq!(&2, v.get(1)); + v.push(3); + assert_eq!(3, v.len()); + assert_eq!(&3, v.get(2)); + } + + #[test] + fn test_from_iterator() { + let v: SmallVector<int> = (~[1, 2, 3]).move_iter().collect(); + assert_eq!(3, v.len()); + assert_eq!(&1, v.get(0)); + assert_eq!(&2, v.get(1)); + assert_eq!(&3, v.get(2)); + } + + #[test] + fn test_iter() { + let v = SmallVector::zero(); + let v: ~[&int] = v.iter().collect(); + assert_eq!(~[], v); + + let v = SmallVector::one(1); + assert_eq!(~[&1], v.iter().collect()); + + let v = SmallVector::many(~[1, 2, 3]); + assert_eq!(~[&1, &2, &3], v.iter().collect()); + } + + #[test] + fn test_move_iter() { + let v = SmallVector::zero(); + let v: ~[int] = v.move_iter().collect(); + assert_eq!(~[], v); + + let v = SmallVector::one(1); + assert_eq!(~[1], v.move_iter().collect()); + + let v = SmallVector::many(~[1, 2, 3]); + assert_eq!(~[1, 2, 3], v.move_iter().collect()); + } +}