]> git.lizzy.rs Git - rust.git/commitdiff
Remove trailing null from strings
authorErick Tryzelaar <erick.tryzelaar@gmail.com>
Sun, 4 Aug 2013 20:22:56 +0000 (13:22 -0700)
committerErick Tryzelaar <erick.tryzelaar@gmail.com>
Sun, 4 Aug 2013 22:45:16 +0000 (15:45 -0700)
12 files changed:
src/libextra/terminfo/parm.rs
src/librustc/middle/trans/common.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/reflect.rs
src/librustc/middle/trans/tvec.rs
src/libstd/cast.rs
src/libstd/io.rs
src/libstd/run.rs
src/libstd/str.rs
src/libstd/str/ascii.rs
src/libstd/unstable/extfmt.rs
src/rt/rust_builtin.cpp

index 3669c1ea0a3579a71061e253e032839fdbfbc7be..d95e5d8d6d8e3cba2dfc80605af5d6f29abfa018 100644 (file)
@@ -476,6 +476,7 @@ impl FormatOp {
     }
 }
 
+#[cfg(stage0)]
 priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> {
     let mut s = match val {
         Number(d) => {
@@ -545,8 +546,103 @@ impl FormatOp {
         String(s) => {
             match op {
                 FormatString => {
-                    let mut s = s.to_bytes_with_null();
-                    s.pop(); // remove the null
+                    let mut s = s.as_bytes().to_owned();
+                    if flags.precision > 0 && flags.precision < s.len() {
+                        s.truncate(flags.precision);
+                    }
+                    s
+                }
+                _ => {
+                    return Err(fmt!("non-string on stack with %%%c", op.to_char()))
+                }
+            }
+        }
+    };
+    if flags.width > s.len() {
+        let n = flags.width - s.len();
+        if flags.left {
+            s.grow(n, &(' ' as u8));
+        } else {
+            let mut s_ = vec::with_capacity(flags.width);
+            s_.grow(n, &(' ' as u8));
+            s_.push_all_move(s);
+            s = s_;
+        }
+    }
+    Ok(s)
+}
+
+#[cfg(not(stage0))]
+priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> {
+    let mut s = match val {
+        Number(d) => {
+            match op {
+                FormatString => {
+                    return Err(~"non-number on stack with %s")
+                }
+                _ => {
+                    let radix = match op {
+                        FormatDigit => 10,
+                        FormatOctal => 8,
+                        FormatHex|FormatHEX => 16,
+                        FormatString => util::unreachable()
+                    };
+                    let mut s = ~[];
+                    match op {
+                        FormatDigit => {
+                            let sign = if flags.sign { SignAll } else { SignNeg };
+                            do int_to_str_bytes_common(d, radix, sign) |c| {
+                                s.push(c);
+                            }
+                        }
+                        _ => {
+                            do int_to_str_bytes_common(d as uint, radix, SignNone) |c| {
+                                s.push(c);
+                            }
+                        }
+                    };
+                    if flags.precision > s.len() {
+                        let mut s_ = vec::with_capacity(flags.precision);
+                        let n = flags.precision - s.len();
+                        s_.grow(n, &('0' as u8));
+                        s_.push_all_move(s);
+                        s = s_;
+                    }
+                    assert!(!s.is_empty(), "string conversion produced empty result");
+                    match op {
+                        FormatDigit => {
+                            if flags.space && !(s[0] == '-' as u8 || s[0] == '+' as u8) {
+                                s.unshift(' ' as u8);
+                            }
+                        }
+                        FormatOctal => {
+                            if flags.alternate && s[0] != '0' as u8 {
+                                s.unshift('0' as u8);
+                            }
+                        }
+                        FormatHex => {
+                            if flags.alternate {
+                                let s_ = util::replace(&mut s, ~['0' as u8, 'x' as u8]);
+                                s.push_all_move(s_);
+                            }
+                        }
+                        FormatHEX => {
+                            s = s.into_ascii().to_upper().into_bytes();
+                            if flags.alternate {
+                                let s_ = util::replace(&mut s, ~['0' as u8, 'X' as u8]);
+                                s.push_all_move(s_);
+                            }
+                        }
+                        FormatString => util::unreachable()
+                    }
+                    s
+                }
+            }
+        }
+        String(s) => {
+            match op {
+                FormatString => {
+                    let mut s = s.as_bytes().to_owned();
                     if flags.precision > 0 && flags.precision < s.len() {
                         s.truncate(flags.precision);
                     }
index 4f5fae8db1a4cf4783d82969f7273749a575b577..2bd1b34f84c69423263befae61a95a07d6e50e25 100644 (file)
@@ -780,7 +780,7 @@ pub fn C_estr_slice(cx: &mut CrateContext, s: @str) -> ValueRef {
     unsafe {
         let len = s.len();
         let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s), Type::i8p().to_ref());
-        C_struct([cs, C_uint(cx, len + 1u /* +1 for null */)])
+        C_struct([cs, C_uint(cx, len)])
     }
 }
 
index 10586dbe55b1acc349d7862d54c1788d824880a1..2487d481c0deae3505c75b74d41edd98af2251a0 100644 (file)
@@ -870,7 +870,6 @@ fn trans_index(bcx: @mut Block,
 
         let _icx = push_ctxt("trans_index");
         let ccx = bcx.ccx();
-        let base_ty = expr_ty(bcx, base);
         let mut bcx = bcx;
 
         let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
@@ -900,12 +899,6 @@ fn trans_index(bcx: @mut Block,
         let (bcx, base, len) =
             base_datum.get_vec_base_and_len(bcx, index_expr.span,
                                             index_expr.id, 0);
-        let mut len = len;
-
-        if ty::type_is_str(base_ty) {
-            // acccount for null terminator in the case of string
-            len = Sub(bcx, len, C_uint(bcx.ccx(), 1u));
-        }
 
         debug!("trans_index: base %s", bcx.val_to_str(base));
         debug!("trans_index: len %s", bcx.val_to_str(len));
index 93b2e8a6665df25816d513630a9c929217c3ae8d..032bbd1be3a84c87f024f64a076f2cc7f749f67b 100644 (file)
@@ -58,7 +58,7 @@ pub fn c_slice(&mut self, s: @str) -> ValueRef {
         let str_vstore = ty::vstore_slice(ty::re_static);
         let str_ty = ty::mk_estr(bcx.tcx(), str_vstore);
         let scratch = scratch_datum(bcx, str_ty, "", false);
-        let len = C_uint(bcx.ccx(), s.len() + 1);
+        let len = C_uint(bcx.ccx(), s.len());
         let c_str = PointerCast(bcx, C_cstr(bcx.ccx(), s), Type::i8p());
         Store(bcx, c_str, GEPi(bcx, scratch.val, [ 0, 0 ]));
         Store(bcx, len, GEPi(bcx, scratch.val, [ 0, 1 ]));
index b37a99771bde0cd5edd523ef6d068d655b1eaa36..58a242c53ec1f838140040c022b9c2e32f14491d 100644 (file)
@@ -265,7 +265,7 @@ pub fn trans_lit_str(bcx: @mut Block,
         Ignore => bcx,
         SaveIn(lldest) => {
             unsafe {
-                let bytes = str_lit.len() + 1; // count null-terminator too
+                let bytes = str_lit.len(); // count null-terminator too
                 let llbytes = C_uint(bcx.ccx(), bytes);
                 let llcstr = C_cstr(bcx.ccx(), str_lit);
                 let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p().to_ref());
@@ -363,7 +363,7 @@ pub fn write_content(bcx: @mut Block,
                     return bcx;
                 }
                 SaveIn(lldest) => {
-                    let bytes = s.len() + 1; // copy null-terminator too
+                    let bytes = s.len();
                     let llbytes = C_uint(bcx.ccx(), bytes);
                     let llcstr = C_cstr(bcx.ccx(), s);
                     base::call_memcpy(bcx, lldest, llcstr, llbytes, 1);
@@ -491,7 +491,7 @@ pub fn elements_required(bcx: @mut Block, content_expr: &ast::expr) -> uint {
 
     match content_expr.node {
         ast::expr_lit(@codemap::spanned { node: ast::lit_str(s), _ }) => {
-            s.len() + 1
+            s.len()
         },
         ast::expr_vec(ref es, _) => es.len(),
         ast::expr_repeat(_, count_expr, _) => {
@@ -524,7 +524,6 @@ pub fn get_base_and_len(bcx: @mut Block,
     match vstore {
         ty::vstore_fixed(n) => {
             let base = GEPi(bcx, llval, [0u, 0u]);
-            let n = if ty::type_is_str(vec_ty) { n + 1u } else { n };
             let len = Mul(bcx, C_uint(ccx, n), vt.llunit_size);
             (base, len)
         }
index ee91d12790953214b49a0c25327a141e8cd03ee9..ff9057afb55fc47dfb1b10f88d8b7b958d757f34 100644 (file)
@@ -165,10 +165,20 @@ fn test_transmute() {
         }
     }
 
+    #[cfg(stage0)]
     #[test]
     fn test_transmute2() {
         unsafe {
             assert_eq!(~[76u8, 0u8], transmute(~"L"));
         }
     }
+
+    #[cfg(not(stage0))]
+    #[test]
+    fn test_transmute2() {
+        unsafe {
+            assert_eq!(~[76u8], transmute(~"L"));
+        }
+    }
+
 }
index 78c6e8d5342ded001a00363f435c306ab3436274..f0d4c3a737596f93857da3b6837f39011a9d3666 100644 (file)
@@ -1707,6 +1707,7 @@ pub fn with_bytes_writer(f: &fn(@Writer)) -> ~[u8] {
     (*bytes).clone()
 }
 
+#[cfg(stage0)]
 pub fn with_str_writer(f: &fn(@Writer)) -> ~str {
     let mut v = with_bytes_writer(f);
 
@@ -1719,6 +1720,11 @@ pub fn with_str_writer(f: &fn(@Writer)) -> ~str {
     }
 }
 
+#[cfg(not(stage0))]
+pub fn with_str_writer(f: &fn(@Writer)) -> ~str {
+    str::from_bytes(with_bytes_writer(f))
+}
+
 // Utility functions
 pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) ->
    uint {
index 6e447d3ded473d839636694665ed91989d0f9fd8..d0f7f307088c4e6ca835e350d507cf4f161b7ce6 100644 (file)
@@ -758,7 +758,8 @@ fn with_envp<T>(env: Option<&[(~str, ~str)]>, cb: &fn(*mut c_void) -> T) -> T {
 
             foreach pair in env.iter() {
                 let kv = fmt!("%s=%s", pair.first(), pair.second());
-                blk.push_all(kv.to_c_str().as_bytes());
+                blk.push_all(kv.as_bytes());
+                blk.push(0);
             }
 
             blk.push(0);
index 4935477536fc5b8d7b914bfd8511bf3188af13cd..5796b541186e55cbf3401772e8d5505fcee124bf 100644 (file)
@@ -33,6 +33,7 @@
 use ptr::RawPtr;
 use to_str::ToStr;
 use uint;
+#[cfg(stage0)]
 use unstable::raw::Repr;
 use vec;
 use vec::{OwnedVector, OwnedCopyableVector, ImmutableVector, MutableVector};
@@ -91,6 +92,7 @@ pub fn from_bytes_owned(vv: ~[u8]) -> ~str {
 /// # Failure
 ///
 /// Fails if invalid UTF-8
+#[cfg(stage0)]
 pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str {
     unsafe {
         assert!(is_utf8(vector));
@@ -100,6 +102,20 @@ pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str {
     }
 }
 
+/// 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() }
@@ -118,11 +134,23 @@ 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 = ~"";
@@ -153,6 +181,7 @@ pub trait StrVector {
 
 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 ~""; }
 
@@ -176,7 +205,32 @@ pub fn concat(&self) -> ~str {
         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 ~""; }
 
@@ -215,6 +269,45 @@ pub fn connect(&self, sep: &str) -> ~str {
         }
         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
@@ -485,7 +578,7 @@ pub fn replace(s: &str, from: &str, to: &str) -> ~str {
 */
 
 /// Bytewise slice equality
-#[cfg(not(test))]
+#[cfg(not(test), stage0)]
 #[lang="str_eq"]
 #[inline]
 pub fn eq_slice(a: &str, b: &str) -> bool {
@@ -503,7 +596,28 @@ 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| {
@@ -520,6 +634,24 @@ pub fn eq_slice(a: &str, b: &str) -> bool {
     }
 }
 
+/// 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"]
@@ -761,9 +893,12 @@ pub mod raw {
     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| {
@@ -776,6 +911,19 @@ pub unsafe fn from_buf_len(buf: *u8, len: uint) -> ~str {
         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;
@@ -796,17 +944,27 @@ pub unsafe fn from_bytes(v: &[u8]) -> ~str {
 
     /// 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;
@@ -820,6 +978,23 @@ pub unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str {
         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`).
@@ -828,6 +1003,7 @@ pub unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str {
     ///
     /// 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| {
@@ -841,6 +1017,28 @@ pub unsafe fn slice_bytes(s: &str, begin: uint, end: uint) -> &str {
         }
     }
 
+    /// 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;
@@ -877,6 +1075,7 @@ pub unsafe fn shift_byte(s: &mut ~str) -> u8 {
     }
 
     /// 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);
@@ -886,6 +1085,23 @@ pub unsafe fn set_len(v: &mut ~str, new_len: uint) {
         *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 {
@@ -1081,10 +1297,17 @@ fn into_owned(self) -> ~str { self.to_owned() }
 }
 
 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 {
@@ -1558,6 +1781,7 @@ pub fn replace(&self, from: &str, to: &str) -> ~str {
     }
 
     /// Copy a slice into a new unique str
+    #[cfg(stage0)]
     #[inline]
     fn to_owned(&self) -> ~str {
         do self.as_imm_buf |src, len| {
@@ -1575,6 +1799,24 @@ fn to_owned(&self) -> ~str {
         }
     }
 
+    /// 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| {
@@ -1583,6 +1825,15 @@ fn to_managed(&self) -> @str {
         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 = ~[];
@@ -1723,6 +1974,7 @@ fn char_at_reverse(&self, i: uint) -> char {
     /// 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();
@@ -1731,6 +1983,14 @@ fn as_bytes(&self) -> &'self [u8] {
         }
     }
 
+    /// 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
@@ -1797,6 +2057,7 @@ fn find_str(&self, needle: &str) -> Option<uint> {
     }
 
     /// 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
@@ -1818,6 +2079,27 @@ fn repeat(&self, nn: uint) -> ~str {
         }
     }
 
+    /// 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
@@ -1934,6 +2216,7 @@ pub trait OwnedStr {
     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.
@@ -2080,6 +2363,7 @@ fn append(self, rhs: &str) -> ~str {
     ///
     /// * s - A string
     /// * n - The number of bytes to reserve space for
+    #[cfg(stage0)]
     #[inline]
     pub fn reserve(&mut self, n: uint) {
         unsafe {
@@ -2088,6 +2372,29 @@ pub fn reserve(&mut self, n: uint) {
         }
     }
 
+    /// 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.
     ///
@@ -2106,13 +2413,38 @@ pub fn reserve(&mut self, n: uint) {
     ///
     /// * 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();
@@ -2120,8 +2452,19 @@ fn capacity(&self) -> uint {
         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) }
@@ -2817,6 +3160,31 @@ fn test_as_bytes() {
         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";
@@ -2844,22 +3212,18 @@ fn test_as_bytes_fail() {
 
     #[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);
             }
         }
     }
index 3f24f98bd3d2a25a25891f8d1b0932d1232b8f0d..f1ffa1b3bce16c5ca7ddd35e1b62eedb24b15d23 100644 (file)
@@ -15,7 +15,9 @@
 use str::StrSlice;
 use cast;
 use iterator::{Iterator, IteratorUtil};
-use vec::{CopyableVector, ImmutableVector, OwnedVector};
+use vec::{CopyableVector, ImmutableVector};
+#[cfg(stage0)]
+use vec::OwnedVector;
 use to_bytes::IterBytes;
 use option::{Some, None};
 
@@ -101,19 +103,26 @@ fn is_ascii(&self) -> bool {
     }
 }
 
-impl<'self> AsciiCast<&'self[Ascii]> for &'self str {
+impl<'self> AsciiCast<&'self [Ascii]> for &'self str {
     #[inline]
-    fn to_ascii(&self) -> &'self[Ascii] {
+    fn to_ascii(&self) -> &'self [Ascii] {
         assert!(self.is_ascii());
-        unsafe {self.to_ascii_nocheck()}
+        unsafe { self.to_ascii_nocheck() }
     }
 
+    #[cfg(stage0)]
     #[inline]
-    unsafe fn to_ascii_nocheck(&self) -> &'self[Ascii] {
+    unsafe fn to_ascii_nocheck(&self) -> &'self [Ascii] {
         let (p,len): (*u8, uint) = cast::transmute(*self);
         cast::transmute((p, len - 1))
     }
 
+    #[cfg(not(stage0))]
+    #[inline]
+    unsafe fn to_ascii_nocheck(&self) -> &'self [Ascii] {
+        cast::transmute(*self)
+    }
+
     #[inline]
     fn is_ascii(&self) -> bool {
         self.byte_iter().all(|b| b.is_ascii())
@@ -186,12 +195,19 @@ fn into_ascii(self) -> ~[Ascii] {
         unsafe {self.into_ascii_nocheck()}
     }
 
+    #[cfg(stage0)]
     #[inline]
     unsafe fn into_ascii_nocheck(self) -> ~[Ascii] {
         let mut r: ~[Ascii] = cast::transmute(self);
         r.pop();
         r
     }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    unsafe fn into_ascii_nocheck(self) -> ~[Ascii] {
+        cast::transmute(self)
+    }
 }
 
 /// Trait for converting an ascii type to a string. Needed to convert `&[Ascii]` to `~str`
@@ -210,11 +226,19 @@ pub trait AsciiStr {
 }
 
 impl<'self> AsciiStr for &'self [Ascii] {
+    #[cfg(stage0)]
     #[inline]
     fn to_str_ascii(&self) -> ~str {
         let mut cpy = self.to_owned();
         cpy.push(0u8.to_ascii());
-        unsafe {cast::transmute(cpy)}
+        unsafe { cast::transmute(cpy) }
+    }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn to_str_ascii(&self) -> ~str {
+        let cpy = self.to_owned();
+        unsafe { cast::transmute(cpy) }
     }
 
     #[inline]
@@ -234,11 +258,18 @@ fn eq_ignore_case(self, other: &[Ascii]) -> bool {
 }
 
 impl ToStrConsume for ~[Ascii] {
+    #[cfg(stage0)]
     #[inline]
     fn into_str(self) -> ~str {
         let mut cpy = self;
         cpy.push(0u8.to_ascii());
-        unsafe {cast::transmute(cpy)}
+        unsafe { cast::transmute(cpy) }
+    }
+
+    #[cfg(not(stage0))]
+    #[inline]
+    fn into_str(self) -> ~str {
+        unsafe { cast::transmute(self) }
     }
 }
 
@@ -257,7 +288,7 @@ pub trait ToBytesConsume {
 
 impl ToBytesConsume for ~[Ascii] {
     fn into_bytes(self) -> ~[u8] {
-        unsafe {cast::transmute(self)}
+        unsafe { cast::transmute(self) }
     }
 }
 
index 5417af50081318282126e2de2e624624b7149ca3..a08851df626c6240276029684a09f82dbe47b2db 100644 (file)
@@ -549,12 +549,14 @@ pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
         // For strings, precision is the maximum characters
         // displayed
         let unpadded = match cv.precision {
-          CountImplied => s,
-          CountIs(max) => if (max as uint) < s.char_len() {
-            s.slice(0, max as uint)
-          } else {
-            s
-          }
+            CountImplied => s,
+            CountIs(max) => {
+                if (max as uint) < s.char_len() {
+                    s.slice(0, max as uint)
+                } else {
+                    s
+                }
+            }
         };
         pad(cv, unpadded, None, PadNozero, buf);
     }
index d77a9f58a38531f795d470a5523cb655c41350ed..dffa7232e348770fa7c5119e07a63bbd02c2f29d 100644 (file)
@@ -302,10 +302,9 @@ void tm_to_rust_tm(tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
 
     if (zone != NULL) {
         size_t size = strlen(zone);
-        reserve_vec_exact(&out_tm->tm_zone, size + 1);
+        reserve_vec_exact(&out_tm->tm_zone, size);
         memcpy(out_tm->tm_zone->data, zone, size);
-        out_tm->tm_zone->fill = size + 1;
-        out_tm->tm_zone->data[size] = '\0';
+        out_tm->tm_zone->fill = size;
     }
 }