Skip to content

Add a StringRef and a VecRef #7599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 88 additions & 1 deletion src/libstd/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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")
}
}
230 changes: 230 additions & 0 deletions src/libstd/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1727,6 +1728,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] #[allow(missing_doc)]
pub fn iter<'r>(&'r self) -> VecIterator<'r, T> {
self.as_slice().iter()
}

#[inline] #[allow(missing_doc)]
pub fn rev_iter<'r>(&'r self) -> VecRevIterator<'r, T> {
self.as_slice().rev_iter()
}

#[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] #[allow(missing_doc)]
pub fn splitn_iter<'r>(&'r self, n: uint, pred: &'r fn(&T) -> bool) -> VecSplitIterator<'r, T> {
self.as_slice().splitn_iter(n, pred)
}

#[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] #[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] #[allow(missing_doc)]
pub fn window_iter<'r>(&'r self, size: uint) -> VecWindowIter<'r, T> {
self.as_slice().window_iter(size)
}

#[inline] #[allow(missing_doc)]
pub fn chunk_iter<'r>(&'r self, size: uint) -> VecChunkIter<'r, T> {
self.as_slice().chunk_iter(size)
}

#[inline] #[allow(missing_doc)]
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 copied 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_elem(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
*
Expand Down Expand Up @@ -2140,6 +2306,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 {
Expand Down Expand Up @@ -3244,4 +3435,43 @@ 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]);
}

#[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);
}
}