1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! Span color buffer allocator.
//!
//! Port of `agg_span_allocator.h` — manages a reusable buffer for span
//! generators to write per-pixel colors into during rendering.
// ============================================================================
// SpanAllocator
// ============================================================================
/// Reusable color buffer for span generators.
///
/// Allocates and reuses a buffer of color values. The buffer grows as
/// needed (aligned to 256 elements) but never shrinks, avoiding
/// repeated allocations during rendering.
///
/// Port of C++ `span_allocator<ColorT>`.
pub struct SpanAllocator<C> {
span: Vec<C>,
}
impl<C: Default + Clone> SpanAllocator<C> {
pub fn new() -> Self {
Self { span: Vec::new() }
}
/// Allocate (or reuse) a buffer of at least `span_len` elements.
///
/// Returns a mutable slice of exactly `span_len` elements.
/// The buffer may be larger internally (aligned to 256).
pub fn allocate(&mut self, span_len: usize) -> &mut [C] {
if span_len > self.span.len() {
// Align to 256 elements to reduce reallocations
let new_size = ((span_len + 255) >> 8) << 8;
self.span.resize(new_size, C::default());
}
&mut self.span[..span_len]
}
pub fn span(&mut self) -> &mut [C] {
&mut self.span
}
pub fn max_span_len(&self) -> usize {
self.span.len()
}
}
impl<C: Default + Clone> Default for SpanAllocator<C> {
fn default() -> Self {
Self::new()
}
}
// ============================================================================
// Tests
// ============================================================================
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_empty() {
let alloc = SpanAllocator::<u8>::new();
assert_eq!(alloc.max_span_len(), 0);
}
#[test]
fn test_allocate_grows() {
let mut alloc = SpanAllocator::<u32>::new();
let span = alloc.allocate(10);
assert_eq!(span.len(), 10);
// Internal buffer should be aligned to 256
assert_eq!(alloc.max_span_len(), 256);
}
#[test]
fn test_allocate_reuses() {
let mut alloc = SpanAllocator::<u32>::new();
alloc.allocate(100);
assert_eq!(alloc.max_span_len(), 256);
// Smaller allocation reuses existing buffer
let span = alloc.allocate(50);
assert_eq!(span.len(), 50);
assert_eq!(alloc.max_span_len(), 256);
}
#[test]
fn test_allocate_alignment() {
let mut alloc = SpanAllocator::<u8>::new();
alloc.allocate(257);
assert_eq!(alloc.max_span_len(), 512);
}
#[test]
fn test_span_accessor() {
let mut alloc = SpanAllocator::<u32>::new();
alloc.allocate(10);
let span = alloc.span();
assert!(span.len() >= 10);
}
}