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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
//! # RingAl - A High-Performance Ring Allocator
//!
//! RingAl is a blazing-fast ring allocator optimized for short-lived buffer allocations. It uses a circular allocation pattern, which grants low-cost allocations as long as allocations are ephemeral. Long-lived allocations can degrade performance by clogging the allocator.
//!
//! ## Key Features
//!
//! 1. **Preallocation Strategy**: Establish a fixed-size backing store of `N` bytes.
//! 2. **Efficient Small Buffer Management**: Allocate smaller buffers efficiently within the preallocated store.
//! 3. **Thread-Safe Operations**: Buffers can be safely shared across threads, offering clone optimizations similar to `Arc`.
//! 4. **Timely Buffer Deallocation**: Buffers should be dropped before the allocator wraps around to reuse the same memory, ensuring optimal recycling.
//!
//! RingAl focuses on efficient memory management with a dynamic memory pool that evolves its
//! backing store using something called guard sequences. Guard sequences are usually exclusively
//! owned by allocator when they are not locked (i.e. not guarding the allocation), and when they
//! do become locked, the memory region (single usize) backing the guard sequence, is only accessed
//! using Atomic operations. This allows for one thread (the owner of buffer) to release the guard
//! (write to guard sequence), when the buffer is no longer in use and the other thread, where
//! allocator is running, to perform synchronized check of whether guard sequence have been
//! released.
//!
//! The design allows for safe multi-threaded access: one thread can write while one other can
//! read. If a buffer is still occupied after allocator wraps around, the allocation attempt just
//! returns `None`, prompting a retry.
//!
//! Note: RingAl itself isn't `Sync`, so it cannot be accessed from multiple threads concurrently.
//! Instead, using thread-local storage is encouraged.
//!
//! ## Allocation Strategies
//!
//! - **Exact Fit**: Perfectly matches the requested and available sizes.
//! - **Oversized Guards**: Splits larger regions to fit the requested size, potentially causing fragmentation.
//! - **Undersized Guards**: Merges smaller regions to accommodate requests, aiding in defragmentation.
//! - **Capacity Constraints**: Fails if the backing store cannot satisfy the request, signaling with `None`.
//!
//! ## Optional Features
//! 1. **`tls` (Thread-Local Storage)**: Enables allocation requests without explicitly passing the allocator. It uses `RefCell` for thread-local data, offering convenience at a minor performance cost.
//! 2. **`drop` (Early Deallocation)**: Allows the allocator to deallocate its resources upon request. If activated, it employs a `Drop` implementation that ensures no memory leaks by blocking until all buffers are released.
//!
//! ## Usage Examples
//!
//! ### Extendable Buffer
//! ```rust
//! # use std::io::Write;
//! # use ringal::RingAl;
//! let mut allocator = RingAl::new(1024);
//! let mut buffer = allocator.extendable(64).unwrap();
//! let msg = b"hello world, this message is longer than allocated capacity...";
//! let size = buffer.write(msg).unwrap();
//! let fixed = buffer.finalize();
//! assert_eq!(fixed.as_ref(), msg);
//! assert_eq!(fixed.len(), size);
//! ```
//!
//! ### Fixed Buffer
//! ```rust
//! # use std::io::Write;
//! # use ringal::RingAl;
//! let mut allocator = RingAl::new(1024);
//! let mut buffer = allocator.fixed(256).unwrap();
//! let size = buffer.write(b"hello world, short message").unwrap();
//! assert_eq!(buffer.len(), size);
//! assert!(buffer.spare() >= 256 - size);
//! ```
//!
//! ### Multi-threaded Environment
//! ```rust
//! # use std::io::Write;
//! # use std::sync::mpsc::channel;
//! # use ringal::{ RingAl, FixedBufMut, FixedBuf };
//! let mut allocator = RingAl::new(1024);
//! let (tx, rx) = channel();
//! let mut buffer = allocator.fixed(64).unwrap();
//! let _ = buffer.write(b"message to another thread").unwrap();
//! let handle = std::thread::spawn(move || {
//! let buffer: FixedBufMut = rx.recv().unwrap();
//! let readonly = buffer.freeze();
//! for _ in 0..16 {
//! let msg: FixedBuf = readonly.clone();
//! let msg_str = std::str::from_utf8(&msg[..]).unwrap();
//! println!("{msg_str}");
//! }
//! });
//! tx.send(buffer);
//! handle.join().unwrap();
//! ```
//! ### Generic buffers
//! ```rust
//! # use ringal::{ RingAl, GenericBufMut };
//! # let mut allocator = RingAl::new(1024); // Create an allocator with initial size
//!
//! struct MyType {
//! field1: usize,
//! field2: u128
//! }
//! let mut buffer = allocator.generic::<MyType>(16).unwrap();
//! buffer.push(MyType { field1: 42, field2: 43 });
//! assert_eq!(buffer.len(), 1);
//! let t = buffer.pop().unwrap();
//! assert_eq!(t.field1, 42);
//! assert_eq!(t.field2, 43);
//! ```
//!
//! ### Thread Local Storage
//! ```rust
//! # use ringal::ringal;
//! # use std::io::Write;
//! // init the thread local allocator, should be called just once, any thread
//! // spawned afterwards, will have access to their own instance of the allocator
//! ringal!(@init, 1024);
//! // allocate fixed buffer
//! let mut fixed = ringal!(@fixed, 64).unwrap();
//! let _ = fixed.write(b"hello world!").unwrap();
//! // allocate extendable buffer, and pass a callback to operate on it
//! // this approach is necessary as ExtBuf contains reference to thread local storage,
//! // and LocalKey doesn't allow any references to exist outside of access callback
//! let fixed = ringal!{@ext, 64, |mut extendable| {
//! let _ = extendable.write(b"hello world!").unwrap();
//! // it's ok to return FixedBuf(Mut) from callback
//! extendable.finalize()
//! }}.unwrap();
//! println!("bytes written: {}", fixed.len());
//! ```
//!
//!
//! ## Safety Considerations
//!
//! While `unsafe` code is used for performance reasons, the public API is designed to be safe.
//! Significant efforts have been made to ensure no undefined behavior occurs, offering a safe
//! experience for end-users.
use ;
pub use ;
use Header;
/// Ring Allocator, see crate level documentation on features and usage
/// Platform specific size of machine word
const USIZELEN: usize = ;
/// We restrict granularity of allocation by rounding up the allocated
/// capacity to multiple of 8 machine words (converted to byte count)
const MINALLOC: usize = 8;
const DEFAULT_ALIGNMENT: usize = 64;
const USIZEALIGN: usize = ;
/// Macro to facilitate interaction with a thread-local ring allocator. This macro provides an
/// interface for initializing, allocating fixed-size buffers, and allocating extendable buffers
/// from a thread-local ring allocator instance, `RINGAL`.
///
/// # Usage
///
/// ## Initializing the Allocator
///
/// Use `ringal!(@init, capacity)` to initialize the thread-local ring allocator with the specified
/// capacity. This sets up a `RefCell` containing a `RingAl` instance, allowing each thread to have
/// its own instance initialized with the given capacity.
///
/// ## Allocating a Fixed-Size Buffer
///
/// Use `ringal!(@fixed, capacity)` to allocate a fixed-size buffer from the thread-local ring
/// allocator. This accesses the thread-local `RINGAL` and borrows it mutably to allocate a buffer
/// of the specified capacity.
///
/// ## Allocating an Extendable Buffer
///
/// Use `ringal!(@ext, capacity, callback)` to allocate an extendable buffer from the thread-local
/// ring allocator. The allocated buffer is passed to the provided callback. This allows for custom
/// handling of the extendable buffer upon allocation. The callback is necessary as LocalKey used
/// by TLS doesn't allow to reference to inner value to be passed around freely.
/// Buffer types
/// Essential header canaries
/// test