1use std::fmt;
2pub struct MemoryPool {
3 chunk_size: usize,
4 max_chunks: usize,
5}
6
7impl MemoryPool {
8 pub fn new(chunk_size: usize, max_chunks: usize) -> Self {
9 MemoryPool {
10 chunk_size: chunk_size.max(64),
11 max_chunks: max_chunks.max(1),
12 }
13 }
14
15 pub fn chunk_size(&self) -> usize {
16 self.chunk_size
17 }
18
19 pub fn max_chunks(&self) -> usize {
20 self.max_chunks
21 }
22}
23
24impl Default for MemoryPool {
25 fn default() -> Self {
26 Self::new(4096, 16)
27 }
28}
29
30impl fmt::Debug for MemoryPool {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 f.debug_struct("MemoryPool")
33 .field("chunk_size", &self.chunk_size)
34 .field("max_chunks", &self.max_chunks)
35 .finish()
36 }
37}
38
39pub struct PooledString {
40 data: Vec<u8>,
41}
42
43impl PooledString {
44 pub fn new() -> Self {
45 PooledString { data: Vec::new() }
46 }
47
48 pub fn with_capacity(capacity: usize) -> Self {
49 PooledString {
50 data: Vec::with_capacity(capacity),
51 }
52 }
53
54 pub fn from_string(s: String) -> Self {
55 PooledString {
56 data: s.into_bytes(),
57 }
58 }
59
60 pub fn as_str(&self) -> &str {
61 unsafe { std::str::from_utf8_unchecked(&self.data) }
62 }
63
64 pub fn as_bytes(&self) -> &[u8] {
65 &self.data
66 }
67
68 pub fn push_str(&mut self, s: &str) {
69 self.data.extend(s.as_bytes());
70 }
71
72 pub fn push(&mut self, c: char) {
73 self.data.extend(c.encode_utf8(&mut [0u8; 4]).as_bytes());
74 }
75
76 pub fn len(&self) -> usize {
77 self.data.len()
78 }
79
80 pub fn is_empty(&self) -> bool {
81 self.data.is_empty()
82 }
83
84 pub fn clear(&mut self) {
85 self.data.clear();
86 }
87
88 pub fn capacity(&self) -> usize {
89 self.data.capacity()
90 }
91
92 pub fn reserve(&mut self, additional: usize) {
93 self.data.reserve(additional);
94 }
95
96 pub fn truncate(&mut self, len: usize) {
97 self.data.truncate(len);
98 }
99}
100
101impl Default for PooledString {
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107impl fmt::Debug for PooledString {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 f.debug_struct("PooledString")
110 .field("len", &self.len())
111 .field("capacity", &self.capacity())
112 .finish()
113 }
114}
115
116impl Clone for PooledString {
117 fn clone(&self) -> Self {
118 PooledString {
119 data: self.data.clone(),
120 }
121 }
122}
123
124impl From<String> for PooledString {
125 fn from(s: String) -> Self {
126 PooledString::from_string(s)
127 }
128}
129
130impl From<&str> for PooledString {
131 fn from(s: &str) -> Self {
132 PooledString::from_string(s.to_string())
133 }
134}
135
136impl std::ops::Deref for PooledString {
137 type Target = str;
138
139 fn deref(&self) -> &Self::Target {
140 self.as_str()
141 }
142}
143
144pub struct StringPool {
145 strings: Vec<PooledString>,
146 #[allow(dead_code)]
147 max_size: usize,
148}
149
150impl StringPool {
151 pub fn new() -> Self {
152 StringPool {
153 strings: Vec::new(),
154 max_size: 1024,
155 }
156 }
157
158 pub fn with_max_size(max_size: usize) -> Self {
159 StringPool {
160 strings: Vec::new(),
161 max_size,
162 }
163 }
164
165 pub fn store(&mut self, s: &str) -> PooledString {
166 PooledString::from_string(s.to_string())
167 }
168
169 pub fn get_or_insert(&mut self, s: &str) -> PooledString {
170 self.store(s)
171 }
172
173 pub fn clear(&mut self) {
174 self.strings.clear();
175 }
176
177 pub fn len(&self) -> usize {
178 self.strings.len()
179 }
180
181 pub fn is_empty(&self) -> bool {
182 self.strings.is_empty()
183 }
184
185 pub fn total_capacity(&self) -> usize {
186 self.strings.iter().map(|s| s.capacity()).sum()
187 }
188}
189
190impl Default for StringPool {
191 fn default() -> Self {
192 Self::new()
193 }
194}
195
196impl fmt::Debug for StringPool {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 f.debug_struct("StringPool")
199 .field("len", &self.len())
200 .field("total_capacity", &self.total_capacity())
201 .finish()
202 }
203}
204
205#[allow(dead_code)]
206pub mod pool_alloc {
207 use std::sync::atomic::{AtomicUsize, Ordering};
208
209 static ALLOC_COUNT: AtomicUsize = AtomicUsize::new(0);
210 static ALLOC_COUNT_MAX: AtomicUsize = AtomicUsize::new(0);
211
212 pub fn get_alloc_count() -> usize {
213 ALLOC_COUNT.load(Ordering::Relaxed)
214 }
215
216 pub fn get_max_alloc_count() -> usize {
217 ALLOC_COUNT_MAX.load(Ordering::Relaxed)
218 }
219
220 pub fn reset_count() {
221 ALLOC_COUNT.store(0, Ordering::Relaxed);
222 }
223
224 pub fn record_allocation(size: usize) {
225 let current = ALLOC_COUNT.fetch_add(size, Ordering::Relaxed);
226 let max = ALLOC_COUNT_MAX.load(Ordering::Relaxed);
227 if current > max {
228 ALLOC_COUNT_MAX.store(current, Ordering::Relaxed);
229 }
230 }
231
232 pub fn record_deallocation(size: usize) {
233 ALLOC_COUNT.fetch_sub(size, Ordering::Relaxed);
234 }
235}