Skip to content

Commit 04f6692

Browse files
committed
Implement shrink_to method on collections
1 parent f5631d9 commit 04f6692

File tree

13 files changed

+237
-2
lines changed

13 files changed

+237
-2
lines changed

src/liballoc/binary_heap.rs

+25
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,31 @@ impl<T: Ord> BinaryHeap<T> {
509509
self.data.shrink_to_fit();
510510
}
511511

512+
/// Discards capacity with a lower bound.
513+
///
514+
/// The capacity will remain at least as large as both the length
515+
/// and the supplied value.
516+
///
517+
/// Panics if the current capacity is smaller than the supplied
518+
/// minimum capacity.
519+
///
520+
/// # Examples
521+
///
522+
/// ```
523+
/// #![feature(shrink_to)]
524+
/// use std::collections::BinaryHeap;
525+
/// let mut heap: BinaryHeap<i32> = BinaryHeap::with_capacity(100);
526+
///
527+
/// assert!(heap.capacity() >= 100);
528+
/// heap.shrink_to(10);
529+
/// assert!(heap.capacity() >= 10);
530+
/// ```
531+
#[inline]
532+
#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
533+
pub fn shrink_to(&mut self, min_capacity: usize) {
534+
self.data.shrink_to(min_capacity)
535+
}
536+
512537
/// Removes the greatest item from the binary heap and returns it, or `None` if it
513538
/// is empty.
514539
///

src/liballoc/string.rs

+28
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,34 @@ impl String {
10151015
self.vec.shrink_to_fit()
10161016
}
10171017

1018+
/// Shrinks the capacity of this `String` with a lower bound.
1019+
///
1020+
/// The capacity will remain at least as large as both the length
1021+
/// and the supplied value.
1022+
///
1023+
/// Panics if the current capacity is smaller than the supplied
1024+
/// minimum capacity.
1025+
///
1026+
/// # Examples
1027+
///
1028+
/// ```
1029+
/// #![feature(shrink_to)]
1030+
/// let mut s = String::from("foo");
1031+
///
1032+
/// s.reserve(100);
1033+
/// assert!(s.capacity() >= 100);
1034+
///
1035+
/// s.shrink_to(10);
1036+
/// assert!(s.capacity() >= 10);
1037+
/// s.shrink_to(0);
1038+
/// assert!(s.capacity() >= 3);
1039+
/// ```
1040+
#[inline]
1041+
#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
1042+
pub fn shrink_to(&mut self, min_capacity: usize) {
1043+
self.vec.shrink_to(min_capacity)
1044+
}
1045+
10181046
/// Appends the given [`char`] to the end of this `String`.
10191047
///
10201048
/// [`char`]: ../../std/primitive.char.html

src/liballoc/vec.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
6767
#![stable(feature = "rust1", since = "1.0.0")]
6868

69-
use core::cmp::Ordering;
69+
use core::cmp::{self, Ordering};
7070
use core::fmt;
7171
use core::hash::{self, Hash};
7272
use core::intrinsics::{arith_offset, assume};
@@ -586,6 +586,31 @@ impl<T> Vec<T> {
586586
self.buf.shrink_to_fit(self.len);
587587
}
588588

589+
/// Shrinks the capacity of the vector with a lower bound.
590+
///
591+
/// The capacity will remain at least as large as both the length
592+
/// and the supplied value.
593+
///
594+
/// Panics if the current capacity is smaller than the supplied
595+
/// minimum capacity.
596+
///
597+
/// # Examples
598+
///
599+
/// ```
600+
/// #![feature(shrink_to)]
601+
/// let mut vec = Vec::with_capacity(10);
602+
/// vec.extend([1, 2, 3].iter().cloned());
603+
/// assert_eq!(vec.capacity(), 10);
604+
/// vec.shrink_to(4);
605+
/// assert!(vec.capacity() >= 4);
606+
/// vec.shrink_to(0);
607+
/// assert!(vec.capacity() >= 3);
608+
/// ```
609+
#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
610+
pub fn shrink_to(&mut self, min_capacity: usize) {
611+
self.buf.shrink_to_fit(cmp::max(self.len, min_capacity));
612+
}
613+
589614
/// Converts the vector into [`Box<[T]>`][owned slice].
590615
///
591616
/// Note that this will drop any excess capacity.

