Skip to content

Commit 87e91e6

Browse files
committed
add ctor/dtors: new_in, from_raw_parts_in, etc
Yes, you could just use `unsafe { from_utf8_unchecked }``, but people get antsy about `unsafe`, so add some Vec ctor/dtor equivalents.
1 parent 6c317a3 commit 87e91e6

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed

library/alloc/src/string.rs

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,97 @@ impl String {
936936
}
937937

938938
impl<A: Allocator> generic::String<A> {
939+
/// Creates a new empty `String`.
940+
///
941+
/// Given that the `String` is empty, this will not allocate any initial
942+
/// buffer. While that means that this initial operation is very
943+
/// inexpensive, it may cause excessive allocation later when you add
944+
/// data. If you have an idea of how much data the `String` will hold,
945+
/// consider the [`with_capacity_in`] method to prevent excessive
946+
/// re-allocation.
947+
///
948+
/// [`with_capacity_in`]: String::with_capacity_in
949+
///
950+
/// # Examples
951+
///
952+
/// ```
953+
/// #![feature(allocator_api)]
954+
///
955+
/// use std::alloc::System;
956+
/// use std::string::generic::String;
957+
///
958+
/// # #[allow(unused_mut)]
959+
/// let mut s = String::new_in(System);
960+
/// ```
961+
#[inline]
962+
#[unstable(feature = "allocator_api", issue = "32838")]
963+
#[must_use]
964+
pub const fn new_in(alloc: A) -> Self {
965+
generic::String { vec: Vec::new_in(alloc) }
966+
}
967+
968+
/// Creates a new empty `String` with at least the specified capacity in the specified allocator.
969+
///
970+
/// `String`s have an internal buffer to hold their data. The capacity is
971+
/// the length of that buffer, and can be queried with the [`capacity`]
972+
/// method. This method creates an empty `String`, but one with an initial
973+
/// buffer that can hold at least `capacity` bytes. This is useful when you
974+
/// may be appending a bunch of data to the `String`, reducing the number of
975+
/// reallocations it needs to do.
976+
///
977+
/// [`capacity`]: String::capacity
978+
///
979+
/// If the given capacity is `0`, no allocation will occur, and this method
980+
/// is identical to the [`new_in`] method.
981+
///
982+
/// [`new_in`]: String::new_in
983+
///
984+
/// # Examples
985+
///
986+
/// ```
987+
/// #![feature(allocator_api)]
988+
///
989+
/// use std::alloc::System;
990+
/// use std::string::generic::String;
991+
///
992+
/// let mut s = String::with_capacity_in(10, System);
993+
///
994+
/// // The String contains no chars, even though it has capacity for more
995+
/// assert_eq!(s.len(), 0);
996+
///
997+
/// // These are all done without reallocating...
998+
/// let cap = s.capacity();
999+
/// for _ in 0..10 {
1000+
/// s.push('a');
1001+
/// }
1002+
///
1003+
/// assert_eq!(s.capacity(), cap);
1004+
///
1005+
/// // ...but this may make the string reallocate
1006+
/// s.push('a');
1007+
/// ```
1008+
#[inline]
1009+
#[cfg(not(no_global_oom_handling))]
1010+
#[unstable(feature = "allocator_api", issue = "32838")]
1011+
#[must_use]
1012+
pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
1013+
generic::String { vec: Vec::with_capacity_in(capacity, alloc) }
1014+
}
1015+
1016+
/// Creates a new empty `String` with at least the specified capacity, in the specified allocator.
1017+
///
1018+
/// # Errors
1019+
///
1020+
/// Returns [`Err`] if the capacity exceeds `isize::MAX` bytes,
1021+
/// or if the memory allocator reports failure.
1022+
///
1023+
#[inline]
1024+
#[unstable(feature = "allocator_api", issue = "32838")]
1025+
// #[unstable(feature = "try_with_capacity", issue = "91913")]
1026+
pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
1027+
Ok(generic::String { vec: Vec::try_with_capacity_in(capacity, alloc)? })
1028+
}
1029+
9391030
/// Converts a vector of bytes to a `String`.
9401031
///
9411032
/// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes
@@ -2185,6 +2276,94 @@ impl<A: Allocator> generic::String<A> {
21852276
unsafe { from_boxed_utf8_unchecked(slice) }
21862277
}
21872278

