use crate::vm::Int;
use std::mem::take;
use std::slice;
#[derive(Debug, Default)]
pub struct Mem {
base: Box<[Int<4>]>,
}
impl Mem {
pub const DEFAULT_SIZE: usize = 256;
pub const MAX_CAPACITY: usize = 2_usize.checked_pow(24).unwrap_or(usize::MAX);
#[inline]
#[must_use]
pub fn new() -> Self {
Default::default()
}
#[must_use]
pub fn with_capacity(mut size: usize) -> Self {
size = size.div_ceil(size_of::<u32>());
size = size.min(Self::MAX_CAPACITY);
let base = vec![Default::default(); size].into();
Self { base }
}
pub fn allocate(&mut self, mut size: usize) {
size = size.div_ceil(size_of::<Int<4>>());
size = size.min(Self::MAX_CAPACITY);
let mut base = take(&mut self.base).into_vec();
base.clear();
base.resize(size, Default::default());
self.base = base.into();
}
#[inline]
pub fn fill(&mut self, mut value: Int<4>) {
value = value.to_be();
self.base.fill(value);
}
#[inline]
pub fn load_byte(&mut self, addr: Int<4>) -> Int<1> {
if let Some(&value) = self.as_bytes().get(addr.as_usize()) {
Int::from_u8(value)
} else {
Default::default()
}
}
#[inline]
pub fn load_word(&mut self, addr: Int<4>) -> Int<2> {
let bytes = match self.as_bytes().get(addr.as_usize()..) {
Some(&[byte0, byte1, ..]) => {
[byte0, byte1]
}
Some(&[byte0]) => {
[byte0, 0]
}
_ => {
[0, 0]
}
};
Int::from_be_bytes(bytes)
}
#[inline]
pub fn load_long(&mut self, addr: Int<4>) -> Int<4> {
let bytes = match self.as_bytes().get(addr.as_usize()..) {
Some(&[byte0, byte1, byte2, byte3, ..]) => {
[byte0, byte1, byte2, byte3]
}
Some(&[byte0, byte1, byte2]) => {
[byte0, byte1, byte2, 0]
}
Some(&[byte0, byte1]) => {
[byte0, byte1, 0, 0]
}
Some(&[byte0]) => {
[byte0, 0, 0, 0]
}
_ => {
[0, 0, 0, 0]
}
};
Int::from_be_bytes(bytes)
}
#[inline]
pub fn store_u8(&mut self, addr: Int<4>, value: u8) {
if let Some(slot) = self.as_bytes_mut().get_mut(addr.as_usize()) {
*slot = value;
}
}
#[inline]
#[must_use]
pub fn capacity(&self) -> usize {
self.base.len()
}
#[inline]
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
let len = self.capacity();
let data = self.as_ptr();
unsafe { slice::from_raw_parts(data, len) }
}
#[inline]
#[must_use]
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
let len = self.capacity();
let data = self.as_mut_ptr();
unsafe { slice::from_raw_parts_mut(data, len) }
}
#[inline]
#[must_use]
pub fn as_ptr(&self) -> *const u8 {
self.base.as_ptr().cast::<u8>()
}
#[inline]
#[must_use]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.base.as_mut_ptr().cast::<u8>()
}
}
impl Drop for Mem {
#[inline(always)]
fn drop(&mut self) {}
}