From 38e25eae4fcb5c985435ae36973900e37af490eb Mon Sep 17 00:00:00 2001 From: James Miller Date: Fri, 5 Jul 2013 15:44:48 +1200 Subject: [PATCH 1/2] Add VecRef to std::vec This adds a `VecRef` that can hold either a ~[T] or a &'static [T] --- src/libstd/vec.rs | 216 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 1014ff48b1d23..d6e869b5ff339 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -1727,6 +1727,171 @@ impl<'self, T:Clone> MutableCloneableVector for &'self mut [T] { } } +/** + * A VecRef is a vector that can hold either an owned vector, + * ~[T] or a static slice, &'static [T]. This can be useful as + * an optimization when allocation is sometimes needed, but the + * common case is statically known. + */ +#[deriving(Eq,Ord,Clone)] +pub enum VecRef { + Own(~[T]), + Static(&'static [T]) +} + +impl VecRef { + /** + * Construct a VecRef from an owned vector + */ + pub fn from_owned(val: ~[T]) -> VecRef { + Own(val) + } + + /** + * Construct a VecRef from a static vector + */ + pub fn from_static(val: &'static [T]) -> VecRef { + Static(val) + } + + // I can't impl ImmutableVector because that has methods + // on self-by-value, which means VecRef would move into + // it. So I'm just gonna re-impl here + + #[inline] + pub fn iter<'r>(&'r self) -> VecIterator<'r, T> { + self.as_slice().iter() + } + + #[inline] + pub fn rev_iter<'r>(&'r self) -> VecRevIterator<'r, T> { + self.as_slice().rev_iter() + } + + #[inline] + pub fn split_iter<'r>(&'r self, pred: &'r fn(&T) -> bool) -> VecSplitIterator<'r, T> { + self.as_slice().split_iter(pred) + } + + #[inline] + pub fn splitn_iter<'r>(&'r self, n: uint, pred: &'r fn(&T) -> bool) -> VecSplitIterator<'r, T> { + self.as_slice().split_iter(n, pred) + } + + #[inline] + pub fn rsplit_iter<'r>(&'r self, pred: &'r fn(&T) -> bool) -> VecRSplitIterator<'r, T> { + self.as_slice().rsplit_iter(pred) + } + + #[inline] + pub fn rsplitn_iter<'r>(&'r self, pred: &'r fn(&T) -> bool) -> VecRSplitIterator<'r, T> { + self.as_slice().rsplit_iter(pred) + } + + #[inline] + pub fn window_iter<'r>(&'r self, size: uint) -> VecWindowIter<'r, T> { + self.as_slice().window_iter(size) + } + + #[inline] + pub fn chunk_iter<'r>(&'r self, size: uint) -> VecChunkIter<'r, T> { + self.as_slice().window_iter(size) + } + + #[inline] + pub fn as_imm_buf(&self, f: &fn(*T, uint) -> U) -> U { + self.as_slice().as_imm_buf(f) + } +} + +impl VecRef { + + /** + * Converts this type into a standard owned vector, consuming it in the process. + * + * If the VecRef holds a static vector, it is converted to an owned one, otherwise the held + * owned vector is returned. + */ + pub fn to_owned_consume(self) -> ~[T] { + match self { + Own(v) => v, + Static(v) => v.to_owned() + } + } + +} + +impl Vector for VecRef { + #[inline(always)] + fn as_slice<'a>(&'a self) -> &'a [T] { + match *self { + Own(ref v) => v.as_slice(), + Static(slice) => slice + } + } +} + +impl Container for VecRef { + #[inline] + fn is_empty(&self) -> bool { + self.as_slice().is_empty() + } + + #[inline] + fn len(&self) -> uint { + self.as_slice().len() + } +} + +impl CopyableVector for VecRef { + #[inline] + fn to_owned(&self) -> ~[T] { + self.as_slice().to_owned() + } +} + +impl ImmutableEqVector for VecRef { + #[inline] + fn position_elem(&self, x: &T) -> Option { + self.as_slice().position_elem(x) + } + + #[inline] + fn rposition_elem(&self, t: &T) -> Option { + self.as_slice().rposition(t) + } + + #[inline] + fn contains(&self, x: &T) -> bool { + self.as_slice().contains(x) + } +} + +impl ImmutableTotalOrdVector for VecRef { + #[inline] + fn bsearch_elem(&self, x: &T) -> Option { + self.as_slice().bsearch_elem(x) + } +} + +impl ImmutableCopyableVector for VecRef { + #[inline] + fn partitioned(&self, f: &fn(&T) -> bool) -> (~[T], ~[T]) { + self.as_slice().partitioned(f) + } + + #[inline] + unsafe fn unsafe_get(&self, elem: uint) -> T { + self.as_slice().unsafe_get(elem) + } +} + +impl Index for VecRef { + fn index(&self, index: uint) -> T { + copy self.as_slice()[index] + } +} + /** * Constructs a vector from an unsafe pointer to a buffer * @@ -2140,6 +2305,31 @@ impl> FromIterator for ~[A] { } } +#[cfg(stage0)] +impl> FromIterator for VecRef { + pub fn from_iterator(iterator: &mut T) -> VecRef { + let mut xs = ~[]; + for iterator.advance |x| { + xs.push(x); + } + VecRef::from_owned(xs) + } +} + + +#[cfg(not(stage0))] +impl> FromIterator for VecRef { + pub fn from_iterator(iterator: &mut T) -> VecRef { + let (lower, _) = iterator.size_hint(); + let mut xs = with_capacity(lower.get_or_zero()); + for iterator.advance |x| { + xs.push(x); + } + VecRef::from_owned(xs) + } +} + + #[cfg(test)] mod tests { @@ -3244,4 +3434,30 @@ mod tests { values.mut_slice(2,4).set_memory(0xFF); assert_eq!(values, [0xAB, 0xAB, 0xFF, 0xFF, 0xAB]); } + + #[test] + fn test_vec_ref() { + let v : VecRef = VecRef::from_owned(~[]); + assert!(v.is_empty()); + + let v = VecRef::from_owned(~[1, 2, 3]); + assert_eq!(v.len(), 3); + + let v : VecRef = VecRef::from_static([]); + assert!(v.is_empty()); + + let v : VecRef = VecRef::from_static([1, 2, 3, 4]); + assert_eq!(v.len(), 4); + } + + #[test] + fn test_vec_ref_consume() { + let v = VecRef::from_owned(~[1, 2, 3, 4]); + let vec = v.to_owned_consume(); + assert_eq!(vec, ~[1, 2, 3, 4]); + + let v = VecRef::from_static([1, 2, 3, 4]); + let vec = v.to_owned_consume(); + assert_eq!(vec, ~[1, 2, 3, 4]); + } } From 41029c91b8897d2fd17df14e183b15149f373c88 Mon Sep 17 00:00:00 2001 From: James Miller Date: Fri, 5 Jul 2013 18:16:59 +1200 Subject: [PATCH 2/2] Implement a StringRef This is the string equivalent of VecRef. I had some trouble with lifetimes trying to implement StrSlice, so I've left it for now, iterating on strings isn't as common and the .as_slice() method merely means you need to add an extra method call. --- src/libstd/str.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++++- src/libstd/vec.rs | 54 +++++++++++++++++----------- 2 files changed, 122 insertions(+), 21 deletions(-) diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 564c58f7097ee..fa23a4068c1ea 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -34,7 +34,7 @@ use ptr::RawPtr; use to_str::ToStr; use uint; use vec; -use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector}; +use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, Vector}; /* Section: Conditions @@ -2238,6 +2238,82 @@ impl OwnedStr for ~str { } } +/** + * A StringRef is a string that can hold either a ~str or a &'static str. + * This can be useful as an optimization when an allocation is sometimes + * needed but the common case is statically known. + */ +#[deriving(Eq,Ord,Clone)] +pub struct StringRef { + priv r: ::vec::VecRef +} + +impl StringRef { + + /** + * Constructs a StringRef from an owned string + */ + #[inline] + pub fn from_owned(s: ~str) -> StringRef { + StringRef { + r: ::vec::VecRef::from_owned(s.as_bytes_with_null_consume()) + } + } + + /** + * Constructs a StringRef from a static string + */ + #[inline] + pub fn from_static(s: &'static str) -> StringRef { + unsafe { + StringRef { + r: ::vec::VecRef::from_static(::cast::transmute(s)) + } + } + } + + /** + * Converts this type into a standard owned string, consuming it in the process. + * + * If the StringRef holds a static string, it is copied to an owned one, otherwise the held + * owned vector is returned + */ + #[inline] + pub fn to_owned_consume(self) -> ~str { + unsafe { + ::cast::transmute(self.r.to_owned_consume()) + } + } + + /** + * Returns the backing VecRef for this StringRef + */ + #[inline] + pub fn as_vec_ref<'r>(&'r self) -> &'r vec::VecRef { + &self.r + } +} + +impl Str for StringRef { + #[inline(always)] + pub fn as_slice<'r>(&'r self) -> &'r str { + unsafe { + ::cast::transmute(self.r.as_slice()) + } + } +} + +impl Container for StringRef { + #[inline] + fn len(&self) -> uint { + self.as_slice().len() + } + #[inline] + fn is_empty(&self) -> bool { + self.len() == 0 + } +} + impl Clone for ~str { #[inline] fn clone(&self) -> ~str { @@ -3448,4 +3524,15 @@ mod tests { t::<@str>(); t::<~str>(); } + + #[test] + fn test_str_ref() { + let r = StringRef::from_static("abcde"); + assert_eq!(r.len(), 5); + assert_eq!(r.as_slice(), "abcde") + + let r = StringRef::from_owned(~"abcde"); + assert_eq!(r.len(), 5); + assert_eq!(r.as_slice(), "abcde") + } } diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index d6e869b5ff339..0848ec1e9bbe9 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -17,6 +17,7 @@ use cast; use container::{Container, Mutable}; use cmp; use cmp::{Eq, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; +use ops::Index; use clone::Clone; use iterator::{FromIterator, Iterator, IteratorUtil}; use kinds::Copy; @@ -1758,47 +1759,47 @@ impl VecRef { // on self-by-value, which means VecRef would move into // it. So I'm just gonna re-impl here - #[inline] + #[inline] #[allow(missing_doc)] pub fn iter<'r>(&'r self) -> VecIterator<'r, T> { self.as_slice().iter() } - #[inline] + #[inline] #[allow(missing_doc)] pub fn rev_iter<'r>(&'r self) -> VecRevIterator<'r, T> { self.as_slice().rev_iter() } - #[inline] + #[inline] #[allow(missing_doc)] pub fn split_iter<'r>(&'r self, pred: &'r fn(&T) -> bool) -> VecSplitIterator<'r, T> { self.as_slice().split_iter(pred) } - #[inline] + #[inline] #[allow(missing_doc)] pub fn splitn_iter<'r>(&'r self, n: uint, pred: &'r fn(&T) -> bool) -> VecSplitIterator<'r, T> { - self.as_slice().split_iter(n, pred) + self.as_slice().splitn_iter(n, pred) } - #[inline] + #[inline] #[allow(missing_doc)] pub fn rsplit_iter<'r>(&'r self, pred: &'r fn(&T) -> bool) -> VecRSplitIterator<'r, T> { self.as_slice().rsplit_iter(pred) } - #[inline] - pub fn rsplitn_iter<'r>(&'r self, pred: &'r fn(&T) -> bool) -> VecRSplitIterator<'r, T> { - self.as_slice().rsplit_iter(pred) + #[inline] #[allow(missing_doc)] + pub fn rsplitn_iter<'r>(&'r self, n: uint, pred: &'r fn(&T) -> bool) -> VecRSplitIterator<'r, T> { + self.as_slice().rsplitn_iter(n, pred) } - #[inline] + #[inline] #[allow(missing_doc)] pub fn window_iter<'r>(&'r self, size: uint) -> VecWindowIter<'r, T> { self.as_slice().window_iter(size) } - #[inline] + #[inline] #[allow(missing_doc)] pub fn chunk_iter<'r>(&'r self, size: uint) -> VecChunkIter<'r, T> { - self.as_slice().window_iter(size) + self.as_slice().chunk_iter(size) } - #[inline] + #[inline] #[allow(missing_doc)] pub fn as_imm_buf(&self, f: &fn(*T, uint) -> U) -> U { self.as_slice().as_imm_buf(f) } @@ -1809,7 +1810,7 @@ impl VecRef { /** * Converts this type into a standard owned vector, consuming it in the process. * - * If the VecRef holds a static vector, it is converted to an owned one, otherwise the held + * If the VecRef holds a static vector, it is copied to an owned one, otherwise the held * owned vector is returned. */ pub fn to_owned_consume(self) -> ~[T] { @@ -1858,7 +1859,7 @@ impl ImmutableEqVector for VecRef { #[inline] fn rposition_elem(&self, t: &T) -> Option { - self.as_slice().rposition(t) + self.as_slice().rposition_elem(t) } #[inline] @@ -1887,8 +1888,8 @@ impl ImmutableCopyableVector for VecRef { } impl Index for VecRef { - fn index(&self, index: uint) -> T { - copy self.as_slice()[index] + fn index(&self, index: &uint) -> T { + copy self.as_slice()[*index] } } @@ -3443,10 +3444,10 @@ mod tests { let v = VecRef::from_owned(~[1, 2, 3]); assert_eq!(v.len(), 3); - let v : VecRef = VecRef::from_static([]); + let v : VecRef = VecRef::from_static(&[]); assert!(v.is_empty()); - let v : VecRef = VecRef::from_static([1, 2, 3, 4]); + let v : VecRef = VecRef::from_static(&[1, 2, 3, 4]); assert_eq!(v.len(), 4); } @@ -3456,8 +3457,21 @@ mod tests { let vec = v.to_owned_consume(); assert_eq!(vec, ~[1, 2, 3, 4]); - let v = VecRef::from_static([1, 2, 3, 4]); + let v = VecRef::from_static(&[1, 2, 3, 4]); let vec = v.to_owned_consume(); assert_eq!(vec, ~[1, 2, 3, 4]); } + + #[test] + fn test_vec_iter() { + let v = VecRef::from_static(&[1, 2, 3, 4]); + + let mut iter = v.iter().transform(|&x| x); + + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.next(), None); + } }