7
7
//! // Create a pool
8
8
//! let pool = BytePool::new();
9
9
//!
10
- //! // Allocate a buffer
10
+ //! // Allocate a buffer with capacity 1024.
11
11
//! let mut buf = pool.alloc(1024);
12
12
//!
13
13
//! // write some data into it
@@ -37,8 +37,9 @@ pub struct BytePool {
37
37
list : Mutex < Vec < Vec < u8 > > > ,
38
38
}
39
39
40
- pub type RawBlock = Vec < u8 > ;
41
-
40
+ /// The value returned by an allocation of the pool.
41
+ /// When it is dropped the memory gets returned into the pool, and is not zeroed.
42
+ /// If that is a concern, you must clear the data yourself.
42
43
pub struct Block < ' a > {
43
44
data : mem:: ManuallyDrop < Vec < u8 > > ,
44
45
pool : & ' a BytePool ,
@@ -66,6 +67,8 @@ impl BytePool {
66
67
67
68
/// Allocates a new `Block`, which represents a fixed sice byte slice.
68
69
/// If `Block` is dropped, the memory is _not_ freed, but rather it is returned into the pool.
70
+ /// The returned `Block` contains arbitrary data, and must be zeroed or overwritten,
71
+ /// in cases this is needed.
69
72
pub fn alloc ( & self , size : usize ) -> Block < ' _ > {
70
73
assert ! ( size > 0 , "Can not allocate empty blocks" ) ;
71
74
@@ -75,9 +78,10 @@ impl BytePool {
75
78
let start = if end > 4 { end - 4 } else { 0 } ;
76
79
77
80
for i in start..end {
78
- if lock[ i] . len ( ) == size {
81
+ if lock[ i] . capacity ( ) == size {
79
82
// found one, reuse it
80
- return Block :: new ( lock. remove ( i) , self ) ;
83
+ let data = lock. remove ( i) ;
84
+ return Block :: new ( data, self ) ;
81
85
}
82
86
}
83
87
drop ( lock) ;
@@ -114,7 +118,10 @@ impl<'a> Block<'a> {
114
118
assert ! ( new_size > 0 ) ;
115
119
match new_size. cmp ( & self . size ( ) ) {
116
120
Greater => self . data . resize ( new_size, 0u8 ) ,
117
- Less => self . data . truncate ( new_size) ,
121
+ Less => {
122
+ self . data . truncate ( new_size) ;
123
+ self . shrink_to_fit ( ) ;
124
+ }
118
125
Equal => { }
119
126
}
120
127
}
@@ -179,21 +186,48 @@ mod tests {
179
186
180
187
let _slice: & [ u8 ] = & buf;
181
188
182
- assert_eq ! ( buf. len ( ) , 10 ) ;
183
- for el in buf . iter_mut ( ) {
184
- * el = 1 ;
189
+ assert_eq ! ( buf. capacity ( ) , 10 ) ;
190
+ for i in 0 .. 10 {
191
+ buf [ i ] = 1 ;
185
192
}
186
193
187
194
buf. realloc ( 512 ) ;
188
- assert_eq ! ( buf. len ( ) , 512 ) ;
195
+ assert_eq ! ( buf. capacity ( ) , 512 ) ;
189
196
for el in buf. iter ( ) . take ( 10 ) {
190
197
assert_eq ! ( * el, 1 ) ;
191
198
}
192
199
193
200
buf. realloc ( 5 ) ;
194
- assert_eq ! ( buf. len ( ) , 5 ) ;
201
+ assert_eq ! ( buf. capacity ( ) , 5 ) ;
195
202
for el in buf. iter ( ) {
196
203
assert_eq ! ( * el, 1 ) ;
197
204
}
198
205
}
206
+
207
+ #[ test]
208
+ fn multi_thread ( ) {
209
+ let pool = std:: sync:: Arc :: new ( BytePool :: new ( ) ) ;
210
+
211
+ let pool1 = pool. clone ( ) ;
212
+ let h1 = std:: thread:: spawn ( move || {
213
+ for _ in 0 ..100 {
214
+ let mut buf = pool1. alloc ( 64 ) ;
215
+ buf[ 10 ] = 10 ;
216
+ }
217
+ } ) ;
218
+
219
+ let pool2 = pool. clone ( ) ;
220
+ let h2 = std:: thread:: spawn ( move || {
221
+ for _ in 0 ..100 {
222
+ let mut buf = pool2. alloc ( 64 ) ;
223
+ buf[ 10 ] = 10 ;
224
+ }
225
+ } ) ;
226
+
227
+ h1. join ( ) . unwrap ( ) ;
228
+ h2. join ( ) . unwrap ( ) ;
229
+
230
+ // two threads allocating in parallel will need 2 buffers
231
+ assert_eq ! ( pool. list. lock( ) . unwrap( ) . len( ) , 2 ) ;
232
+ }
199
233
}
0 commit comments