From 09f84aa8f4298489828720c048ec7f769338c0e2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 24 Nov 2013 21:18:21 -0800 Subject: [PATCH] Add SmallVector to libsyntax --- src/libsyntax/lib.rs | 1 + src/libsyntax/util/small_vector.rs | 213 +++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 src/libsyntax/util/small_vector.rs 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 or the MIT license +// , 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 { + priv Zero, + priv One(T), + priv Many(~[T]), +} + +impl Container for SmallVector { + fn len(&self) -> uint { + match *self { + Zero => 0, + One(*) => 1, + Many(ref vals) => vals.len() + } + } +} + +impl FromIterator for SmallVector { + fn from_iterator>(iter: &mut I) -> SmallVector { + let mut v = Zero; + for val in *iter { + v.push(val); + } + v + } +} + +impl SmallVector { + pub fn zero() -> SmallVector { + Zero + } + + pub fn one(v: T) -> SmallVector { + One(v) + } + + pub fn many(vs: ~[T]) -> SmallVector { + 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 { + match self { + Zero => ZeroIterator, + One(v) => OneIterator(v), + Many(vs) => ManyIterator(vs.move_iter()) + } + } +} + +pub struct SmallVectorIterator<'vec, T> { + priv vec: &'vec SmallVector, + 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) { + let rem = self.vec.len() - self.idx; + (rem, Some(rem)) + } +} + +pub enum SmallVectorMoveIterator { + priv ZeroIterator, + priv OneIterator(T), + priv ManyIterator(MoveIterator), +} + +impl Iterator for SmallVectorMoveIterator { + fn next(&mut self) -> Option { + 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) { + 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 = 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 = (~[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()); + } +}