From 2338d7419743f876135f723d1823dde16bdb7fdf Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 12 Feb 2016 12:21:57 -0500 Subject: [PATCH] Add Capacity/length methods for OsString. https://github.com/rust-lang/rust/issues/29453 --- src/libstd/ffi/os_str.rs | 178 +++++++++++++++++++++++++++++++ src/libstd/sys/common/wtf8.rs | 14 +++ src/libstd/sys/unix/os_str.rs | 41 +++++++ src/libstd/sys/windows/os_str.rs | 35 ++++++ 4 files changed, 268 insertions(+) diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index eb5ddecbd05..90ea7396a8a 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -102,6 +102,58 @@ impl OsString { pub fn push>(&mut self, s: T) { self.inner.push_slice(&s.as_ref().inner) } + + /// Creates a new `OsString` with the given capacity. The string will be + /// able to hold exactly `capacity` bytes without reallocating. If + /// `capacity` is 0, the string will not allocate. + /// + /// See main `OsString` documentation information about encoding. + #[unstable(feature = "osstring_simple_functions", + reason = "recently added", issue = "29453")] + pub fn with_capacity(capacity: usize) -> OsString { + OsString { + inner: Buf::with_capacity(capacity) + } + } + + /// Truncates the `OsString` to zero length. + #[unstable(feature = "osstring_simple_functions", + reason = "recently added", issue = "29453")] + pub fn clear(&mut self) { + self.inner.clear() + } + + /// Returns the number of bytes this `OsString` can hold without + /// reallocating. + /// + /// See `OsString` introduction for information about encoding. + #[unstable(feature = "osstring_simple_functions", + reason = "recently added", issue = "29453")] + pub fn capacity(&self) -> usize { + self.inner.capacity() + } + + /// Reserves capacity for at least `additional` more bytes to be inserted + /// in the given `OsString`. The collection may reserve more space to avoid + /// frequent reallocations. + #[unstable(feature = "osstring_simple_functions", + reason = "recently added", issue = "29453")] + pub fn reserve(&mut self, additional: usize) { + self.inner.reserve(additional) + } + + /// Reserves the minimum capacity for exactly `additional` more bytes to be + /// inserted in the given `OsString`. Does nothing if the capacity is + /// already sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore capacity can not be relied upon to be precisely + /// minimal. Prefer reserve if future insertions are expected. + #[unstable(feature = "osstring_simple_functions", + reason = "recently added", issue = "29453")] + pub fn reserve_exact(&mut self, additional: usize) { + self.inner.reserve_exact(additional) + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -277,6 +329,22 @@ impl OsStr { self.to_bytes().and_then(|b| CString::new(b).ok()) } + /// Checks whether the `OsStr` is empty. + #[unstable(feature = "osstring_simple_functions", + reason = "recently added", issue = "29453")] + pub fn is_empty(&self) -> bool { + self.inner.inner.is_empty() + } + + /// Returns the number of bytes in this `OsStr`. + /// + /// See `OsStr` introduction for information about encoding. + #[unstable(feature = "osstring_simple_functions", + reason = "recently added", issue = "29453")] + pub fn len(&self) -> usize { + self.inner.inner.len() + } + /// Gets the underlying byte representation. /// /// Note: it is *crucial* that this API is private, to avoid @@ -414,3 +482,113 @@ impl AsInner for OsStr { &self.inner } } + +#[cfg(test)] +mod tests { + use super::*; + use sys_common::{AsInner, IntoInner}; + + #[test] + fn test_os_string_with_capacity() { + let os_string = OsString::with_capacity(0); + assert_eq!(0, os_string.inner.into_inner().capacity()); + + let os_string = OsString::with_capacity(10); + assert_eq!(10, os_string.inner.into_inner().capacity()); + + let mut os_string = OsString::with_capacity(0); + os_string.push("abc"); + assert!(os_string.inner.into_inner().capacity() >= 3); + } + + #[test] + fn test_os_string_clear() { + let mut os_string = OsString::from("abc"); + assert_eq!(3, os_string.inner.as_inner().len()); + + os_string.clear(); + assert_eq!(&os_string, ""); + assert_eq!(0, os_string.inner.as_inner().len()); + } + + #[test] + fn test_os_string_capacity() { + let os_string = OsString::with_capacity(0); + assert_eq!(0, os_string.capacity()); + + let os_string = OsString::with_capacity(10); + assert_eq!(10, os_string.capacity()); + + let mut os_string = OsString::with_capacity(0); + os_string.push("abc"); + assert!(os_string.capacity() >= 3); + } + + #[test] + fn test_os_string_reserve() { + let mut os_string = OsString::new(); + assert_eq!(os_string.capacity(), 0); + + os_string.reserve(2); + assert!(os_string.capacity() >= 2); + + for _ in 0..16 { + os_string.push("a"); + } + + assert!(os_string.capacity() >= 16); + os_string.reserve(16); + assert!(os_string.capacity() >= 32); + + os_string.push("a"); + + os_string.reserve(16); + assert!(os_string.capacity() >= 33) + } + + #[test] + fn test_os_string_reserve_exact() { + let mut os_string = OsString::new(); + assert_eq!(os_string.capacity(), 0); + + os_string.reserve_exact(2); + assert!(os_string.capacity() >= 2); + + for _ in 0..16 { + os_string.push("a"); + } + + assert!(os_string.capacity() >= 16); + os_string.reserve_exact(16); + assert!(os_string.capacity() >= 32); + + os_string.push("a"); + + os_string.reserve_exact(16); + assert!(os_string.capacity() >= 33) + } + + #[test] + fn test_os_str_is_empty() { + let mut os_string = OsString::new(); + assert!(os_string.is_empty()); + + os_string.push("abc"); + assert!(!os_string.is_empty()); + + os_string.clear(); + assert!(os_string.is_empty()); + } + + #[test] + fn test_os_str_len() { + let mut os_string = OsString::new(); + assert_eq!(0, os_string.len()); + + os_string.push("abc"); + assert_eq!(3, os_string.len()); + + os_string.clear(); + assert_eq!(0, os_string.len()); + } +} diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index bc997af3a27..68ba2fe20b4 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -178,6 +178,10 @@ impl Wtf8Buf { Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()) } } + pub fn clear(&mut self) { + self.bytes.clear() + } + /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units. /// /// This is lossless: calling `.encode_wide()` on the resulting string @@ -234,6 +238,11 @@ impl Wtf8Buf { self.bytes.reserve(additional) } + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.bytes.reserve_exact(additional) + } + /// Returns the number of bytes that this string buffer can hold without reallocating. #[inline] pub fn capacity(&self) -> usize { @@ -443,6 +452,11 @@ impl Wtf8 { self.bytes.len() } + #[inline] + pub fn is_empty(&self) -> bool { + self.bytes.is_empty() + } + /// Returns the code point at `position` if it is in the ASCII range, /// or `b'\xFF' otherwise. /// diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index 0524df218a1..d5eea5d1f3b 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -17,6 +17,7 @@ use vec::Vec; use str; use string::String; use mem; +use sys_common::{AsInner, IntoInner}; #[derive(Clone, Hash)] pub struct Buf { @@ -39,11 +40,51 @@ impl Debug for Buf { } } +impl IntoInner> for Buf { + fn into_inner(self) -> Vec { + self.inner + } +} + +impl AsInner<[u8]> for Buf { + fn as_inner(&self) -> &[u8] { + &self.inner + } +} + + impl Buf { pub fn from_string(s: String) -> Buf { Buf { inner: s.into_bytes() } } + #[inline] + pub fn with_capacity(capacity: usize) -> Buf { + Buf { + inner: Vec::with_capacity(capacity) + } + } + + #[inline] + pub fn clear(&mut self) { + self.inner.clear() + } + + #[inline] + pub fn capacity(&self) -> usize { + self.inner.capacity() + } + + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.inner.reserve(additional) + } + + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.inner.reserve_exact(additional) + } + pub fn as_slice(&self) -> &Slice { unsafe { mem::transmute(&*self.inner) } } diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 91905ae7489..26767a1349e 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -18,12 +18,25 @@ use string::String; use result::Result; use option::Option; use mem; +use sys_common::{AsInner, IntoInner}; #[derive(Clone, Hash)] pub struct Buf { pub inner: Wtf8Buf } +impl IntoInner for Buf { + fn into_inner(self) -> Wtf8Buf { + self.inner + } +} + +impl AsInner for Buf { + fn as_inner(&self) -> &Wtf8 { + &self.inner + } +} + impl Debug for Buf { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { self.as_slice().fmt(formatter) @@ -41,6 +54,20 @@ impl Debug for Slice { } impl Buf { + pub fn with_capacity(capacity: usize) -> Buf { + Buf { + inner: Wtf8Buf::with_capacity(capacity) + } + } + + pub fn clear(&mut self) { + self.inner.clear() + } + + pub fn capacity(&self) -> usize { + self.inner.capacity() + } + pub fn from_string(s: String) -> Buf { Buf { inner: Wtf8Buf::from_string(s) } } @@ -56,6 +83,14 @@ impl Buf { pub fn push_slice(&mut self, s: &Slice) { self.inner.push_wtf8(&s.inner) } + + pub fn reserve(&mut self, additional: usize) { + self.inner.reserve(additional) + } + + pub fn reserve_exact(&mut self, additional: usize) { + self.inner.reserve_exact(additional) + } } impl Slice {