use ptr::RawPtr;
use to_str::ToStr;
use uint;
+#[cfg(stage0)]
use unstable::raw::Repr;
use vec;
use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector};
/// # Failure
///
/// Fails if invalid UTF-8
+#[cfg(stage0)]
pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str {
unsafe {
assert!(is_utf8(vector));
}
}
+/// Converts a vector to a string slice without performing any allocations.
+///
+/// Once the slice has been validated as utf-8, it is transmuted in-place and
+/// returned as a '&str' instead of a '&[u8]'
+///
+/// # Failure
+///
+/// Fails if invalid UTF-8
+#[cfg(not(stage0))]
+pub fn from_bytes_slice<'a>(v: &'a [u8]) -> &'a str {
+ assert!(is_utf8(v));
+ unsafe { cast::transmute(v) }
+}
+
impl ToStr for ~str {
#[inline]
fn to_str(&self) -> ~str { self.to_owned() }
/// # Failure
///
/// Fails if invalid UTF-8
+#[cfg(stage0)]
pub fn from_byte(b: u8) -> ~str {
assert!(b < 128u8);
unsafe { cast::transmute(~[b, 0u8]) }
}
+/// Convert a byte to a UTF-8 string
+///
+/// # Failure
+///
+/// Fails if invalid UTF-8
+#[cfg(not(stage0))]
+pub fn from_byte(b: u8) -> ~str {
+ assert!(b < 128u8);
+ unsafe { ::cast::transmute(~[b]) }
+}
+
/// Convert a char to a string
pub fn from_char(ch: char) -> ~str {
let mut buf = ~"";
impl<'self, S: Str> StrVector for &'self [S] {
/// Concatenate a vector of strings.
+ #[cfg(stage0)]
pub fn concat(&self) -> ~str {
if self.is_empty() { return ~""; }
s
}
+ /// Concatenate a vector of strings.
+ #[cfg(not(stage0))]
+ pub fn concat(&self) -> ~str {
+ if self.is_empty() { return ~""; }
+
+ let len = self.iter().transform(|s| s.as_slice().len()).sum();
+
+ let mut s = with_capacity(len);
+
+ unsafe {
+ do s.as_mut_buf |buf, _| {
+ let mut buf = buf;
+ foreach ss in self.iter() {
+ do ss.as_slice().as_imm_buf |ssbuf, sslen| {
+ ptr::copy_memory(buf, ssbuf, sslen);
+ buf = buf.offset(sslen as int);
+ }
+ }
+ }
+ raw::set_len(&mut s, len);
+ }
+ s
+ }
+
/// Concatenate a vector of strings, placing a given separator between each.
+ #[cfg(stage0)]
pub fn connect(&self, sep: &str) -> ~str {
if self.is_empty() { return ~""; }
}
s
}
+
+ /// Concatenate a vector of strings, placing a given separator between each.
+ #[cfg(not(stage0))]
+ pub fn connect(&self, sep: &str) -> ~str {
+ if self.is_empty() { return ~""; }
+
+ // concat is faster
+ if sep.is_empty() { return self.concat(); }
+
+ // this is wrong without the guarantee that `self` is non-empty
+ let len = sep.len() * (self.len() - 1)
+ + self.iter().transform(|s| s.as_slice().len()).sum();
+ let mut s = ~"";
+ let mut first = true;
+
+ s.reserve(len);
+
+ unsafe {
+ do s.as_mut_buf |buf, _| {
+ do sep.as_imm_buf |sepbuf, seplen| {
+ let mut buf = buf;
+ foreach ss in self.iter() {
+ do ss.as_slice().as_imm_buf |ssbuf, sslen| {
+ if first {
+ first = false;
+ } else {
+ ptr::copy_memory(buf, sepbuf, seplen);
+ buf = buf.offset(seplen as int);
+ }
+ ptr::copy_memory(buf, ssbuf, sslen);
+ buf = buf.offset(sslen as int);
+ }
+ }
+ }
+ }
+ raw::set_len(&mut s, len);
+ }
+ s
+ }
}
/// Something that can be used to compare against a character
*/
/// Bytewise slice equality
-#[cfg(not(test))]
+#[cfg(not(test), stage0)]
#[lang="str_eq"]
#[inline]
pub fn eq_slice(a: &str, b: &str) -> bool {
}
}
-#[cfg(test)]
+/// Bytewise slice equality
+#[cfg(not(test), not(stage0))]
+#[lang="str_eq"]
+#[inline]
+pub fn eq_slice(a: &str, b: &str) -> bool {
+ do a.as_imm_buf |ap, alen| {
+ do b.as_imm_buf |bp, blen| {
+ if (alen != blen) { false }
+ else {
+ unsafe {
+ libc::memcmp(ap as *libc::c_void,
+ bp as *libc::c_void,
+ alen as libc::size_t) == 0
+ }
+ }
+ }
+ }
+}
+
+/// Bytewise slice equality
+#[cfg(test, stage0)]
+#[lang="str_eq"]
#[inline]
pub fn eq_slice(a: &str, b: &str) -> bool {
do a.as_imm_buf |ap, alen| {
}
}
+/// Bytewise slice equality
+#[cfg(test, not(stage0))]
+#[inline]
+pub fn eq_slice(a: &str, b: &str) -> bool {
+ do a.as_imm_buf |ap, alen| {
+ do b.as_imm_buf |bp, blen| {
+ if (alen != blen) { false }
+ else {
+ unsafe {
+ libc::memcmp(ap as *libc::c_void,
+ bp as *libc::c_void,
+ alen as libc::size_t) == 0
+ }
+ }
+ }
+ }
+}
+
/// Bytewise string equality
#[cfg(not(test))]
#[lang="uniq_str_eq"]
use str::is_utf8;
use vec;
use vec::MutableVector;
- use unstable::raw::{Slice, String};
+ use unstable::raw::Slice;
+ #[cfg(stage0)]
+ use unstable::raw::String;
/// Create a Rust string from a *u8 buffer of the given length
+ #[cfg(stage0)]
pub unsafe fn from_buf_len(buf: *u8, len: uint) -> ~str {
let mut v: ~[u8] = vec::with_capacity(len + 1);
v.as_mut_buf(|vbuf, _len| {
cast::transmute(v)
}
+ /// Create a Rust string from a *u8 buffer of the given length
+ #[cfg(not(stage0))]
+ pub unsafe fn from_buf_len(buf: *u8, len: uint) -> ~str {
+ let mut v: ~[u8] = vec::with_capacity(len);
+ do v.as_mut_buf |vbuf, _len| {
+ ptr::copy_memory(vbuf, buf as *u8, len)
+ };
+ vec::raw::set_len(&mut v, len);
+
+ assert!(is_utf8(v));
+ ::cast::transmute(v)
+ }
+
/// Create a Rust string from a null-terminated C string
pub unsafe fn from_c_str(buf: *libc::c_char) -> ~str {
let mut curr = buf;
/// Converts an owned vector of bytes to a new owned string. This assumes
/// that the utf-8-ness of the vector has already been validated
+ #[cfg(stage0)]
pub unsafe fn from_bytes_owned(mut v: ~[u8]) -> ~str {
v.push(0u8);
cast::transmute(v)
}
+ /// Converts an owned vector of bytes to a new owned string. This assumes
+ /// that the utf-8-ness of the vector has already been validated
+ #[cfg(not(stage0))]
+ #[inline]
+ pub unsafe fn from_bytes_owned(v: ~[u8]) -> ~str {
+ cast::transmute(v)
+ }
+
/// Converts a byte to a string.
pub unsafe fn from_byte(u: u8) -> ~str { from_bytes([u]) }
/// Form a slice from a C string. Unsafe because the caller must ensure the
/// C string has the static lifetime, or else the return value may be
/// invalidated later.
+ #[cfg(stage0)]
pub unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str {
let s = s as *u8;
let mut curr = s;
cast::transmute(v)
}
+ /// Form a slice from a C string. Unsafe because the caller must ensure the
+ /// C string has the static lifetime, or else the return value may be
+ /// invalidated later.
+ #[cfg(not(stage0))]
+ pub unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str {
+ let s = s as *u8;
+ let mut curr = s;
+ let mut len = 0u;
+ while *curr != 0u8 {
+ len += 1u;
+ curr = ptr::offset(s, len as int);
+ }
+ let v = Slice { data: s, len: len };
+ assert!(is_utf8(::cast::transmute(v)));
+ ::cast::transmute(v)
+ }
+
/// Takes a bytewise (not UTF-8) slice from a string.
///
/// Returns the substring from [`begin`..`end`).
///
/// If begin is greater than end.
/// If end is greater than the length of the string.
+ #[cfg(stage0)]
#[inline]
pub unsafe fn slice_bytes(s: &str, begin: uint, end: uint) -> &str {
do s.as_imm_buf |sbuf, n| {
}
}
+ /// Takes a bytewise (not UTF-8) slice from a string.
+ ///
+ /// Returns the substring from [`begin`..`end`).
+ ///
+ /// # Failure
+ ///
+ /// If begin is greater than end.
+ /// If end is greater than the length of the string.
+ #[cfg(not(stage0))]
+ #[inline]
+ pub unsafe fn slice_bytes(s: &str, begin: uint, end: uint) -> &str {
+ do s.as_imm_buf |sbuf, n| {
+ assert!((begin <= end));
+ assert!((end <= n));
+
+ cast::transmute(Slice {
+ data: ptr::offset(sbuf, begin as int),
+ len: end - begin,
+ })
+ }
+ }
+
/// Appends a byte to a string. (Not UTF-8 safe).
pub unsafe fn push_byte(s: &mut ~str, b: u8) {
let new_len = s.len() + 1;
}
/// Sets the length of the string and adds the null terminator
+ #[cfg(stage0)]
#[inline]
pub unsafe fn set_len(v: &mut ~str, new_len: uint) {
let v: **mut String = cast::transmute(v);
*null = 0u8;
}
+ /// Sets the length of a string
+ ///
+ /// This will explicitly set the size of the string, without actually
+ /// modifing its buffers, so it is up to the caller to ensure that
+ /// the string is actually the specified size.
+ #[cfg(not(stage0))]
+ #[inline]
+ pub unsafe fn set_len(s: &mut ~str, new_len: uint) {
+ let v: &mut ~[u8] = cast::transmute(s);
+ vec::raw::set_len(v, new_len)
+ }
+
+ /// Sets the length of a string
+ ///
+ /// This will explicitly set the size of the string, without actually
+ /// modifing its buffers, so it is up to the caller to ensure that
+ /// the string is actually the specified size.
#[test]
fn test_from_buf_len() {
unsafe {
}
impl<'self> Container for &'self str {
+ #[cfg(stage0)]
#[inline]
fn len(&self) -> uint {
do self.as_imm_buf |_p, n| { n - 1u }
}
+
+ #[cfg(not(stage0))]
+ #[inline]
+ fn len(&self) -> uint {
+ do self.as_imm_buf |_p, n| { n }
+ }
}
impl Container for ~str {
}
/// Copy a slice into a new unique str
+ #[cfg(stage0)]
#[inline]
fn to_owned(&self) -> ~str {
do self.as_imm_buf |src, len| {
}
}
+ /// Copy a slice into a new unique str
+ #[cfg(not(stage0))]
+ #[inline]
+ fn to_owned(&self) -> ~str {
+ do self.as_imm_buf |src, len| {
+ unsafe {
+ let mut v = vec::with_capacity(len);
+
+ do v.as_mut_buf |dst, _| {
+ ptr::copy_memory(dst, src, len);
+ }
+ vec::raw::set_len(&mut v, len);
+ ::cast::transmute(v)
+ }
+ }
+ }
+
+ #[cfg(stage0)]
#[inline]
fn to_managed(&self) -> @str {
let v = at_vec::from_fn(self.len() + 1, |i| {
unsafe { cast::transmute(v) }
}
+ #[cfg(not(stage0))]
+ #[inline]
+ fn to_managed(&self) -> @str {
+ unsafe {
+ let v: *&[u8] = cast::transmute(self);
+ cast::transmute(at_vec::to_managed(*v))
+ }
+ }
+
/// Converts to a vector of `u16` encoded as UTF-16.
fn to_utf16(&self) -> ~[u16] {
let mut u = ~[];
/// Work with the byte buffer of a string as a byte slice.
///
/// The byte slice does not include the null terminator.
+ #[cfg(stage0)]
fn as_bytes(&self) -> &'self [u8] {
unsafe {
let mut slice = self.repr();
}
}
+ /// Work with the byte buffer of a string as a byte slice.
+ ///
+ /// The byte slice does not include the null terminator.
+ #[cfg(not(stage0))]
+ fn as_bytes(&self) -> &'self [u8] {
+ unsafe { cast::transmute(*self) }
+ }
+
/// Returns the byte index of the first character of `self` that matches `search`
///
/// # Return value
}
/// Given a string, make a new string with repeated copies of it.
+ #[cfg(stage0)]
fn repeat(&self, nn: uint) -> ~str {
do self.as_imm_buf |buf, len| {
// ignore the NULL terminator
}
}
+ /// Given a string, make a new string with repeated copies of it.
+ #[cfg(not(stage0))]
+ fn repeat(&self, nn: uint) -> ~str {
+ do self.as_imm_buf |buf, len| {
+ let mut ret = with_capacity(nn * len);
+
+ unsafe {
+ do ret.as_mut_buf |rbuf, _len| {
+ let mut rbuf = rbuf;
+
+ do nn.times {
+ ptr::copy_memory(rbuf, buf, len);
+ rbuf = rbuf.offset(len as int);
+ }
+ }
+ raw::set_len(&mut ret, nn * len);
+ }
+ ret
+ }
+ }
+
/// Retrieves the first character from a string slice and returns
/// it. This does not allocate a new string; instead, it returns a
/// slice that point one character beyond the character that was
fn reserve(&mut self, n: uint);
fn reserve_at_least(&mut self, n: uint);
fn capacity(&self) -> uint;
+ #[cfg(stage0)]
fn to_bytes_with_null(self) -> ~[u8];
/// Work with the mutable byte buffer and length of a slice.
///
/// * s - A string
/// * n - The number of bytes to reserve space for
+ #[cfg(stage0)]
#[inline]
pub fn reserve(&mut self, n: uint) {
unsafe {
}
}
+ /// Reserves capacity for exactly `n` bytes in the given string, not including
+ /// the null terminator.
+ ///
+ /// Assuming single-byte characters, the resulting string will be large
+ /// enough to hold a string of length `n`. To account for the null terminator,
+ /// the underlying buffer will have the size `n` + 1.
+ ///
+ /// If the capacity for `s` is already equal to or greater than the requested
+ /// capacity, then no action is taken.
+ ///
+ /// # Arguments
+ ///
+ /// * s - A string
+ /// * n - The number of bytes to reserve space for
+ #[cfg(not(stage0))]
+ #[inline]
+ pub fn reserve(&mut self, n: uint) {
+ unsafe {
+ let v: &mut ~[u8] = cast::transmute(self);
+ (*v).reserve(n);
+ }
+ }
+
/// Reserves capacity for at least `n` bytes in the given string, not including
/// the null terminator.
///
///
/// * s - A string
/// * n - The number of bytes to reserve space for
+ #[cfg(stage0)]
#[inline]
fn reserve_at_least(&mut self, n: uint) {
self.reserve(uint::next_power_of_two(n + 1u) - 1u)
}
+ /// Reserves capacity for at least `n` bytes in the given string.
+ ///
+ /// Assuming single-byte characters, the resulting string will be large
+ /// enough to hold a string of length `n`. To account for the null terminator,
+ /// the underlying buffer will have the size `n` + 1.
+ ///
+ /// This function will over-allocate in order to amortize the allocation costs
+ /// in scenarios where the caller may need to repeatedly reserve additional
+ /// space.
+ ///
+ /// If the capacity for `s` is already equal to or greater than the requested
+ /// capacity, then no action is taken.
+ ///
+ /// # Arguments
+ ///
+ /// * s - A string
+ /// * n - The number of bytes to reserve space for
+ #[cfg(not(stage0))]
+ #[inline]
+ fn reserve_at_least(&mut self, n: uint) {
+ self.reserve(uint::next_power_of_two(n))
+ }
+
/// Returns the number of single-byte characters the string can hold without
/// reallocating
+ #[cfg(stage0)]
fn capacity(&self) -> uint {
let buf: &~[u8] = unsafe { cast::transmute(self) };
let vcap = buf.capacity();
vcap - 1u
}
+ /// Returns the number of single-byte characters the string can hold without
+ /// reallocating
+ #[cfg(not(stage0))]
+ fn capacity(&self) -> uint {
+ unsafe {
+ let buf: &~[u8] = cast::transmute(self);
+ buf.capacity()
+ }
+ }
+
/// Convert to a vector of bytes. This does not allocate a new
/// string, and includes the null terminator.
+ #[cfg(stage0)]
#[inline]
fn to_bytes_with_null(self) -> ~[u8] {
unsafe { cast::transmute(self) }
assert_eq!("ศไทย中华Việt Nam".as_bytes(), v);
}
+ #[cfg(stage0)]
+ #[test]
+ #[ignore(cfg(windows))]
+ #[should_fail]
+ fn test_as_bytes_fail() {
+ // Don't double free. (I'm not sure if this exercises the
+ // original problem code path anymore.)
+ let s = ~"";
+ let _bytes = s.as_bytes();
+ fail!();
+ }
+
+ #[cfg(stage0)]
+ #[test]
+ #[ignore(cfg(windows))]
+ #[should_fail]
+ fn test_as_bytes_fail() {
+ // Don't double free. (I'm not sure if this exercises the
+ // original problem code path anymore.)
+ let s = ~"";
+ let _bytes = s.as_bytes_with_null();
+ fail!();
+ }
+
+ #[cfg(stage0)]
#[test]
fn test_to_bytes_with_null() {
let s = ~"ศไทย中华Việt Nam";
#[test]
fn test_as_imm_buf() {
- do "".as_imm_buf |buf, len| {
- assert_eq!(len, 1);
- unsafe {
- assert_eq!(*ptr::offset(buf, 0), 0);
- }
+ do "".as_imm_buf |_, len| {
+ assert_eq!(len, 0);
}
do "hello".as_imm_buf |buf, len| {
- assert_eq!(len, 6);
+ assert_eq!(len, 5);
unsafe {
assert_eq!(*ptr::offset(buf, 0), 'h' as u8);
assert_eq!(*ptr::offset(buf, 1), 'e' as u8);
assert_eq!(*ptr::offset(buf, 2), 'l' as u8);
assert_eq!(*ptr::offset(buf, 3), 'l' as u8);
assert_eq!(*ptr::offset(buf, 4), 'o' as u8);
- assert_eq!(*ptr::offset(buf, 5), 0);
}
}
}