Skip to content

Commit 8622c78

Browse files
implement realloc and debug
1 parent 210cf73 commit 8622c78

File tree

3 files changed

+112
-3
lines changed

3 files changed

+112
-3
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ is-it-maintained-issue-resolution = { repository = "dignifiedquire/byte-pool" }
1313
is-it-maintained-open-issues = { repository = "dignifiedquire/byte-pool" }
1414

1515
[dependencies]
16+
stable_deref_trait = { version = "1.1.1", optional = true }
17+
18+
[features]
19+
default = ["stable_deref"]
20+
stable_deref = ["stable_deref_trait"]

benches/main.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,32 @@ fn pool_mixed(b: &mut Bencher) {
7272
i += 1;
7373
});
7474
}
75+
76+
#[bench]
77+
fn base_vec_grow(b: &mut Bencher) {
78+
let mut size = 16;
79+
80+
b.iter(|| {
81+
let mut buf = vec![0u8; size];
82+
touch_obj(&mut buf, size);
83+
84+
size = (size * 2).min(4 * 1024);
85+
buf.resize(size, 0);
86+
touch_obj(&mut buf, size);
87+
});
88+
}
89+
90+
#[bench]
91+
fn pool_grow(b: &mut Bencher) {
92+
let mut size = 16;
93+
let pool = BytePool::new();
94+
95+
b.iter(|| {
96+
let mut buf = pool.alloc(size);
97+
touch_obj(&mut buf, size);
98+
99+
size = (size * 2).min(4 * 1024);
100+
buf.realloc(size);
101+
touch_obj(&mut buf, size);
102+
});
103+
}

src/lib.rs

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@
2525
//! drop(pool);
2626
//! ```
2727
28-
use std::alloc::{alloc, dealloc, handle_alloc_error, Layout};
28+
use std::alloc::{alloc, dealloc, handle_alloc_error, realloc, Layout};
29+
use std::fmt;
2930
use std::mem;
3031
use std::ops::{Deref, DerefMut};
3132
use std::ptr::{self, NonNull};
3233
use std::sync::Mutex;
3334

3435
/// A pool of byte slices, that reuses memory.
36+
#[derive(Debug)]
3537
pub struct BytePool {
3638
list: Mutex<Vec<RawBlock>>,
3739
}
@@ -41,11 +43,29 @@ pub struct RawBlock {
4143
layout: Layout,
4244
}
4345

46+
unsafe impl Sync for RawBlock {}
47+
unsafe impl Send for RawBlock {}
48+
49+
#[cfg(feature = "stable_deref")]
50+
unsafe impl stable_deref_trait::StableDeref for RawBlock {}
51+
4452
pub struct Block<'a> {
4553
data: mem::ManuallyDrop<RawBlock>,
4654
pool: &'a BytePool,
4755
}
4856

57+
impl fmt::Debug for Block<'_> {
58+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59+
f.debug_struct("Block").field("data", &self.data).finish()
60+
}
61+
}
62+
63+
impl fmt::Debug for RawBlock {
64+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65+
write!(f, "RawBlock({:?})", self.deref())
66+
}
67+
}
68+
4969
impl Default for BytePool {
5070
fn default() -> Self {
5171
BytePool {
@@ -103,7 +123,7 @@ impl<'a> Drop for Block<'a> {
103123
}
104124

105125
impl RawBlock {
106-
pub fn alloc(size: usize) -> Self {
126+
fn alloc(size: usize) -> Self {
107127
// TODO: consider caching the layout
108128
let layout = layout_for_size(size);
109129
debug_assert!(layout.size() > 0);
@@ -114,6 +134,24 @@ impl RawBlock {
114134
layout,
115135
}
116136
}
137+
138+
fn grow(&mut self, new_size: usize) {
139+
// TODO: use grow_in_place once it stablizies and possibly via a flag.
140+
assert!(new_size > 0);
141+
let new_layout = Layout::from_size_align(new_size, self.layout.align()).unwrap();
142+
let new_ptr = unsafe { realloc(self.ptr.as_mut(), self.layout, new_layout.size()) };
143+
self.ptr = NonNull::new(new_ptr).unwrap_or_else(|| handle_alloc_error(self.layout));
144+
self.layout = new_layout;
145+
}
146+
147+
fn shrink(&mut self, new_size: usize) {
148+
// TODO: use shrink_in_place once it stablizies and possibly via a flag.
149+
assert!(new_size > 0);
150+
let new_layout = Layout::from_size_align(new_size, self.layout.align()).unwrap();
151+
let new_ptr = unsafe { realloc(self.ptr.as_mut(), self.layout, new_layout.size()) };
152+
self.ptr = NonNull::new(new_ptr).unwrap_or_else(|| handle_alloc_error(self.layout));
153+
self.layout = new_layout;
154+
}
117155
}
118156

119157
impl Drop for RawBlock {
@@ -141,12 +179,26 @@ impl DerefMut for RawBlock {
141179
}
142180

143181
impl<'a> Block<'a> {
144-
pub fn new(data: RawBlock, pool: &'a BytePool) -> Self {
182+
fn new(data: RawBlock, pool: &'a BytePool) -> Self {
145183
Block {
146184
data: mem::ManuallyDrop::new(data),
147185
pool,
148186
}
149187
}
188+
189+
/// Resizes a block to a new size
190+
pub fn realloc(&mut self, new_size: usize) {
191+
if new_size < self.size() {
192+
self.data.shrink(new_size);
193+
} else if new_size > self.size() {
194+
self.data.grow(new_size);
195+
}
196+
}
197+
198+
/// Returns the amount of bytes this block has.
199+
pub fn size(&self) -> usize {
200+
self.data.layout.size()
201+
}
150202
}
151203

152204
impl<'a> Deref for Block<'a> {
@@ -194,4 +246,27 @@ mod tests {
194246
}
195247
}
196248
}
249+
250+
#[test]
251+
fn realloc() {
252+
let pool = BytePool::new();
253+
254+
let mut buf = pool.alloc(10);
255+
assert_eq!(buf.len(), 10);
256+
for el in buf.iter_mut() {
257+
*el = 1;
258+
}
259+
260+
buf.realloc(512);
261+
assert_eq!(buf.len(), 512);
262+
for el in buf.iter().take(10) {
263+
assert_eq!(*el, 1);
264+
}
265+
266+
buf.realloc(5);
267+
assert_eq!(buf.len(), 5);
268+
for el in buf.iter() {
269+
assert_eq!(*el, 1);
270+
}
271+
}
197272
}

0 commit comments

Comments
 (0)