2279+
/// Decomposes a `String` into its raw components: `(pointer, length, capacity, allocator)`.
2280+
///
2281+
/// Returns the raw pointer to the underlying data, the length of
2282+
/// the string (in bytes), the allocated capacity of the data
2283+
/// (in bytes), and the allocator storing the bytes. These are the same arguments in the same order as
2284+
/// the arguments to [`from_raw_parts_in`].
2285+
///
2286+
/// After calling this function, the caller is responsible for the
2287+
/// memory previously managed by the `String`. The only way to do
2288+
/// this is to convert the raw pointer, length, and capacity back
2289+
/// into a `String` with the [`from_raw_parts_in`] function, allowing
2290+
/// the destructor to perform the cleanup.
2291+
///
2292+
/// [`from_raw_parts_in`]: String::from_raw_parts_in
2293+
///
2294+
/// # Examples
2295+
///
2296+
/// ```
2297+
/// #![feature(allocator_api)]
2298+
///
2299+
/// use std::alloc::System;
2300+
/// use std::string::generic::String;
2301+
///
2302+
/// let mut s = String::new_in(System);
2303+
/// s.push_str("hello");
2304+
///
2305+
/// let (ptr, len, cap, alloc) = s.into_raw_parts_with_alloc();
2306+
///
2307+
/// let rebuilt = unsafe { String::from_raw_parts_in(ptr, len, cap, alloc) };
2308+
/// assert_eq!(rebuilt, "hello");
2309+
/// ```
2310+
#[inline]
2311+
#[must_use = "losing the pointer will leak memory"]
2312+
#[unstable(feature = "allocator_api", issue = "32838")]
2313+
pub fn into_raw_parts_with_alloc(self) -> (*mut u8, usize, usize, A) {
2314+
self.vec.into_raw_parts_with_alloc()
2315+
}
2316+
2317+
/// Creates a new `String` from a pointer, a length, a capacity, and an allocator.
2318+
///
2319+
/// # Safety
2320+
///
2321+
/// This is highly unsafe, due to the number of invariants that aren't
2322+
/// checked:
2323+
///
2324+
/// * all safety requirements for [`Vec::<u8>::from_raw_parts_in`].
2325+
/// * all safety requirements for [`String::from_utf8_unchecked`].
2326+
///
2327+
/// Violating these may cause problems like corrupting the allocator's
2328+
/// internal data structures. For example, it is normally **not** safe to
2329+
/// build a `String` from a pointer to a C `char` array containing UTF-8
2330+
/// _unless_ you are certain that array is [*currently allocated*] via the given allocator `alloc`.
2331+
///
2332+
/// The ownership of `buf` is effectively transferred to the
2333+
/// `String` which may then deallocate, reallocate or change the
2334+
/// contents of memory pointed to by the pointer at will. Ensure
2335+
/// that nothing else uses the pointer after calling this
2336+
/// function.
2337+
///
2338+
/// # Examples
2339+
///
2340+
/// ```
2341+
/// #![feature(allocator_api)]
2342+
///
2343+
/// use std::alloc::System;
2344+
/// use std::string::generic::String;
2345+
///
2346+
/// let mut s = String::new_in(System);
2347+
/// s.push_str("hello");
2348+
///
2349+
/// // Deconstruct the String into parts.
2350+
/// let (ptr, len, capacity, alloc) = s.into_raw_parts_with_alloc();
2351+
///
2352+
/// let rebuilt = unsafe { String::from_raw_parts_in(ptr, len, capacity, alloc) };
2353+
/// assert_eq!(rebuilt, "hello");
2354+
/// ```
2355+
#[inline]
2356+
#[unstable(feature = "allocator_api", issue = "32838")]
2357+
pub unsafe fn from_raw_parts_in(
2358+
ptr: *mut u8,
2359+
length: usize,
2360+
capacity: usize,
2361+
alloc: A,
2362+
) -> Self {
2363+
let vec = unsafe { Vec::from_raw_parts_in(ptr, length, capacity, alloc) };
2364+
generic::String { vec }
2365+
}
2366+
21882367
/// Consumes and leaks the `String`, returning a mutable reference to the contents,
21892368
/// `&'a mut str`.
21902369
///

0 commit comments

Comments
 (0)