I've been playing around with the allocator_api
. I have a custom allocator backed by a Vec<u8, Global>
. When I print the contents of the data
member, I'm expecting to see what I've allocated, but the data
is empty:
#![feature(allocator_api)]
use std::{alloc::Allocator, cell::RefCell, sync::Mutex};
#[derive(Debug)]
struct MyAllocator {
data: RefCell<Mutex<Vec<u8>>>,
used: RefCell<Mutex<usize>>,
}
impl MyAllocator {
fn new(capacity: usize) -> Self {
Self {
data: RefCell::new(Mutex::new(Vec::with_capacity(capacity))),
used: RefCell::new(Mutex::new(0)),
}
}
fn print(&self) {
let mutex = self.data.borrow_mut();
let data = mutex.lock().expect("could not lock allocator");
println!("==== data contents ====");
for d in data.chunks_exact(4) {
let num = i32::from_ne_bytes([d[0], d[1], d[2], d[3]]);
println!("{}", num);
}
println!("=======================");
}
}
unsafe impl Allocator for &MyAllocator {
fn allocate(
&self,
layout: std::alloc::Layout,
) -> Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError> {
unsafe {
let used = *self
.used
.borrow()
.lock()
.map_err(|_| std::alloc::AllocError)?;
let data = self
.data
.borrow_mut()
.lock()
.map_err(|_| std::alloc::AllocError)?
.as_mut_ptr()
.add(used);
*self
.used
.borrow_mut()
.lock()
.map_err(|_| std::alloc::AllocError)? += layout.size();
let ptr = std::ptr::slice_from_raw_parts_mut(data, layout.size());
std::ptr::NonNull::new(ptr).ok_or(std::alloc::AllocError)
}
}
unsafe fn deallocate(&self, _ptr: std::ptr::NonNull<u8>, _layout: std::alloc::Layout) {
// noop
}
unsafe fn shrink(
&self,
ptr: std::ptr::NonNull<u8>,
old_layout: std::alloc::Layout,
_new_layout: std::alloc::Layout,
) -> Result<std::ptr::NonNull<[u8]>, std::alloc::AllocError> {
// noop
let ptr = std::ptr::slice_from_raw_parts_mut(ptr.as_ptr(), old_layout.size());
std::ptr::NonNull::new(ptr).ok_or(std::alloc::AllocError)
}
}
fn main() {
let a = MyAllocator::new(40);
let mut v = Vec::with_capacity_in(4, &a);
v.push(7);
v.push(4);
v.push(1);
v.push(10);
v.sort_unstable();
for i in v {
println!("{}", i);
}
a.print();
}
Output:
1
4
7
10
==== data contents (0 items) ====
=================================
The allocations are clearly happening correctly, otherwise I'd not be able to get the data back out of the vector. Why is the data
member empty and where are my allocations actually going?