From 38e25eae4fcb5c985435ae36973900e37af490eb Mon Sep 17 00:00:00 2001
From: James Miller <james@aatch.net>
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<T> 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<T> {
+    Own(~[T]),
+    Static(&'static [T])
+}
+
+impl<T> VecRef<T> {
+    /**
+     * Construct a VecRef from an owned vector
+     */
+    pub fn from_owned(val: ~[T]) -> VecRef<T> {
+        Own(val)
+    }
+
+    /**
+     * Construct a VecRef from a static vector
+     */
+    pub fn from_static(val: &'static [T]) -> VecRef<T> {
+        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<U>(&self, f: &fn(*T, uint) -> U) -> U {
+        self.as_slice().as_imm_buf(f)
+    }
+}
+
+impl<T:Copy> VecRef<T> {
+
+    /**
+     * 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<T> Vector<T> for VecRef<T> {
+    #[inline(always)]
+    fn as_slice<'a>(&'a self) -> &'a [T] {
+        match *self {
+            Own(ref v) => v.as_slice(),
+            Static(slice) => slice
+        }
+    }
+}
+
+impl<T> Container for VecRef<T> {
+    #[inline]
+    fn is_empty(&self) -> bool {
+        self.as_slice().is_empty()
+    }
+
+    #[inline]
+    fn len(&self) -> uint {
+        self.as_slice().len()
+    }
+}
+
+impl<T:Copy> CopyableVector<T> for VecRef<T> {
+    #[inline]
+    fn to_owned(&self) -> ~[T] {
+        self.as_slice().to_owned()
+    }
+}
+
+impl<T:Eq> ImmutableEqVector<T> for VecRef<T> {
+    #[inline]
+    fn position_elem(&self, x: &T) -> Option<uint> {
+        self.as_slice().position_elem(x)
+    }
+
+    #[inline]
+    fn rposition_elem(&self, t: &T) -> Option<uint> {
+        self.as_slice().rposition(t)
+    }
+
+    #[inline]
+    fn contains(&self, x: &T) -> bool {
+        self.as_slice().contains(x)
+    }
+}
+
+impl<T: TotalOrd> ImmutableTotalOrdVector<T> for VecRef<T> {
+    #[inline]
+    fn bsearch_elem(&self, x: &T) -> Option<uint> {
+        self.as_slice().bsearch_elem(x)
+    }
+}
+
+impl<T:Copy> ImmutableCopyableVector<T> for VecRef<T> {
+    #[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<T:Copy> Index<uint, T> for VecRef<T> {
+    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<A, T: Iterator<A>> FromIterator<A, T> for ~[A] {
     }
 }
 
+#[cfg(stage0)]
+impl<A, T: Iterator<A>> FromIterator<A, T> for VecRef<A> {
+    pub fn from_iterator(iterator: &mut T) -> VecRef<A> {
+        let mut xs = ~[];
+        for iterator.advance |x| {
+            xs.push(x);
+        }
+        VecRef::from_owned(xs)
+    }
+}
+
+
+#[cfg(not(stage0))]
+impl<A, T: Iterator<A>> FromIterator<A, T> for VecRef<A> {
+    pub fn from_iterator(iterator: &mut T) -> VecRef<A> {
+        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<int> = VecRef::from_owned(~[]);
+        assert!(v.is_empty());
+
+        let v = VecRef::from_owned(~[1, 2, 3]);
+        assert_eq!(v.len(), 3);
+
+        let v : VecRef<int> = VecRef::from_static([]);
+        assert!(v.is_empty());
+
+        let v : VecRef<int> = 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 <james@aatch.net>
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<u8>
+}
+
+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<u8> {
+        &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<T> VecRef<T> {
     // 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<U>(&self, f: &fn(*T, uint) -> U) -> U {
         self.as_slice().as_imm_buf(f)
     }
@@ -1809,7 +1810,7 @@ impl<T:Copy> VecRef<T> {
     /**
      * 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<T:Eq> ImmutableEqVector<T> for VecRef<T> {
 
     #[inline]
     fn rposition_elem(&self, t: &T) -> Option<uint> {
-        self.as_slice().rposition(t)
+        self.as_slice().rposition_elem(t)
     }
 
     #[inline]
@@ -1887,8 +1888,8 @@ impl<T:Copy> ImmutableCopyableVector<T> for VecRef<T> {
 }
 
 impl<T:Copy> Index<uint, T> for VecRef<T> {
-    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<int> = VecRef::from_static([]);
+        let v : VecRef<int> = VecRef::from_static(&[]);
         assert!(v.is_empty());
 
-        let v : VecRef<int> = VecRef::from_static([1, 2, 3, 4]);
+        let v : VecRef<int> = 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);
+    }
 }