src/liballoc/vec_deque.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -676,9 +676,42 @@ impl<T> VecDeque<T> {
676676
/// ```
677677
#[stable(feature = "deque_extras_15", since = "1.5.0")]
678678
pub fn shrink_to_fit(&mut self) {
679+
self.shrink_to(0);
680+
}
681+
682+
/// Shrinks the capacity of the `VecDeque` with a lower bound.
683+
///
684+
/// The capacity will remain at least as large as both the length
685+
/// and the supplied value.
686+
///
687+
/// Panics if the current capacity is smaller than the supplied
688+
/// minimum capacity.
689+
///
690+
/// # Examples
691+
///
692+
/// ```
693+
/// #![feature(shrink_to)]
694+
/// use std::collections::VecDeque;
695+
///
696+
/// let mut buf = VecDeque::with_capacity(15);
697+
/// buf.extend(0..4);
698+
/// assert_eq!(buf.capacity(), 15);
699+
/// buf.shrink_to(6);
700+
/// assert!(buf.capacity() >= 6);
701+
/// buf.shrink_to(0);
702+
/// assert!(buf.capacity() >= 4);
703+
/// ```
704+
#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
705+
pub fn shrink_to(&mut self, min_capacity: usize) {
706+
assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity");
707+
679708
// +1 since the ringbuffer always leaves one space empty
680709
// len + 1 can't overflow for an existing, well-formed ringbuffer.
681-
let target_cap = cmp::max(self.len() + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
710+
let target_cap = cmp::max(
711+
cmp::max(min_capacity, self.len()) + 1,
712+
MINIMUM_CAPACITY + 1
713+
).next_power_of_two();
714+
682715
if target_cap < self.cap() {
683716
// There are three cases of interest:
684717
// All elements are out of desired bounds

src/libstd/collections/hash/map.rs

+40
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,46 @@ impl<K, V, S> HashMap<K, V, S>
910910
}
911911
}
912912

913+
/// Shrinks the capacity of the map with a lower limit. It will drop
914+
/// down no lower than the supplied limit while maintaining the internal rules
915+
/// and possibly leaving some space in accordance with the resize policy.
916+
///
917+
/// Panics if the current capacity is smaller than the supplied
918+
/// minimum capacity.
919+
///
920+
/// # Examples
921+
///
922+
/// ```
923+
/// #![feature(shrink_to)]
924+
/// use std::collections::HashMap;
925+
///
926+
/// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100);
927+
/// map.insert(1, 2);
928+
/// map.insert(3, 4);
929+
/// assert!(map.capacity() >= 100);
930+
/// map.shrink_to(10);
931+
/// assert!(map.capacity() >= 10);
932+
/// map.shrink_to(0);
933+
/// assert!(map.capacity() >= 2);
934+
/// ```
935+
#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
936+
pub fn shrink_to(&mut self, min_capacity: usize) {
937+
assert!(self.capacity() >= min_capacity, "Tried to shrink to a larger capacity");
938+
939+
let new_raw_cap = self.resize_policy.raw_capacity(max(self.len(), min_capacity));
940+
if self.raw_capacity() != new_raw_cap {
941+
let old_table = replace(&mut self.table, RawTable::new(new_raw_cap));
942+
let old_size = old_table.size();
943+
944+
// Shrink the table. Naive algorithm for resizing:
945+
for (h, k, v) in old_table.into_iter() {
946+
self.insert_hashed_nocheck(h, k, v);
947+
}
948+
949+
debug_assert_eq!(self.table.size(), old_size);
950+
}
951+
}
952+
913953
/// Insert a pre-hashed key-value pair, without first checking
914954
/// that there's enough room in the buckets. Returns a reference to the
915955
/// newly insert value.

src/libstd/collections/hash/set.rs

+28
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,34 @@ impl<T, S> HashSet<T, S>
292292
self.map.shrink_to_fit()
293293
}
294294

295+
/// Shrinks the capacity of the set with a lower limit. It will drop
296+
/// down no lower than the supplied limit while maintaining the internal rules
297+
/// and possibly leaving some space in accordance with the resize policy.
298+
///
299+
/// Panics if the current capacity is smaller than the supplied
300+
/// minimum capacity.
301+
///
302+
/// # Examples
303+
///
304+
/// ```
305+
/// #![feature(shrink_to)]
306+
/// use std::collections::HashSet;
307+
///
308+
/// let mut set = HashSet::with_capacity(100);
309+
/// set.insert(1);
310+
/// set.insert(2);
311+
/// assert!(set.capacity() >= 100);
312+
/// set.shrink_to(10);
313+
/// assert!(set.capacity() >= 10);
314+
/// set.shrink_to(0);
315+
/// assert!(set.capacity() >= 2);
316+
/// ```
317+
#[inline]
318+
#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
319+
pub fn shrink_to(&mut self, min_capacity: usize) {
320+
self.map.shrink_to(min_capacity)
321+
}
322+
295323
/// An iterator visiting all elements in arbitrary order.
296324
/// The iterator element type is `&'a T`.
297325
///

src/libstd/ffi/os_str.rs

+30
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,36 @@ impl OsString {
295295
self.inner.shrink_to_fit()
296296
}
297297

298+
/// Shrinks the capacity of the `OsString` with a lower bound.
299+
///
300+
/// The capacity will remain at least as large as both the length
301+
/// and the supplied value.
302+
///
303+
/// Panics if the current capacity is smaller than the supplied
304+
/// minimum capacity.
305+
///
306+
/// # Examples
307+
///
308+
/// ```
309+
/// #![feature(shrink_to)]
310+
/// use std::ffi::OsString;
311+
///
312+
/// let mut s = OsString::from("foo");
313+
///
314+
/// s.reserve(100);
315+
/// assert!(s.capacity() >= 100);
316+
///
317+
/// s.shrink_to(10);
318+
/// assert!(s.capacity() >= 10);
319+
/// s.shrink_to(0);
320+
/// assert!(s.capacity() >= 3);
321+
/// ```
322+
#[inline]
323+
#[unstable(feature = "shrink_to", reason = "new API", issue="0")]
324+
pub fn shrink_to(&mut self, min_capacity: usize) {
325+
self.inner.shrink_to(min_capacity)
326+
}
327+
298328
/// Converts this `OsString` into a boxed [`OsStr`].
299329
///
300330
/// [`OsStr`]: struct.OsStr.html

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@
299299
#![feature(raw)]
300300
#![feature(rustc_attrs)]
301301
#![feature(stdsimd)]
302+
#![feature(shrink_to)]
302303
#![feature(slice_bytes)]
303304
#![feature(slice_concat_ext)]
304305
#![feature(slice_internals)]

src/libstd/sys/redox/os_str.rs

+5
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ impl Buf {
104104
self.inner.shrink_to_fit()
105105
}
106106

107+
#[inline]
108+
pub fn shrink_to(&mut self, min_capacity: usize) {
109+
self.inner.shrink_to(min_capacity)
110+
}
111+
107112
pub fn as_slice(&self) -> &Slice {
108113
unsafe { mem::transmute(&*self.inner) }
109114
}

src/libstd/sys/unix/os_str.rs

+5
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ impl Buf {
104104
self.inner.shrink_to_fit()
105105
}
106106

107+
#[inline]
108+
pub fn shrink_to(&mut self, min_capacity: usize) {
109+
self.inner.shrink_to(min_capacity)
110+
}
111+
107112
pub fn as_slice(&self) -> &Slice {
108113
unsafe { mem::transmute(&*self.inner) }
109114
}

src/libstd/sys/wasm/os_str.rs

+5
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ impl Buf {
104104
self.inner.shrink_to_fit()
105105
}
106106

107+
#[inline]
108+
pub fn shrink_to(&mut self, min_capacity: usize) {
109+
self.inner.shrink_to(min_capacity)
110+
}
111+
107112
pub fn as_slice(&self) -> &Slice {
108113
unsafe { mem::transmute(&*self.inner) }
109114
}

src/libstd/sys/windows/os_str.rs

+5
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ impl Buf {
113113
self.inner.shrink_to_fit()
114114
}
115115

116+
#[inline]
117+
pub fn shrink_to(&mut self, min_capacity: usize) {
118+
self.inner.shrink_to(min_capacity)
119+
}
120+
116121
#[inline]
117122
pub fn into_box(self) -> Box<Slice> {
118123
unsafe { mem::transmute(self.inner.into_box()) }

src/libstd/sys_common/wtf8.rs

+5
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@ impl Wtf8Buf {
253253
self.bytes.shrink_to_fit()
254254
}
255255

256+
#[inline]
257+
pub fn shrink_to(&mut self, min_capacity: usize) {
258+
self.bytes.shrink_to(min_capacity)
259+
}
260+
256261
/// Returns the number of bytes that this string buffer can hold without reallocating.
257262
#[inline]
258263
pub fn capacity(&self) -> usize {

0 commit comments

Comments
 (0)