diff options
| author | Erick Tryzelaar <erick.tryzelaar@gmail.com> | 2013-08-04 13:22:56 -0700 |
|---|---|---|
| committer | Erick Tryzelaar <erick.tryzelaar@gmail.com> | 2013-08-04 15:45:16 -0700 |
| commit | 5865a7597b060e81a6540b5d205b4a7d45a9b328 (patch) | |
| tree | d344bbaa99d685e53df4153dd0e266b2e8221596 | |
| parent | 17e0089856de145b10485c9a96bcf4f39e5b7f71 (diff) | |
| download | rust-5865a7597b060e81a6540b5d205b4a7d45a9b328.tar.gz rust-5865a7597b060e81a6540b5d205b4a7d45a9b328.zip | |
Remove trailing null from strings
| -rw-r--r-- | src/libextra/terminfo/parm.rs | 100 | ||||
| -rw-r--r-- | src/librustc/middle/trans/common.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/trans/expr.rs | 7 | ||||
| -rw-r--r-- | src/librustc/middle/trans/reflect.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/trans/tvec.rs | 7 | ||||
| -rw-r--r-- | src/libstd/cast.rs | 10 | ||||
| -rw-r--r-- | src/libstd/io.rs | 6 | ||||
| -rw-r--r-- | src/libstd/run.rs | 3 | ||||
| -rw-r--r-- | src/libstd/str.rs | 384 | ||||
| -rw-r--r-- | src/libstd/str/ascii.rs | 47 | ||||
| -rw-r--r-- | src/libstd/unstable/extfmt.rs | 14 | ||||
| -rw-r--r-- | src/rt/rust_builtin.cpp | 5 |
12 files changed, 544 insertions, 43 deletions
diff --git a/src/libextra/terminfo/parm.rs b/src/libextra/terminfo/parm.rs index 3669c1ea0a3..d95e5d8d6d8 100644 --- a/src/libextra/terminfo/parm.rs +++ b/src/libextra/terminfo/parm.rs @@ -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 @@ priv fn format(val: Param, op: FormatOp, flags: Flags) -> Result<~[u8],~str> { 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); } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 4f5fae8db1a..2bd1b34f84c 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -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)]) } } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 10586dbe55b..2487d481c0d 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -870,7 +870,6 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock { 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_lvalue_unadjusted(bcx: @mut Block, expr: @ast::expr) -> DatumBlock { 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)); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 93b2e8a6665..032bbd1be3a 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -58,7 +58,7 @@ impl Reflector { 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 ])); diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index b37a99771bd..58a242c53ec 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -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) } diff --git a/src/libstd/cast.rs b/src/libstd/cast.rs index ee91d127909..ff9057afb55 100644 --- a/src/libstd/cast.rs +++ b/src/libstd/cast.rs @@ -165,10 +165,20 @@ mod tests { } } + #[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")); + } + } + } diff --git a/src/libstd/io.rs b/src/libstd/io.rs index 78c6e8d5342..f0d4c3a7375 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -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 { diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 6e447d3ded4..d0f7f307088 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -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); diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 4935477536f..5796b541186 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -33,6 +33,7 @@ use ptr; 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 @@ impl ToStr for @str { /// # 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 @@ impl<'self, S: Str> StrVector for &'self [S] { 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 @@ impl<'self, S: Str> StrVector for &'self [S] { } 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 @@ Section: Comparing strings */ /// 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 mod raw { 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 mod raw { /// 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 mod raw { 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 mod raw { /// /// 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 mod raw { } } + /// 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 mod raw { } /// 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 mod raw { *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 @@ impl<'self> Str for @str { } 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 @@ impl<'self> StrSlice<'self> for &'self 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 @@ impl<'self> StrSlice<'self> for &'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 @@ impl<'self> StrSlice<'self> for &'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 @@ impl<'self> StrSlice<'self> for &'self str { /// 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 @@ impl<'self> StrSlice<'self> for &'self str { } } + /// 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 @@ impl<'self> StrSlice<'self> for &'self str { } /// 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 @@ impl<'self> StrSlice<'self> for &'self 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 @@ impl OwnedStr for ~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 @@ impl OwnedStr for ~str { } } + /// 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 @@ impl OwnedStr for ~str { /// /// * 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 @@ impl OwnedStr for ~str { 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 @@ mod tests { 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 @@ mod tests { #[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); } } } diff --git a/src/libstd/str/ascii.rs b/src/libstd/str/ascii.rs index 3f24f98bd3d..f1ffa1b3bce 100644 --- a/src/libstd/str/ascii.rs +++ b/src/libstd/str/ascii.rs @@ -15,7 +15,9 @@ use str; 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 @@ impl<'self> AsciiCast<&'self[Ascii]> for &'self [u8] { } } -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 @@ impl OwnedAsciiCast for ~str { 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 @@ impl<'self> AsciiStr for &'self [Ascii] { } 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) } } } diff --git a/src/libstd/unstable/extfmt.rs b/src/libstd/unstable/extfmt.rs index 5417af50081..a08851df626 100644 --- a/src/libstd/unstable/extfmt.rs +++ b/src/libstd/unstable/extfmt.rs @@ -549,12 +549,14 @@ pub mod rt { // 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); } diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index d77a9f58a38..dffa7232e34 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -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; } } |
