Remove trailing null from strings
This commit is contained in:
parent
17e0089856
commit
5865a7597b
@ -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);
|
||||
}
|
||||
|
@ -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)])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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 ]));
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user