-
Notifications
You must be signed in to change notification settings - Fork 824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Array::shrink_to_fit(&mut self)
#6790
Changes from 12 commits
4977c53
aeb7fe4
e010cc9
18acd88
93d07f7
3f5c6e7
74cc447
8c0cfe4
e7c1ba7
b843ae2
bc8c761
3b7cdeb
4e92782
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -167,6 +167,41 @@ impl Buffer { | |
self.data.capacity() | ||
} | ||
|
||
/// Tried to shrink the capacity of the buffer as much as possible, freeing unused memory. | ||
/// | ||
/// If the buffer is shared, this is a no-op. | ||
/// | ||
/// If the memory was allocated with a custom allocator, this is a no-op. | ||
/// | ||
/// If the capacity is already less than or equal to the desired capacity, this is a no-op. | ||
/// | ||
/// The memory region will be reallocated using `std::alloc::realloc`. | ||
pub fn shrink_to_fit(&mut self) { | ||
let offset = self.ptr_offset(); | ||
let is_empty = self.is_empty(); | ||
let desired_capacity = if is_empty { | ||
0 | ||
} else { | ||
// For realloc to work, we cannot free the elements before the offset | ||
offset + self.len() | ||
}; | ||
if desired_capacity < self.capacity() { | ||
if let Some(bytes) = Arc::get_mut(&mut self.data) { | ||
if bytes.try_realloc(desired_capacity).is_ok() { | ||
// Realloc complete - update our pointer into `bytes`: | ||
self.ptr = if is_empty { | ||
bytes.as_ptr() | ||
} else { | ||
// SAFETY: we kept all elements leading up to the offset | ||
unsafe { bytes.as_ptr().add(offset) } | ||
} | ||
} else { | ||
// Failure to reallocate is fine; we just failed to free up memory. | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// Returns whether the buffer is empty. | ||
#[inline] | ||
pub fn is_empty(&self) -> bool { | ||
|
@@ -554,6 +589,34 @@ mod tests { | |
assert_eq!(buf2.slice_with_length(2, 1).as_slice(), &[10]); | ||
} | ||
|
||
#[test] | ||
fn test_shrink_to_fit() { | ||
let original = Buffer::from(&[0, 1, 2, 3, 4, 5, 6, 7]); | ||
assert_eq!(original.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7]); | ||
assert_eq!(original.capacity(), 64); | ||
|
||
let slice = original.slice_with_length(2, 3); | ||
drop(original); // Make sure the buffer isn't shared (or shrink_to_fit won't work) | ||
assert_eq!(slice.as_slice(), &[2, 3, 4]); | ||
assert_eq!(slice.capacity(), 64); | ||
|
||
let mut shrunk = slice; | ||
shrunk.shrink_to_fit(); | ||
assert_eq!(shrunk.as_slice(), &[2, 3, 4]); | ||
assert_eq!(shrunk.capacity(), 5); // shrink_to_fit is allowed to keep the elements before the offset | ||
|
||
// Test that we can handle empty slices: | ||
let empty_slice = shrunk.slice_with_length(1, 0); | ||
drop(shrunk); // Make sure the buffer isn't shared (or shrink_to_fit won't work) | ||
assert_eq!(empty_slice.as_slice(), &[]); | ||
assert_eq!(empty_slice.capacity(), 5); | ||
|
||
let mut shrunk_empty = empty_slice; | ||
shrunk_empty.shrink_to_fit(); | ||
assert_eq!(shrunk_empty.as_slice(), &[]); | ||
assert_eq!(shrunk_empty.capacity(), 1); // NOTE: `Buffer` and `Bytes` doesn't support 0-capacity | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They should do, but IIRC you need to use a dangling ptr, there should be some examples of this... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added in #6817 |
||
} | ||
|
||
#[test] | ||
#[should_panic(expected = "the offset of the new Buffer cannot exceed the existing length")] | ||
fn test_slice_offset_out_of_bound() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooops… my editor is set to trim trailing whitspace on save. Let me know if you want me to reverse.