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