use std::sync::Arc;
const NUM_TILE_BUCKETS: usize = 6;
pub struct BlobTilePool {
largest_size_class: usize,
buckets: [Vec<Arc<Vec<u8>>>; NUM_TILE_BUCKETS],
}
impl BlobTilePool {
pub fn new() -> Self {
let max_tile_size = 512;
BlobTilePool {
largest_size_class: max_tile_size * max_tile_size * 4,
buckets: [
Vec::with_capacity(32),
Vec::with_capacity(32),
Vec::with_capacity(32),
Vec::with_capacity(32),
Vec::with_capacity(32),
Vec::with_capacity(32),
],
}
}
pub fn get_buffer(&mut self, requested_size: usize) -> MutableTileBuffer {
if requested_size > self.largest_size_class {
let mut buf = vec![0; requested_size];
return MutableTileBuffer {
ptr: buf.as_mut_ptr(),
strong_ref: Arc::new(buf),
};
}
let (bucket_idx, cap) = self.bucket_and_size(requested_size);
let bucket = &mut self.buckets[bucket_idx];
let mut selected_idx = None;
for (buf_idx, buffer) in bucket.iter().enumerate() {
if Arc::strong_count(buffer) == 1 {
selected_idx = Some(buf_idx);
break;
}
}
let ptr;
let strong_ref;
if let Some(idx) = selected_idx {
{
let buffer = Arc::get_mut(&mut bucket[idx]).unwrap();
debug_assert!(buffer.capacity() >= requested_size);
unsafe { buffer.set_len(requested_size); }
buffer.fill(0);
ptr = buffer.as_mut_ptr();
}
strong_ref = Arc::clone(&bucket[idx]);
} else {
let mut buf = vec![0; cap];
unsafe { buf.set_len(requested_size) };
ptr = buf.as_mut_ptr();
strong_ref = Arc::new(buf);
bucket.push(Arc::clone(&strong_ref));
};
MutableTileBuffer {
ptr,
strong_ref,
}
}
fn bucket_and_size(&self, size: usize) -> (usize, usize) {
let mut next_size_class = self.largest_size_class / 4;
let mut idx = 0;
while size < next_size_class && idx < NUM_TILE_BUCKETS - 1 {
next_size_class /= 4;
idx += 1;
}
(idx, next_size_class * 4)
}
pub fn cleanup(&mut self) {
for bucket in &mut self.buckets {
let threshold = bucket.len() / 2;
let mut num_available = 0;
bucket.retain(&mut |buffer: &Arc<Vec<u8>>| {
if Arc::strong_count(buffer) > 1 {
return true;
}
num_available += 1;
num_available < threshold
});
}
}
}
pub struct MutableTileBuffer {
strong_ref: Arc<Vec<u8>>,
ptr: *mut u8,
}
impl MutableTileBuffer {
pub fn as_mut_slice(&mut self) -> &mut[u8] {
unsafe { std::slice::from_raw_parts_mut(self.ptr, self.strong_ref.len()) }
}
pub fn into_arc(self) -> Arc<Vec<u8>> {
self.strong_ref
}
}
unsafe impl Send for MutableTileBuffer {}