use crate::runner::ds::error::JErrorType;
#[derive(Debug, Clone)]
pub struct HeapConfig {
pub max_bytes: Option<usize>,
}
impl HeapConfig {
pub fn unlimited() -> Self {
HeapConfig { max_bytes: None }
}
pub fn with_limit(max_bytes: usize) -> Self {
HeapConfig {
max_bytes: Some(max_bytes),
}
}
}
impl Default for HeapConfig {
fn default() -> Self {
Self::unlimited()
}
}
#[derive(Debug)]
pub struct Heap {
config: HeapConfig,
allocated_bytes: usize,
}
impl Heap {
pub fn new(config: HeapConfig) -> Self {
Heap {
config,
allocated_bytes: 0,
}
}
pub fn allocate(&mut self, bytes: usize) -> Result<(), JErrorType> {
if let Some(max_bytes) = self.config.max_bytes {
if self.allocated_bytes + bytes > max_bytes {
return Err(JErrorType::RangeError("Out of memory".to_string()));
}
}
self.allocated_bytes += bytes;
Ok(())
}
pub fn deallocate(&mut self, bytes: usize) {
self.allocated_bytes = self.allocated_bytes.saturating_sub(bytes);
}
pub fn get_allocated(&self) -> usize {
self.allocated_bytes
}
pub fn get_max_bytes(&self) -> Option<usize> {
self.config.max_bytes
}
pub fn can_allocate(&self, bytes: usize) -> bool {
if let Some(max_bytes) = self.config.max_bytes {
self.allocated_bytes + bytes <= max_bytes
} else {
true
}
}
pub fn available_bytes(&self) -> Option<usize> {
self.config
.max_bytes
.map(|max| max.saturating_sub(self.allocated_bytes))
}
}
impl Default for Heap {
fn default() -> Self {
Self::new(HeapConfig::default())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_heap_unlimited() {
let mut heap = Heap::new(HeapConfig::unlimited());
assert!(heap.allocate(1000).is_ok());
assert!(heap.allocate(1000000).is_ok());
assert_eq!(heap.get_allocated(), 1001000);
}
#[test]
fn test_heap_limited() {
let mut heap = Heap::new(HeapConfig::with_limit(1000));
assert!(heap.allocate(500).is_ok());
assert!(heap.allocate(400).is_ok());
assert_eq!(heap.get_allocated(), 900);
let result = heap.allocate(200);
assert!(result.is_err());
if let Err(JErrorType::RangeError(msg)) = result {
assert_eq!(msg, "Out of memory");
}
}
#[test]
fn test_heap_deallocate() {
let mut heap = Heap::new(HeapConfig::with_limit(1000));
heap.allocate(500).unwrap();
heap.deallocate(300);
assert_eq!(heap.get_allocated(), 200);
assert!(heap.allocate(700).is_ok());
}
#[test]
fn test_heap_can_allocate() {
let heap = Heap::new(HeapConfig::with_limit(1000));
assert!(heap.can_allocate(500));
assert!(heap.can_allocate(1000));
assert!(!heap.can_allocate(1001));
}
#[test]
fn test_heap_available_bytes() {
let mut heap = Heap::new(HeapConfig::with_limit(1000));
assert_eq!(heap.available_bytes(), Some(1000));
heap.allocate(300).unwrap();
assert_eq!(heap.available_bytes(), Some(700));
let unlimited = Heap::new(HeapConfig::unlimited());
assert_eq!(unlimited.available_bytes(), None);
}
}