Skip to main content

omp_core/
append_vec.rs

1//! Thread-safe append-only vector with exponential bucket growth.
2//!
3//! `AppendVec<T>` provides lock-free concurrent appends using atomic operations
4//! and a segmented bucket allocator. Supports indexed access, slicing, and
5//! bidirectional iteration.
6
7use std::{
8	alloc::{self, Layout},
9	hint,
10	iter::{FusedIterator, Iterator},
11	mem,
12	ops::{Index, IndexMut},
13	ptr::{self, NonNull},
14	slice,
15	sync::atomic::{AtomicPtr, AtomicU64, AtomicUsize, Ordering},
16};
17
18use parking_lot_core::{DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN};
19use smallvec::SmallVec;
20
21/// The number of bits used for the initial bucket size.
22const SHIFT: usize = 8;
23
24/// Maximum amount of items that can be stored in the vector in log2.
25const MAX_LOG2: usize = 39;
26
27/// A specialized bucket array optimized for append-only operations.
28///
29/// The bucket array uses a power-of-two growth strategy where each bucket is
30/// twice the size of the previous one, providing amortized O(1) append
31/// performance.
32#[derive(Debug)]
33struct BucketArray<T> {
34	/// Array of atomic pointers to allocated buckets.
35	ptrs:   [AtomicPtr<T>; MAX_LOG2 - 1 - SHIFT],
36	oplock: AtomicU64,
37}
38
39// SAFETY: BucketArray can be Send if T is Send. The atomic pointers ensure
40// proper synchronization when transferring ownership across threads.
41unsafe impl<T: Send> Send for BucketArray<T> {}
42
43// SAFETY: BucketArray can be Sync if T is Send + Sync. All access to the
44// bucket pointers is synchronized via atomics, and T needs to be Send + Sync
45// for safe concurrent access.
46unsafe impl<T: Send + Sync> Sync for BucketArray<T> {}
47
48impl<T> BucketArray<T> {
49	/// Creates a new bucket array with the specified number of levels.
50	const fn new() -> Self {
51		// SAFETY: The array is ptr and u64 are both zero-initialized.
52		unsafe { mem::zeroed() }
53	}
54
55	/// Creates a new bucket array with the specified number of levels.
56	///
57	/// # Arguments
58	///
59	/// * `capacity` - The initial capacity of the bucket array.
60	///
61	/// # Returns
62	///
63	/// A new bucket array with the specified number of levels.
64	fn with_capacity(capacity: usize) -> Self {
65		let buckets = Self::new();
66		let (_, max_level) = Self::locate(capacity.saturating_sub(1));
67		for level in 0..=max_level {
68			let ptr = Self::allocate_bucket(level);
69			buckets.ptrs[level as usize].store(ptr, Ordering::Relaxed);
70		}
71		buckets
72	}
73
74	/// Returns the maximum number of elements this bucket array can hold
75	/// without reallocating.
76	fn total_capacity(&self) -> usize {
77		let mut total = 0;
78		for (level, _) in self.iter() {
79			total += Self::level_size(level as u32);
80		}
81		total
82	}
83
84	/// Returns the maximum capacity of the bucket array.
85	fn max_capacity(&self) -> usize {
86		let mut total = 0;
87		for i in 0..self.ptrs.len() {
88			total += Self::level_size(i as u32);
89		}
90		total
91	}
92
93	/// Returns the size of a bucket at the specified level.
94	#[inline]
95	const fn level_size(level: u32) -> usize {
96		(const { 1usize << SHIFT }) << level
97	}
98
99	/// Returns the layout for a bucket at the specified level.
100	#[inline]
101	fn level_layout(level: u32) -> Layout {
102		Layout::array::<T>(Self::level_size(level)).expect("bucket size exceeds addressable memory")
103	}
104
105	/// Computes the level and offset within that level for a given index.
106	#[inline]
107	const fn locate(idx: usize) -> (usize, u32) {
108		let i = idx + Self::level_size(0);
109		let bin = (usize::BITS - 1 - i.leading_zeros()) - (SHIFT as u32);
110		let offset = i - Self::level_size(bin);
111		(offset, bin)
112	}
113
114	/// Notifies all waiting threads. Uses `parking_lot_core` futex wait/wake.
115	#[inline]
116	fn notify_all(&self, idx: u32) {
117		// SAFETY: The address passed to unpark must match the address used for park.
118		// We consistently use the address of the AtomicU32.
119		let mask = 1 << idx;
120		if self.oplock.load(Ordering::Relaxed) & mask == 0 {
121			return;
122		}
123		let prev = self.oplock.fetch_and(!mask, Ordering::Relaxed);
124		if prev & mask != 0 {
125			// SAFETY: We use the pointer as a futex key for parking_lot_core. The pointer
126			// is derived from a valid allocation (self.ptrs) and offset by idx
127			// which is < bucket count. The key is only used as an identifier and
128			// not dereferenced by parking_lot_core.
129			unsafe {
130				let key = self.ptrs.as_ptr().add(idx as usize) as usize;
131				parking_lot_core::unpark_all(key, DEFAULT_UNPARK_TOKEN);
132			}
133		}
134	}
135
136	/// Waits until the state changes from the provided `state` value.
137	/// Uses `parking_lot_core` futex wait/wake.
138	#[inline]
139	fn wait(&self, idx: u32) {
140		self.oplock.fetch_or(1 << idx, Ordering::Relaxed);
141
142		// SAFETY: See safety comment in `notify_all`.
143		unsafe {
144			let key = self.ptrs.as_ptr().add(idx as usize) as usize;
145
146			// park() checks the condition closure *before* sleeping.
147			// It only sleeps if the closure returns true (meaning state hasn't changed).
148			let _ = parking_lot_core::park(
149				key,
150				|| self.ptrs[idx as usize].load(Ordering::Acquire).is_null(), /* Validate: still
151				                                                               * needs waiting? */
152				|| {},              /* Before sleep
153				                     * callback */
154				|_, _| {},          // Timed out callback (we don't use timeouts)
155				DEFAULT_PARK_TOKEN, // Token passed to unpark
156				None,               // No timeout
157			);
158		}
159	}
160
161	/// Ensures that a bucket at the specified level is allocated and returns a
162	/// pointer to it.
163	#[inline]
164	fn ensure_bucket(&self, level: u32, wait: bool) -> *mut T {
165		let ptr = self.ptrs[level as usize].load(Ordering::Acquire);
166		if !ptr.is_null() {
167			return ptr;
168		}
169		self.try_allocate_bucket(level, wait)
170	}
171
172	/// Allocates a new bucket at the specified level.
173	///
174	/// This is a cold path that should rarely be taken.
175	#[cold]
176	fn try_allocate_bucket(&self, level: u32, wait: bool) -> *mut T {
177		let bucket = &self.ptrs[level as usize];
178		if wait {
179			for _ in 0..1000 {
180				hint::spin_loop();
181				let ptr = bucket.load(Ordering::Acquire);
182				if !ptr.is_null() {
183					return ptr;
184				}
185			}
186			loop {
187				self.wait(level);
188				let ptr = bucket.load(Ordering::Acquire);
189				if !ptr.is_null() {
190					return ptr;
191				}
192			}
193		}
194
195		let ptr = Self::allocate_bucket(level);
196
197		// Publish with Release; a failed CAS must Acquire so the loser can safely
198		// write through the winner's allocation.
199		let result =
200			bucket.compare_exchange(ptr::null_mut(), ptr, Ordering::Release, Ordering::Acquire);
201		match result {
202			Ok(_) => {
203				self.notify_all(level);
204				ptr
205			},
206			Err(p) => {
207				// Shouldn't really happen unless someone just forcefully allocates
208				// at this level, but let's handle it anyway.
209				Self::deallocate_bucket(ptr, level);
210				p
211			},
212		}
213	}
214
215	fn allocate_bucket(level: u32) -> *mut T {
216		let layout = Self::level_layout(level);
217		if layout.size() == 0 {
218			// ZSTs occupy no storage; a well-aligned dangling pointer is a valid
219			// bucket for reads, writes, and drops of zero-sized values.
220			return NonNull::dangling().as_ptr();
221		}
222		// SAFETY: layout is non-zero-sized (checked above) and valid, coming
223		// from level_layout. The resulting pointer is checked for null before use.
224		let ptr = unsafe { alloc::alloc(layout).cast::<T>() };
225		if ptr.is_null() {
226			alloc::handle_alloc_error(layout);
227		}
228		ptr
229	}
230
231	fn deallocate_bucket(ptr: *mut T, level: u32) {
232		let layout = Self::level_layout(level);
233		if layout.size() == 0 {
234			return;
235		}
236		// SAFETY: ptr was allocated with the same non-zero-sized layout via
237		// allocate_bucket. The caller ensures the pointer is valid and no longer
238		// in use.
239		unsafe { alloc::dealloc(ptr.cast::<u8>(), layout) };
240	}
241
242	/// Clears all buckets and deallocates memory.
243	fn clear(&mut self, mut n_elements: usize) {
244		// We need to mut self, as we cannot have any other reference to self as this
245		// operation is on going in order to not cause a race. But clippy doesn't
246		// know this so let's inform it.
247		hint::black_box(&mut *self);
248
249		for (level, bucket) in self.ptrs.iter().enumerate() {
250			let ptr = bucket.swap(ptr::null_mut(), Ordering::Relaxed);
251			if ptr.is_null() {
252				continue;
253			}
254
255			let level_size = Self::level_size(level as u32);
256			let drop_count = n_elements.min(level_size);
257			n_elements = n_elements.saturating_sub(drop_count);
258
259			// SAFETY: We're dropping elements that were properly initialized.
260			// We have exclusive access via &mut self, ensuring no concurrent access.
261			// The pointer arithmetic is within bounds as drop_count <= level_size.
262			// After dropping elements, the bucket is deallocated with the same layout
263			// it was allocated with.
264			unsafe {
265				for i in 0..drop_count {
266					ptr.add(i).drop_in_place();
267				}
268
269				let layout = Layout::array::<T>(level_size).unwrap();
270				if layout.size() != 0 {
271					alloc::dealloc(ptr.cast::<u8>(), layout);
272				}
273			}
274
275			if n_elements == 0 {
276				break;
277			}
278		}
279	}
280
281	/// Returns a reference to the bucket at the specified level,
282	/// assuming initialization.
283	///
284	/// # Safety
285	/// Caller must ensure the bucket exists and the level is valid.
286	#[inline]
287	unsafe fn get_bucket_unchecked(&self, level: u32) -> &[T] {
288		// SAFETY: The caller guarantees the bucket at this level is allocated
289		// and the pointer is non-null. The slice length is exactly the level size,
290		// which matches the allocation size.
291		unsafe {
292			slice::from_raw_parts(
293				self.ptrs[level as usize].load(Ordering::Relaxed),
294				Self::level_size(level),
295			)
296		}
297	}
298
299	// Returns an iterator over the buckets, ending at the first null bucket.
300	const fn iter(&self) -> BucketArrayIter<'_, T> {
301		BucketArrayIter { array: &self.ptrs, level: 0 }
302	}
303}
304
305impl<T> Drop for BucketArray<T> {
306	/// Frees any buckets still allocated. Element destructors are the owner's
307	/// responsibility: [`AppendVec`] runs them via `clear` (which also nulls
308	/// every bucket pointer) before this executes.
309	fn drop(&mut self) {
310		for (level, bucket) in self.ptrs.iter().enumerate() {
311			let ptr = bucket.swap(ptr::null_mut(), Ordering::Relaxed);
312			if !ptr.is_null() {
313				Self::deallocate_bucket(ptr, level as u32);
314			}
315		}
316	}
317}
318
319/// An iterator over the elements of a [`BucketArray`].
320///
321/// This iterator traverses each bucket in sequence, yielding the level and a
322/// pointer to the elements within each bucket. The iteration ends when all
323/// initialized elements have been visited.
324struct BucketArrayIter<'a, T> {
325	array: &'a [AtomicPtr<T>],
326	level: usize,
327}
328
329impl<T> Iterator for BucketArrayIter<'_, T> {
330	type Item = (usize, NonNull<T>);
331
332	fn next(&mut self) -> Option<Self::Item> {
333		let level = self.level;
334		let ptr = self.array.get(level)?.load(Ordering::Relaxed);
335		self.level = level + 1;
336		Some((level, NonNull::new(ptr)?))
337	}
338
339	fn size_hint(&self) -> (usize, Option<usize>) {
340		let n = self.len();
341		(n, Some(n))
342	}
343}
344
345impl<T> FusedIterator for BucketArrayIter<'_, T> {}
346
347impl<T> ExactSizeIterator for BucketArrayIter<'_, T> {
348	fn len(&self) -> usize {
349		let rem = &self.array[self.level..];
350		let mut n = 0;
351		for ptr in rem {
352			if ptr.load(Ordering::Relaxed).is_null() {
353				break;
354			}
355			n += 1;
356		}
357		n
358	}
359}
360
361/// A thread-safe, append-only vector implementation with amortized O(1) push
362/// operations.
363///
364/// This data structure is optimized for concurrent append operations while
365/// maintaining strong memory safety guarantees. It uses a series of dynamically
366/// allocated buckets that grow exponentially in size to reduce allocation
367/// frequency.
368#[derive(Debug)]
369pub struct AppendVec<T> {
370	/// Tracks the number of elements that are safe to access.
371	last_safe:  AtomicUsize,
372	/// Tracks the next index for insertion.
373	next_index: AtomicUsize,
374	/// The array of buckets storing the actual elements.
375	buckets:    BucketArray<T>,
376}
377
378// SAFETY: AppendVec can be Send if T is Send. The atomics ensure proper
379// synchronization when transferring ownership across threads.
380unsafe impl<T: Send> Send for AppendVec<T> {}
381
382// SAFETY: AppendVec can be Sync if T is Send + Sync. All internal state is
383// synchronized via atomics (last_safe, next_index) and the BucketArray is Sync
384// when T is Send + Sync.
385unsafe impl<T: Send + Sync> Sync for AppendVec<T> {}
386
387impl<T> Default for AppendVec<T> {
388	fn default() -> Self {
389		Self::new()
390	}
391}
392
393impl<T: Clone> Clone for AppendVec<T> {
394	fn clone(&self) -> Self {
395		self.iter().cloned().collect()
396	}
397}
398
399impl<T> AppendVec<T> {
400	/// Creates a new, empty [`AppendVec`].
401	pub const fn new() -> Self {
402		Self {
403			last_safe:  AtomicUsize::new(0),
404			next_index: AtomicUsize::new(0),
405			buckets:    BucketArray::new(),
406		}
407	}
408
409	/// Creates a new, empty [`AppendVec`] with a specified capacity.
410	///
411	/// This method pre-allocates buckets up to the specified capacity,
412	/// reducing the number of reallocations as elements are added.
413	///
414	/// # Arguments
415	///
416	/// * `capacity` - The initial capacity of the vector.
417	///
418	/// # Returns
419	///
420	/// A new [`AppendVec`] with the specified capacity.
421	pub fn with_capacity(capacity: usize) -> Self {
422		Self {
423			last_safe:  AtomicUsize::new(0),
424			next_index: AtomicUsize::new(0),
425			buckets:    BucketArray::with_capacity(capacity),
426		}
427	}
428
429	/// Returns the total capacity of the vector before reallocation would be
430	/// needed.
431	pub fn capacity(&self) -> usize {
432		self.buckets.total_capacity()
433	}
434
435	/// Returns the maximum capacity of the vector.
436	pub fn max_capacity(&self) -> usize {
437		self.buckets.max_capacity()
438	}
439
440	/// Clears the vector, dropping all elements and deallocating memory.
441	pub fn clear(&mut self) {
442		let len = self.last_safe.load(Ordering::Relaxed);
443		self.buckets.clear(len);
444		self.next_index.store(0, Ordering::Release);
445		self.last_safe.store(0, Ordering::Release);
446	}
447
448	/// Updates the `last_safe` counter after a successful push operation.
449	///
450	/// This ensures elements are visible only after they are fully initialized.
451	#[inline]
452	fn bump(&self, expected: usize, desired: usize) {
453		loop {
454			if self.last_safe.load(Ordering::Acquire) == expected {
455				self.last_safe.store(desired, Ordering::Release);
456				return;
457			}
458			hint::spin_loop();
459		}
460	}
461
462	/// Creates an iterator that yields references to individual elements.
463	pub fn iter(&self) -> AppendVecIter<'_, T> {
464		AppendVecIter::new(self)
465	}
466
467	/// Get a reference to the element at the specified index, if it exists.
468	pub fn get(&self, index: usize) -> Option<&T> {
469		let len = self.last_safe.load(Ordering::Acquire);
470		if index >= len {
471			return None;
472		}
473
474		// Calculate bucket and offset
475		let (offset, level) = BucketArray::<T>::locate(index);
476
477		// SAFETY: The index is valid (index < len) and the element is fully
478		// initialized. The pointer is loaded with Acquire ordering to ensure we
479		// see the write. Pointer arithmetic is within bounds since offset <
480		// level_size.
481		unsafe {
482			let ptr = self.buckets.ptrs[level as usize].load(Ordering::Acquire);
483			if ptr.is_null() {
484				return None;
485			}
486
487			Some(&*ptr.add(offset))
488		}
489	}
490
491	/// Get a mutable reference to the element at the specified index, if it
492	/// exists.
493	pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
494		let len = self.last_safe.load(Ordering::Relaxed);
495		if index >= len {
496			return None;
497		}
498
499		// Calculate bucket and offset
500		let (offset, level) = BucketArray::<T>::locate(index);
501
502		let ptr = self.buckets.ptrs[level as usize].load(Ordering::Relaxed);
503		if ptr.is_null() {
504			return None;
505		}
506
507		// SAFETY: We have exclusive mutable access via &mut self. The index is valid
508		// (index < len) and the element is initialized. Pointer arithmetic is within
509		// bounds.
510		Some(unsafe { &mut *ptr.add(offset) })
511	}
512
513	/// Returns the number of elements in the vector.
514	pub fn len(&self) -> usize {
515		self.last_safe.load(Ordering::Acquire)
516	}
517
518	/// Checks if the vector is empty.
519	pub fn is_empty(&self) -> bool {
520		self.len() == 0
521	}
522
523	/// Pushes an item to the vector.
524	pub fn push(&self, item: T) -> usize {
525		// Reserve an index for this item
526		let prev = self.next_index.fetch_add(1, Ordering::Relaxed);
527
528		// Determine which bucket and position within that bucket
529		let (offset, level) = BucketArray::<T>::locate(prev);
530
531		// Ensure the bucket exists
532		let ptr = self.buckets.ensure_bucket(level, offset > 0);
533
534		// SAFETY: We have exclusive access to this memory location because we
535		// atomically reserved it via fetch_add. The pointer arithmetic is valid
536		// since offset < level_size. The memory is uninitialized and write() is
537		// the correct method to initialize it.
538		unsafe { ptr.add(offset).write(item) };
539
540		// Make the item visible to other threads
541		self.bump(prev, prev + 1);
542
543		prev
544	}
545
546	/// Grows the vector to at least `size` elements, initializing new elements
547	/// with the provided function.
548	///
549	/// This method ensures the vector contains at least `size` elements. If the
550	/// current length is less than `size`, new elements are initialized by
551	/// calling `init` with their index.
552	///
553	/// # Arguments
554	///
555	/// * `size` - The minimum size the vector should have
556	/// * `init` - A function that produces initial values for new elements,
557	///   called with the index of each new element
558	///
559	/// # Returns
560	///
561	/// The previous length of the vector before growth
562	pub fn grow_with(&self, size: usize, mut init: impl FnMut(usize) -> T) -> usize {
563		let prev = self.next_index.fetch_max(size, Ordering::Relaxed);
564		if prev < size {
565			for i in prev..size {
566				let (offset, level) = BucketArray::<T>::locate(i);
567				let ptr = self.buckets.ensure_bucket(level, offset > 0);
568				// SAFETY: We have exclusive access to indices [prev..size) via fetch_max.
569				// Pointer arithmetic is valid since offset < level_size. The memory is
570				// uninitialized and write() properly initializes it.
571				unsafe { ptr.add(offset).write(init(i)) };
572			}
573			self.bump(prev, size);
574		}
575		prev
576	}
577
578	/// Grows the vector to at least `size` elements, initializing new elements
579	/// with their default value.
580	///
581	/// This is a convenience method that calls `grow_with` using `T::default()`
582	/// for new elements.
583	///
584	/// # Arguments
585	///
586	/// * `size` - The minimum size the vector should have
587	///
588	/// # Returns
589	///
590	/// The previous length of the vector before growth
591	pub fn grow_default(&self, size: usize) -> usize
592	where
593		T: Default,
594	{
595		self.grow_with(size, |_| T::default())
596	}
597
598	/// Grows the vector to at least `size` elements, initializing new elements
599	/// with the provided value.
600	///
601	/// This is a convenience method that calls `grow_with` using `value.clone()`
602	/// for new elements.
603	///
604	/// # Arguments
605	///
606	/// * `size` - The minimum size the vector should have
607	/// * `value` - The value to initialize new elements with
608	///
609	/// # Returns
610	///
611	/// The previous length of the vector before growth
612	pub fn grow(&self, size: usize, value: T) -> usize
613	where
614		T: Clone,
615	{
616		self.grow_with(size, |_| value.clone())
617	}
618
619	/// Pushes multiple items at once when exclusive access is guaranteed.
620	///
621	/// # Panics
622	///
623	/// Panics if the reported iterator length would overflow the vector's
624	/// maximum capacity, or if the iterator yields a different number of items
625	/// than reported by [`ExactSizeIterator::len`]. If it yields too few items,
626	/// the reserved range is not published and the vector is left in a poisoned
627	/// state, so subsequent insertions may stall. If it yields too many items,
628	/// exactly the reported prefix is published before the panic and the vector
629	/// remains usable.
630	pub fn extend(&self, items: impl IntoIterator<Item = T, IntoIter: ExactSizeIterator>) -> usize {
631		let mut iter = items.into_iter();
632		let n_items = iter.len();
633		if n_items == 0 {
634			// Nothing to reserve. Reserving an empty range would still run
635			// bump(idx, idx), which can deadlock against a concurrent push that
636			// wins the same start index.
637			return self.next_index.load(Ordering::Relaxed);
638		}
639
640		// Reserve [idx, end) with a checked CAS: a lying `len()` must never
641		// wrap or overflow `next_index` — a wrapped counter would hand out
642		// already-occupied slots to later insertions.
643		let max = self.buckets.max_capacity();
644		let mut idx = self.next_index.load(Ordering::Relaxed);
645		let end = loop {
646			let end = idx
647				.checked_add(n_items)
648				.filter(|&end| end <= max)
649				.expect("ExactSizeIterator length overflowed the AppendVec capacity");
650			match self
651				.next_index
652				.compare_exchange_weak(idx, end, Ordering::Relaxed, Ordering::Relaxed)
653			{
654				Ok(_) => break end,
655				Err(current) => idx = current,
656			}
657		};
658
659		for i in idx..end {
660			let item = iter
661				.next()
662				.expect("ExactSizeIterator under-yielded relative to its reported length");
663			let (offset, level) = BucketArray::<T>::locate(i);
664			let ptr = self.buckets.ensure_bucket(level, offset > 0);
665			// SAFETY: We reserved exactly the indices in [idx, end) via fetch_add,
666			// and the loop never writes outside that range. Pointer arithmetic is
667			// valid since offset < level_size. The memory is uninitialized and
668			// write() properly initializes it.
669			unsafe { ptr.add(offset).write(item) };
670		}
671
672		if iter.next().is_some() {
673			// The entire reservation is initialized, so publish it before reporting
674			// that the iterator yielded beyond the reservation.
675			self.bump(idx, end);
676			panic!("ExactSizeIterator over-yielded relative to its reported length");
677		}
678
679		// Update last_safe in one go.
680		self.bump(idx, end);
681		idx
682	}
683
684	/// Extends the vector with the given items, without any bounds checking.
685	///
686	/// This method is useful when you have exclusive access to the vector and
687	/// want to extend it with an unknown iterator.
688	///
689	/// # Panics
690	///
691	/// Panics if a previous insertion panicked leaving the vector in a poisoned
692	/// state.
693	pub fn extend_unbounded(&mut self, items: impl IntoIterator<Item = T>) -> usize {
694		let idx = self.next_index.load(Ordering::Relaxed);
695
696		let mut count = 0;
697		for item in items {
698			let (offset, level) = BucketArray::<T>::locate(idx + count);
699			let ptr = self.buckets.ensure_bucket(level, offset > 0);
700			// SAFETY: We have exclusive access via &mut self. The pointer arithmetic
701			// is valid since offset < level_size. The memory is uninitialized and
702			// write() properly initializes it.
703			unsafe { ptr.add(offset).write(item) };
704			count += 1;
705		}
706
707		assert!(
708			self.last_safe.load(Ordering::Relaxed) == idx,
709			"must be idle with exclusive reference"
710		);
711		self.next_index.store(idx + count, Ordering::Release);
712		self.last_safe.store(idx + count, Ordering::Release);
713		idx + count
714	}
715
716	/// Returns a view over a contiguous range of elements.
717	///
718	/// The returned [`AppendSlice`] is a lightweight wrapper around several
719	/// slice references, each coming from a different internal bucket.  It
720	/// offers the standard slice-like API (`len`, indexing, iteration)
721	/// without copying the underlying data.
722	///
723	/// The function is lock-free and **does not allocate**.
724	///
725	/// # Panics
726	///
727	/// Panics if `range.end` is greater than the current length of the vector,
728	/// or if `range.start > range.end`.
729	///
730	/// # Examples
731	///
732	/// ```
733	/// use omp_core::append_vec::AppendVec;
734	/// let vec = AppendVec::with_capacity(10);
735	/// for i in 0..10 {
736	/// 	vec.push(i);
737	/// }
738	/// let window = vec.slice(2..5);
739	/// assert_eq!(window.len(), 3);
740	/// assert_eq!(window[0], 2);
741	/// ```
742	pub fn slice(&self, range: std::ops::Range<usize>) -> AppendSlice<T> {
743		assert!(range.start <= range.end, "range start must not exceed range end");
744		let len = self.len();
745		assert!(range.end <= len, "range end is out of bounds for AppendVec of length {len}");
746		if range.start == range.end {
747			return AppendSlice::default();
748		}
749
750		let (loc0, lvl0) = BucketArray::<T>::locate(range.start);
751		let (loc1, lvl1) = BucketArray::<T>::locate(range.end);
752
753		// SAFETY: The asserts above establish range.start < range.end <= len, so
754		// the lvl0 bucket exists and contains an initialized element at loc0.
755		let bucket0 = unsafe { self.buckets.get_bucket_unchecked(lvl0) };
756
757		// Push first level
758		if lvl1 == lvl0 {
759			return AppendSlice(SmallVec::from_iter([&bucket0[loc0..loc1]]));
760		}
761		let mut slices = SmallVec::from_iter([&bucket0[loc0..]]);
762
763		// Push middle levels
764		for lvl in lvl0 + 1..lvl1 {
765			// SAFETY: The asserts above establish range.end <= len, so all buckets
766			// between lvl0 and lvl1 exist and are initialized.
767			slices.push(unsafe { self.buckets.get_bucket_unchecked(lvl) });
768		}
769
770		// Push last level
771		if loc1 > 0 {
772			// SAFETY: The asserts above establish range.end <= len, so lvl1 exists
773			// and its elements before loc1 are initialized.
774			slices.push(unsafe { &self.buckets.get_bucket_unchecked(lvl1)[..loc1] });
775		}
776
777		AppendSlice(slices)
778	}
779}
780
781impl<T> FromIterator<T> for AppendVec<T> {
782	fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
783		let iter = iter.into_iter();
784		let mut vec = Self::with_capacity(iter.size_hint().0);
785		vec.extend_unbounded(iter);
786		vec
787	}
788}
789
790impl<T> Drop for AppendVec<T> {
791	fn drop(&mut self) {
792		self.clear();
793	}
794}
795
796/// A slice-like view produced by [`AppendVec::slice`].
797///
798/// Internally the vector is backed by multiple exponentially growing buckets.
799/// An [`AppendSlice`] therefore stores a small `SmallVec` of slice
800/// references so that the common case of spanning at most four buckets is
801/// allocated on the stack.
802///
803/// The structure is *copy-free* and merely borrows the data.  Two different
804/// iterator flavours are provided:
805///
806/// * [`iter`](Self::iter) – borrows `&self` and yields `&T` items.
807/// * [`IntoIterator`] – consumes the range and yields `&T` items with the
808///   exact-size, fused iterator [`AppendSliceIntoIter`].
809#[derive(Debug)]
810pub struct AppendSlice<'a, T>(SmallVec<&'a [T], 4>);
811
812impl<T> Default for AppendSlice<'_, T> {
813	fn default() -> Self {
814		Self(SmallVec::new())
815	}
816}
817
818impl<'a, T> FromIterator<&'a [T]> for AppendSlice<'a, T> {
819	fn from_iter<I: IntoIterator<Item = &'a [T]>>(iter: I) -> Self {
820		Self(iter.into_iter().collect())
821	}
822}
823
824impl<'a, T> AppendSlice<'a, T> {
825	/// A view over `slices` presented as one contiguous sequence.
826	pub fn new(slices: &'a [&'a [T]]) -> Self {
827		Self(SmallVec::from_iter(slices.iter().copied()))
828	}
829
830	/// Returns a reference to the element at `index`, or `None` if the index is
831	/// out of bounds for this range.
832	///
833	/// Equivalent to `self.into_iter().nth(index)` but constant-time.
834	pub fn get(&self, mut index: usize) -> Option<&'a T> {
835		for slice in &self.0 {
836			if index < slice.len() {
837				return Some(&slice[index]);
838			}
839			index -= slice.len();
840		}
841		None
842	}
843
844	/// Returns the total number of elements in the range.
845	pub fn len(&self) -> usize {
846		self.0.iter().map(|s| s.len()).sum()
847	}
848
849	/// Returns `true` if the range contains no elements.
850	pub fn is_empty(&self) -> bool {
851		self.len() == 0
852	}
853
854	/// Returns an iterator over the elements in the range.
855	///
856	/// This is the same iterator that the `&AppendSlice` implementation of
857	/// [`IntoIterator`] returns.
858	#[define_opaque(Iter)]
859	pub fn iter(&self) -> Iter<T> {
860		self.0.iter().flat_map(|s| s.iter())
861	}
862}
863
864/// Iterator returned by [`AppendSlice::iter`].
865pub type Iter<'s, T: 's> = impl DoubleEndedIterator<Item = &'s T> + FusedIterator + Clone + 's;
866
867/// An exact-size, fused iterator yielding references into the original
868/// vector.
869///
870/// It is created by calling [`IntoIterator::into_iter`] on an
871/// [`AppendSlice`].  Because the range owns its internal `SmallVec`, the
872/// iterator can operate by *mutating* the stored slices in place, achieving
873/// zero allocations and minimal bookkeeping.
874#[derive(Debug)]
875pub struct AppendSliceIntoIter<'s, T> {
876	range:      AppendSlice<'s, T>,
877	bucket_idx: usize,
878}
879
880impl<'s, T> Iterator for AppendSliceIntoIter<'s, T> {
881	type Item = &'s T;
882
883	fn next(&mut self) -> Option<Self::Item> {
884		while let Some(slice) = self.range.0.get_mut(self.bucket_idx) {
885			let Some((item, rest)) = slice.split_first() else {
886				self.bucket_idx += 1;
887				continue;
888			};
889
890			*slice = rest;
891			return Some(item);
892		}
893		None
894	}
895
896	fn size_hint(&self) -> (usize, Option<usize>) {
897		let n = ExactSizeIterator::len(self);
898		(n, Some(n))
899	}
900}
901
902impl<T> ExactSizeIterator for AppendSliceIntoIter<'_, T> {
903	fn len(&self) -> usize {
904		self.range.0[self.bucket_idx..]
905			.iter()
906			.map(|s| s.len())
907			.sum()
908	}
909}
910
911impl<T> FusedIterator for AppendSliceIntoIter<'_, T> {}
912
913impl<'a, T> IntoIterator for AppendSlice<'a, T> {
914	type IntoIter = AppendSliceIntoIter<'a, T>;
915	type Item = &'a T;
916
917	fn into_iter(self) -> Self::IntoIter {
918		AppendSliceIntoIter { range: self, bucket_idx: 0 }
919	}
920}
921
922impl<'a, 'b, T> IntoIterator for &'b AppendSlice<'a, T>
923where
924	'b: 'a,
925{
926	type IntoIter = Iter<'b, T>;
927	type Item = &'a T;
928
929	fn into_iter(self) -> Self::IntoIter {
930		self.iter()
931	}
932}
933
934impl<T> Index<usize> for AppendSlice<'_, T> {
935	type Output = T;
936
937	fn index(&self, index: usize) -> &Self::Output {
938		self.get(index).expect("index out of bounds")
939	}
940}
941
942// Implementation of common traits for AppendVec
943
944impl<T> Index<usize> for AppendVec<T> {
945	type Output = T;
946
947	fn index(&self, index: usize) -> &Self::Output {
948		self.get(index).expect("index out of bounds")
949	}
950}
951
952impl<T> IndexMut<usize> for AppendVec<T> {
953	fn index_mut(&mut self, index: usize) -> &mut Self::Output {
954		self.get_mut(index).expect("index out of bounds")
955	}
956}
957
958/// Implementation of `IntoIterator` for [`AppendVec`]
959impl<'a, T> IntoIterator for &'a AppendVec<T> {
960	type IntoIter = AppendVecIter<'a, T>;
961	type Item = &'a T;
962
963	fn into_iter(self) -> Self::IntoIter {
964		self.iter()
965	}
966}
967
968/// An iterator over elements in a [`AppendVec`].
969#[derive(Debug)]
970pub struct AppendVecIter<'a, T> {
971	n:           usize,
972	vec:         &'a AppendVec<T>,
973	front:       u32,
974	back:        u32,
975	front_slice: &'a [T],
976	back_slice:  &'a [T],
977}
978
979impl<'a, T> AppendVecIter<'a, T> {
980	const fn empty(vec: &'a AppendVec<T>) -> Self {
981		Self { n: 0, vec, front: 0, back: 0, front_slice: &[], back_slice: &[] }
982	}
983
984	fn new(vec: &'a AppendVec<T>) -> Self {
985		let len = vec.len();
986		if len == 0 {
987			return Self::empty(vec);
988		}
989
990		let (back_bucket_level, back_bucket_offset) = if len > 0 {
991			let (offset, level) = BucketArray::<T>::locate(len - 1);
992			(level, offset + 1)
993		} else {
994			(0, 0)
995		};
996
997		if back_bucket_level == 0 {
998			// SAFETY: len > 0, so bucket 0 must exist and contain initialized elements.
999			let bucket = unsafe { vec.buckets.get_bucket_unchecked(0) };
1000			Self {
1001				n: len,
1002				vec,
1003				front: 0,
1004				back: 0,
1005				front_slice: &bucket[..back_bucket_offset],
1006				back_slice: &[],
1007			}
1008		} else {
1009			// SAFETY: len > 0 implies bucket 0 exists. The back_bucket_level was computed
1010			// from len-1, so that bucket also exists and contains initialized elements.
1011			let front_bucket = unsafe { vec.buckets.get_bucket_unchecked(0) };
1012			// SAFETY: back_bucket_level was computed from len-1, so it's a valid bucket
1013			// index.
1014			let back_bucket = unsafe { vec.buckets.get_bucket_unchecked(back_bucket_level) };
1015			Self {
1016				vec,
1017				n: len,
1018				front: 0,
1019				back: back_bucket_level,
1020				front_slice: front_bucket,
1021				back_slice: &back_bucket[..back_bucket_offset],
1022			}
1023		}
1024	}
1025}
1026
1027impl<'a, T> Iterator for AppendVecIter<'a, T> {
1028	type Item = &'a T;
1029
1030	#[inline]
1031	fn next(&mut self) -> Option<Self::Item> {
1032		if self.n == 0 {
1033			return None;
1034		}
1035		self.n -= 1;
1036
1037		if let Some(item) = self.front_slice.split_off_first() {
1038			return Some(item);
1039		}
1040
1041		self.front += 1;
1042		if self.front == self.back {
1043			mem::swap(&mut self.front_slice, &mut self.back_slice);
1044		} else {
1045			// SAFETY: The front index only advances through buckets that were
1046			// initialized when the iterator was created (n tracks remaining elements).
1047			// We never go past the back bucket.
1048			self.front_slice = unsafe { self.vec.buckets.get_bucket_unchecked(self.front) };
1049		}
1050		self.front_slice.split_off_first()
1051	}
1052
1053	fn size_hint(&self) -> (usize, Option<usize>) {
1054		(self.n, Some(self.n))
1055	}
1056}
1057
1058impl<T> ExactSizeIterator for AppendVecIter<'_, T> {
1059	fn len(&self) -> usize {
1060		self.n
1061	}
1062}
1063
1064impl<T> FusedIterator for AppendVecIter<'_, T> {}
1065
1066impl<T> DoubleEndedIterator for AppendVecIter<'_, T> {
1067	#[inline]
1068	fn next_back(&mut self) -> Option<Self::Item> {
1069		if self.n == 0 {
1070			return None;
1071		}
1072		self.n -= 1;
1073
1074		// Fast path: if we're in the same bucket
1075		if self.front == self.back {
1076			return self.front_slice.split_off_last();
1077		}
1078
1079		// Try current back slice
1080		if let Some(item) = self.back_slice.split_off_last() {
1081			return Some(item);
1082		}
1083
1084		// Move to previous bucket
1085		self.back -= 1;
1086		if self.back == self.front {
1087			self.front_slice.split_off_last()
1088		} else {
1089			// SAFETY: The back index only moves backwards through buckets that were
1090			// initialized when the iterator was created (n tracks remaining elements).
1091			// We never go before the front bucket.
1092			self.back_slice = unsafe { self.vec.buckets.get_bucket_unchecked(self.back) };
1093			self.back_slice.split_off_last()
1094		}
1095	}
1096}
1097
1098// Extension: ToOwned/Cow support for advanced use cases
1099impl<T: Clone> AppendVec<T> {
1100	/// Creates a standard Vec from this `AppendVec`.
1101	pub fn to_vec(&self) -> Vec<T> {
1102		self.iter().cloned().collect()
1103	}
1104}
1105
1106#[cfg(test)]
1107mod tests {
1108	use std::{
1109		cell::RefCell,
1110		rc::Rc,
1111		sync::{
1112			Arc,
1113			atomic::{AtomicUsize, Ordering},
1114		},
1115	};
1116
1117	use super::*;
1118
1119	struct LyingLen<T> {
1120		items:        std::vec::IntoIter<T>,
1121		reported_len: usize,
1122	}
1123
1124	impl<T> LyingLen<T> {
1125		fn new(items: Vec<T>, reported_len: usize) -> Self {
1126			Self { items: items.into_iter(), reported_len }
1127		}
1128	}
1129
1130	impl<T> Iterator for LyingLen<T> {
1131		type Item = T;
1132
1133		fn next(&mut self) -> Option<Self::Item> {
1134			self.items.next()
1135		}
1136
1137		fn size_hint(&self) -> (usize, Option<usize>) {
1138			(self.reported_len, Some(self.reported_len))
1139		}
1140	}
1141
1142	impl<T> ExactSizeIterator for LyingLen<T> {
1143		fn len(&self) -> usize {
1144			self.reported_len
1145		}
1146	}
1147
1148	#[test]
1149	fn locate() {
1150		type T = BucketArray<usize>;
1151
1152		fn naive_locate(mut idx: usize) -> (usize, u32) {
1153			for level in 0..32 {
1154				let size = T::level_size(level);
1155				if idx < size {
1156					return (idx, level);
1157				}
1158				idx -= size;
1159			}
1160			unreachable!()
1161		}
1162
1163		for i in 0..1000 {
1164			assert_eq!(T::locate(i), naive_locate(i));
1165		}
1166	}
1167
1168	#[test]
1169	fn test_basic_operations() {
1170		let vec = AppendVec::<i32>::new();
1171
1172		// Test push and len
1173		assert_eq!(vec.push(1), 0);
1174		assert_eq!(vec.push(2), 1);
1175		assert_eq!(vec.push(3), 2);
1176		assert_eq!(vec.len(), 3);
1177
1178		// Test get_ref
1179		assert_eq!(*vec.get(0).unwrap(), 1);
1180		assert_eq!(*vec.get(1).unwrap(), 2);
1181		assert_eq!(*vec.get(2).unwrap(), 3);
1182
1183		// Test IndexOp
1184		assert_eq!(vec[0], 1);
1185		assert_eq!(vec[1], 2);
1186		assert_eq!(vec[2], 3);
1187
1188		// Test iterator
1189		let mut iter = vec.iter();
1190		assert_eq!(*iter.next().unwrap(), 1);
1191		assert_eq!(*iter.next().unwrap(), 2);
1192		assert_eq!(*iter.next().unwrap(), 3);
1193		assert!(iter.next().is_none());
1194
1195		// Test into_iter
1196		let mut collected = vec.into_iter().copied().collect::<Vec<_>>();
1197		collected.sort_unstable();
1198		assert_eq!(collected, vec![1, 2, 3]);
1199	}
1200
1201	#[test]
1202	fn test_concurrent_push() {
1203		const THREADS: usize = 10;
1204		const ITEMS_PER_THREAD: usize = 1000;
1205
1206		let vec = Arc::new(AppendVec::<usize>::new());
1207
1208		std::thread::scope(|scope| {
1209			for thread in 0..THREADS {
1210				let vec = Arc::clone(&vec);
1211				scope.spawn(move || {
1212					let start = thread * ITEMS_PER_THREAD;
1213					for i in start..start + ITEMS_PER_THREAD {
1214						vec.push(i);
1215					}
1216				});
1217			}
1218		});
1219
1220		assert_eq!(vec.len(), THREADS * ITEMS_PER_THREAD);
1221
1222		let values: std::collections::HashSet<usize> = vec.iter().copied().collect();
1223		assert_eq!(values.len(), THREADS * ITEMS_PER_THREAD);
1224
1225		for expected in 0..THREADS * ITEMS_PER_THREAD {
1226			assert!(values.contains(&expected));
1227		}
1228	}
1229
1230	#[test]
1231	fn test_clear() {
1232		let mut vec = AppendVec::<i32>::new();
1233
1234		// Add some elements
1235		for i in 0..100 {
1236			vec.push(i);
1237		}
1238
1239		assert_eq!(vec.len(), 100);
1240
1241		// Clear the vector
1242		vec.clear();
1243
1244		// Verify state after clearing
1245		assert_eq!(vec.len(), 0);
1246		assert!(vec.is_empty());
1247
1248		// Test that we can add elements after clearing
1249		vec.push(42);
1250		assert_eq!(vec.len(), 1);
1251		assert_eq!(vec[0], 42);
1252	}
1253
1254	#[test]
1255	fn test_extend_from_slice() {
1256		let vec = AppendVec::<i32>::new();
1257		let items = [1, 2, 3, 4, 5];
1258
1259		vec.extend(items);
1260
1261		assert_eq!(vec.len(), 5);
1262		for (i, &val) in items.iter().enumerate() {
1263			assert_eq!(vec[i], val);
1264		}
1265	}
1266
1267	#[test]
1268	fn test_get_mut() {
1269		let mut vec = AppendVec::<String>::new();
1270
1271		vec.push("Hello".to_string());
1272		vec.push("World".to_string());
1273
1274		// Modify element through get_mut
1275		if let Some(e) = vec.get_mut(1) {
1276			e.push('!');
1277		}
1278
1279		assert_eq!(vec[1], "World!");
1280
1281		// Test out of bounds
1282		assert!(vec.get_mut(100).is_none());
1283	}
1284
1285	#[test]
1286	fn test_is_empty() {
1287		let vec = AppendVec::<u32>::new();
1288
1289		assert!(vec.is_empty());
1290
1291		vec.push(1);
1292		assert!(!vec.is_empty());
1293
1294		let mut vec = AppendVec::<u32>::new();
1295		vec.push(1);
1296		vec.clear();
1297		assert!(vec.is_empty());
1298	}
1299
1300	#[test]
1301	fn test_extend() {
1302		let vec = AppendVec::<char>::new();
1303
1304		let items = ['a', 'b', 'c', 'd', 'e'];
1305		vec.extend(items);
1306
1307		assert_eq!(vec.len(), 5);
1308		assert_eq!(vec[0], 'a');
1309		assert_eq!(vec[4], 'e');
1310	}
1311
1312	#[test]
1313	#[should_panic(expected = "range end is out of bounds for AppendVec of length 0")]
1314	fn test_slice_rejects_out_of_bounds_range() {
1315		let _ = AppendVec::<u32>::new().slice(0..1);
1316	}
1317
1318	#[test]
1319	fn test_empty_slice_of_empty_vec() {
1320		let vec = AppendVec::<u32>::new();
1321		let slice = vec.slice(0..0);
1322
1323		assert_eq!(slice.len(), 0);
1324		assert!(slice.iter().next().is_none());
1325	}
1326
1327	#[test]
1328	#[should_panic(expected = "ExactSizeIterator under-yielded relative to its reported length")]
1329	fn test_extend_rejects_under_yielding_exact_size_iterator() {
1330		let vec = AppendVec::<u32>::new();
1331		vec.extend(LyingLen::new(vec![1, 2], 3));
1332	}
1333
1334	#[test]
1335	#[should_panic(expected = "ExactSizeIterator over-yielded relative to its reported length")]
1336	fn test_extend_publishes_reported_prefix_before_over_yield_panic() {
1337		let vec = AppendVec::<u32>::new();
1338		let panic = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1339			vec.extend(LyingLen::new(vec![10, 20, 30, 40], 2));
1340		}))
1341		.expect_err("over-yielding ExactSizeIterator must panic");
1342
1343		assert_eq!(vec.len(), 2);
1344		assert_eq!(vec.iter().copied().collect::<Vec<_>>(), vec![10, 20]);
1345
1346		std::panic::resume_unwind(panic);
1347	}
1348
1349	#[test]
1350	fn test_extend_lying_len_usize_max_does_not_corrupt_counter() {
1351		let vec = AppendVec::<u32>::new();
1352		vec.push(1);
1353
1354		// A reported length of usize::MAX must panic BEFORE the reservation
1355		// counter is touched; a wrapped counter would hand slot 0 to the next
1356		// push.
1357		std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1358			vec.extend(LyingLen::new(vec![2, 3], usize::MAX));
1359		}))
1360		.expect_err("overflowing reported length must panic");
1361
1362		assert_eq!(vec.push(2), 1);
1363		assert_eq!(vec.len(), 2);
1364		assert_eq!(vec.iter().copied().collect::<Vec<_>>(), vec![1, 2]);
1365	}
1366
1367	#[test]
1368	fn test_extend_empty_iterator_reserves_nothing() {
1369		let vec = AppendVec::<u32>::new();
1370		vec.push(7);
1371
1372		assert_eq!(vec.extend(std::iter::empty()), 1);
1373		assert_eq!(vec.len(), 1);
1374
1375		// The vector stays fully usable afterwards.
1376		assert_eq!(vec.push(8), 1);
1377		assert_eq!(vec.iter().copied().collect::<Vec<_>>(), vec![7, 8]);
1378	}
1379
1380	#[test]
1381	fn test_to_vec() {
1382		let vec = AppendVec::<usize>::new();
1383		for i in 0..100 {
1384			vec.push(i);
1385		}
1386
1387		let std_vec = vec.to_vec();
1388
1389		assert_eq!(std_vec.len(), 100);
1390		for (i, &val) in std_vec.iter().enumerate() {
1391			assert_eq!(val, i);
1392		}
1393	}
1394
1395	#[test]
1396	fn test_element_iter_size_hint() {
1397		let vec = AppendVec::<i32>::new();
1398		for i in 0..100 {
1399			vec.push(i);
1400		}
1401
1402		let iter = vec.iter();
1403		assert_eq!(iter.size_hint(), (100, Some(100)));
1404		assert_eq!(iter.len(), 100);
1405
1406		// Check size_hint during iteration
1407		let mut iter = vec.iter();
1408		iter.next();
1409		iter.next();
1410		assert_eq!(iter.size_hint(), (98, Some(98)));
1411	}
1412
1413	#[test]
1414	fn test_bucket_array_num_buckets() {
1415		let bucket_array = BucketArray::<i32>::new();
1416		assert_eq!(bucket_array.iter().count(), 0);
1417
1418		// Allocate a bucket via the ensure_bucket method
1419		bucket_array.ensure_bucket(0, false);
1420		assert_eq!(bucket_array.iter().count(), 1);
1421
1422		bucket_array.ensure_bucket(1, false);
1423		bucket_array.ensure_bucket(2, false);
1424		assert_eq!(bucket_array.iter().count(), 3);
1425	}
1426
1427	#[test]
1428	fn test_destructors() {
1429		// Counter to track destructor calls
1430		static DESTROY_COUNT: AtomicUsize = AtomicUsize::new(0);
1431
1432		// Type that counts when destroyed
1433		struct DestructorCounter;
1434
1435		impl Drop for DestructorCounter {
1436			fn drop(&mut self) {
1437				DESTROY_COUNT.fetch_add(1, Ordering::SeqCst);
1438			}
1439		}
1440
1441		{
1442			let mut vec = AppendVec::<DestructorCounter>::new();
1443
1444			// Add several counters
1445			for _ in 0..10 {
1446				vec.push(DestructorCounter);
1447			}
1448
1449			// Verify no destructors called yet
1450			assert_eq!(DESTROY_COUNT.load(Ordering::SeqCst), 0);
1451
1452			// Clear should call destructors
1453			vec.clear();
1454			assert_eq!(DESTROY_COUNT.load(Ordering::SeqCst), 10);
1455
1456			// Add more elements
1457			for _ in 0..5 {
1458				vec.push(DestructorCounter);
1459			}
1460		} // vec goes out of scope here
1461
1462		// Verify all destructors called
1463		assert_eq!(DESTROY_COUNT.load(Ordering::SeqCst), 15);
1464	}
1465
1466	#[test]
1467	fn test_drop_elements_across_buckets() {
1468		// Create a shared counter across multiple objects
1469		let counter = Rc::new(RefCell::new(0));
1470
1471		struct Tracked {
1472			counter: Rc<RefCell<usize>>,
1473		}
1474
1475		impl Drop for Tracked {
1476			fn drop(&mut self) {
1477				*self.counter.borrow_mut() += 1;
1478			}
1479		}
1480
1481		{
1482			let mut vec = AppendVec::<Tracked>::new();
1483
1484			// Add enough elements to span multiple buckets
1485			let total = 1000;
1486			for _ in 0..total {
1487				vec.push(Tracked { counter: counter.clone() });
1488			}
1489
1490			// Verify no elements dropped yet
1491			assert_eq!(*counter.borrow(), 0);
1492
1493			// Validate the element count
1494			assert_eq!(vec.len(), total);
1495
1496			// Clear half the vector
1497			vec.clear();
1498			assert_eq!(*counter.borrow(), total);
1499		}
1500
1501		// All objects should be dropped when vec goes out of scope
1502		assert_eq!(*counter.borrow(), 1000);
1503	}
1504
1505	#[test]
1506	fn test_range_and_iterators() {
1507		let vec = AppendVec::<usize>::new();
1508
1509		// Fill vector with enough elements to span multiple buckets.
1510		for i in 0..600 {
1511			vec.push(i);
1512		}
1513
1514		// ----- Single-bucket range -----
1515		let range_single = vec.slice(10..20);
1516		assert_eq!(range_single.len(), 10);
1517		assert!(!range_single.is_empty());
1518		assert_eq!(range_single[0], 10);
1519		assert_eq!(range_single[9], 19);
1520
1521		// Iterate using AppendSliceIter
1522		let collected_iter: Vec<_> = range_single.iter().copied().collect();
1523		assert_eq!(collected_iter, (10usize..20).collect::<Vec<_>>());
1524
1525		// Iterate using AppendSliceIntoIter (consumes the range)
1526		let collected_into: Vec<_> = range_single.into_iter().copied().collect();
1527		assert_eq!(collected_into, (10usize..20).collect::<Vec<_>>());
1528
1529		// ----- Multi-bucket range -----
1530		let range_multi = vec.slice(200..400); // crosses bucket boundary (256-element level)
1531		assert_eq!(range_multi.len(), 200);
1532		assert_eq!(range_multi[0], 200);
1533		assert_eq!(range_multi[199], 399);
1534
1535		let collected_multi: Vec<_> = range_multi.into_iter().copied().collect();
1536		assert_eq!(collected_multi, (200usize..400).collect::<Vec<_>>());
1537	}
1538
1539	#[test]
1540	fn test_iter_double_ended() {
1541		let vec = AppendVec::<i32>::new();
1542
1543		// Test empty iterator
1544		let mut empty_iter = vec.iter();
1545		assert!(empty_iter.next().is_none());
1546		assert!(empty_iter.next_back().is_none());
1547
1548		// Add some elements
1549		for i in 0..10 {
1550			vec.push(i);
1551		}
1552
1553		// Test alternating front and back iteration
1554		let mut iter = vec.iter();
1555		assert_eq!(*iter.next().unwrap(), 0);
1556		assert_eq!(*iter.next_back().unwrap(), 9);
1557		assert_eq!(*iter.next().unwrap(), 1);
1558		assert_eq!(*iter.next_back().unwrap(), 8);
1559		assert_eq!(*iter.next().unwrap(), 2);
1560		assert_eq!(*iter.next_back().unwrap(), 7);
1561		assert_eq!(*iter.next().unwrap(), 3);
1562		assert_eq!(*iter.next_back().unwrap(), 6);
1563		assert_eq!(*iter.next().unwrap(), 4);
1564		assert_eq!(*iter.next_back().unwrap(), 5);
1565
1566		// Both ends should be exhausted
1567		assert!(iter.next().is_none());
1568		assert!(iter.next_back().is_none());
1569	}
1570
1571	#[test]
1572	fn test_iter_double_ended_across_buckets() {
1573		let vec = AppendVec::<usize>::new();
1574
1575		// Add enough elements to span multiple buckets
1576		for i in 0..600 {
1577			vec.push(i);
1578		}
1579
1580		// Test reverse iteration
1581		let mut iter = vec.iter();
1582		let mut collected_forward = Vec::new();
1583		let mut collected_backward = Vec::new();
1584
1585		// Collect some from front
1586		for _ in 0..100 {
1587			collected_forward.push(*iter.next().unwrap());
1588		}
1589
1590		// Collect some from back
1591		for _ in 0..100 {
1592			collected_backward.push(*iter.next_back().unwrap());
1593		}
1594
1595		// Verify correct values
1596		assert_eq!(collected_forward, (0..100).collect::<Vec<_>>());
1597		assert_eq!(collected_backward, (500..600).rev().collect::<Vec<_>>());
1598
1599		// Test full reverse iteration
1600		let reverse_collected: Vec<_> = vec.iter().rev().copied().collect();
1601		assert_eq!(reverse_collected, (0..600).rev().collect::<Vec<_>>());
1602	}
1603
1604	#[test]
1605	fn test_iter_size_hint_with_double_ended() {
1606		let vec = AppendVec::<i32>::new();
1607
1608		for i in 0..100 {
1609			vec.push(i);
1610		}
1611
1612		let mut iter = vec.iter();
1613
1614		// Initial size hint
1615		assert_eq!(iter.size_hint(), (100, Some(100)));
1616		assert_eq!(iter.len(), 100);
1617
1618		// Consume from front
1619		iter.next();
1620		assert_eq!(iter.size_hint(), (99, Some(99)));
1621		assert_eq!(iter.len(), 99);
1622
1623		// Consume from back
1624		iter.next_back();
1625		assert_eq!(iter.size_hint(), (98, Some(98)));
1626		assert_eq!(iter.len(), 98);
1627
1628		// Consume multiple from both ends
1629		for _ in 0..48 {
1630			iter.next();
1631			iter.next_back();
1632		}
1633
1634		assert_eq!(iter.size_hint(), (2, Some(2)));
1635		assert_eq!(iter.len(), 2);
1636
1637		// Final two elements
1638		let a = iter.next().unwrap();
1639		let b = iter.next_back().unwrap();
1640		assert_ne!(a, b); // Should be different elements
1641
1642		// Exhausted
1643		assert_eq!(iter.size_hint(), (0, Some(0)));
1644		assert_eq!(iter.len(), 0);
1645	}
1646
1647	#[test]
1648	fn test_iter_fused_double_ended() {
1649		let vec = AppendVec::<i32>::new();
1650
1651		for i in 0..10 {
1652			vec.push(i);
1653		}
1654
1655		let mut iter = vec.iter();
1656
1657		// Exhaust from both ends
1658		while iter.next().is_some() || iter.next_back().is_some() {}
1659
1660		// Iterator should continue returning None from both ends
1661		assert!(iter.next().is_none());
1662		assert!(iter.next().is_none());
1663		assert!(iter.next_back().is_none());
1664		assert!(iter.next_back().is_none());
1665	}
1666
1667	#[test]
1668	fn test_iter_collect_all() {
1669		// Test with various sizes
1670		for size in [100, 256, 257, 512, 1000, 2000] {
1671			let vec = AppendVec::<usize>::new();
1672			for i in 0..size {
1673				vec.push(i);
1674			}
1675
1676			let collected: Vec<_> = vec.iter().copied().collect();
1677			assert_eq!(collected.len(), size, "Failed for size {size}");
1678
1679			for (i, &val) in collected.iter().enumerate() {
1680				assert_eq!(val, i, "Wrong value at index {i} for size {size}");
1681			}
1682		}
1683	}
1684
1685	#[test]
1686	fn test_grow_with() {
1687		let vec = AppendVec::<usize>::new();
1688
1689		// Test growing empty vector
1690		let prev = vec.grow_with(5, |i| i * 10);
1691		assert_eq!(prev, 0);
1692		assert_eq!(vec.len(), 5);
1693		for i in 0..5 {
1694			assert_eq!(vec[i], i * 10);
1695		}
1696
1697		// Test growing already populated vector
1698		vec.push(100);
1699		vec.push(101);
1700		let prev = vec.grow_with(10, |i| i * 100);
1701		assert_eq!(prev, 7); // Was at index 7 after previous operations
1702		assert_eq!(vec.len(), 10);
1703		assert_eq!(vec[7], 700);
1704		assert_eq!(vec[8], 800);
1705		assert_eq!(vec[9], 900);
1706
1707		// Test no-op when size is smaller than current
1708		let prev = vec.grow_with(8, |_| panic!("Should not be called"));
1709		assert_eq!(prev, 10);
1710		assert_eq!(vec.len(), 10);
1711	}
1712
1713	#[test]
1714	fn test_grow() {
1715		let vec = AppendVec::<i32>::new();
1716
1717		// Test growing empty vector
1718		let prev = vec.grow_default(5);
1719		assert_eq!(prev, 0);
1720		assert_eq!(vec.len(), 5);
1721		for i in 0..5 {
1722			assert_eq!(vec[i], 0); // default value
1723		}
1724
1725		// Test growing with existing elements
1726		vec.push(42);
1727		vec.push(43);
1728		let prev = vec.grow_default(10);
1729		assert_eq!(prev, 7);
1730		assert_eq!(vec.len(), 10);
1731		assert_eq!(vec[5], 42);
1732		assert_eq!(vec[6], 43);
1733		assert_eq!(vec[7], 0);
1734		assert_eq!(vec[9], 0);
1735	}
1736
1737	#[test]
1738	fn test_grow_with_custom_types() {
1739		#[derive(Debug, PartialEq)]
1740		struct Custom {
1741			value:   usize,
1742			squared: usize,
1743		}
1744
1745		let vec = AppendVec::<Custom>::new();
1746
1747		vec.grow_with(5, |i| Custom { value: i, squared: i * i });
1748
1749		assert_eq!(vec.len(), 5);
1750		assert_eq!(vec[0], Custom { value: 0, squared: 0 });
1751		assert_eq!(vec[2], Custom { value: 2, squared: 4 });
1752		assert_eq!(vec[4], Custom { value: 4, squared: 16 });
1753	}
1754
1755	#[test]
1756	fn test_grow_across_buckets() {
1757		let vec = AppendVec::<usize>::new();
1758
1759		// Grow to span multiple buckets
1760		let prev = vec.grow_with(600, |i| i * 2);
1761		assert_eq!(prev, 0);
1762		assert_eq!(vec.len(), 600);
1763
1764		// Verify values across bucket boundaries
1765		assert_eq!(vec[0], 0);
1766		assert_eq!(vec[255], 255 * 2);
1767		assert_eq!(vec[256], 256 * 2); // Start of second bucket
1768		assert_eq!(vec[511], 511 * 2);
1769		assert_eq!(vec[512], 512 * 2); // Start of third bucket
1770		assert_eq!(vec[599], 599 * 2);
1771	}
1772
1773	#[test]
1774	fn test_concurrent_grow() {
1775		let vec = Arc::new(AppendVec::<usize>::new());
1776
1777		std::thread::scope(|scope| {
1778			for i in 0..10 {
1779				let vec = Arc::clone(&vec);
1780				scope.spawn(move || {
1781					let target_size = (i + 1) * 100;
1782					vec.grow_with(target_size, |idx| idx);
1783				});
1784			}
1785		});
1786
1787		// Should grow to the maximum requested size
1788		assert_eq!(vec.len(), 1000);
1789
1790		// Verify all values are correctly initialized
1791		for i in 0..1000 {
1792			assert_eq!(vec[i], i);
1793		}
1794	}
1795
1796	#[test]
1797	fn test_grow_with_side_effects() {
1798		let counter = Arc::new(AtomicUsize::new(0));
1799		let vec = AppendVec::<usize>::new();
1800
1801		// Ensure init function is called exactly once per new element
1802		let counter_clone = counter.clone();
1803		vec.grow_with(5, |i| {
1804			counter_clone.fetch_add(1, Ordering::SeqCst);
1805			i * 10
1806		});
1807
1808		assert_eq!(counter.load(Ordering::SeqCst), 5);
1809
1810		// Growing to same size should not call init
1811		let counter_clone = counter.clone();
1812		vec.grow_with(5, |_| {
1813			counter_clone.fetch_add(1, Ordering::SeqCst);
1814			0
1815		});
1816
1817		assert_eq!(counter.load(Ordering::SeqCst), 5); // No additional calls
1818	}
1819
1820	#[test]
1821	fn test_extend_unbounded() {
1822		let mut vec = AppendVec::<usize>::new();
1823
1824		// Test extending with a basic iterator
1825		let items = vec![10, 20, 30, 40, 50];
1826		let result = vec.extend_unbounded(items);
1827		assert_eq!(result, 5);
1828		assert_eq!(vec.len(), 5);
1829		for i in 0..5 {
1830			assert_eq!(vec[i], (i + 1) * 10);
1831		}
1832
1833		// Test extending with more items
1834		let more_items = (100..110).map(|x| x * 2);
1835		let result = vec.extend_unbounded(more_items);
1836		assert_eq!(result, 15);
1837		assert_eq!(vec.len(), 15);
1838		for i in 0..10 {
1839			assert_eq!(vec[i + 5], (100 + i) * 2);
1840		}
1841	}
1842
1843	#[test]
1844	fn test_extend_unbounded_across_buckets() {
1845		let mut vec = AppendVec::<usize>::new();
1846
1847		// Extend with enough items to span multiple buckets
1848		let items = (0..600).map(|i| i * 3);
1849		let result = vec.extend_unbounded(items);
1850		assert_eq!(result, 600);
1851		assert_eq!(vec.len(), 600);
1852
1853		// Verify values across bucket boundaries
1854		assert_eq!(vec[0], 0);
1855		assert_eq!(vec[255], 255 * 3);
1856		assert_eq!(vec[256], 256 * 3); // Start of second bucket
1857		assert_eq!(vec[511], 511 * 3);
1858		assert_eq!(vec[512], 512 * 3); // Start of third bucket
1859		assert_eq!(vec[599], 599 * 3);
1860	}
1861
1862	#[test]
1863	fn test_extend_unbounded_with_side_effects() {
1864		let counter = Arc::new(AtomicUsize::new(0));
1865		let mut vec = AppendVec::<usize>::new();
1866
1867		// Ensure each item is processed exactly once
1868		let counter_clone = counter.clone();
1869		let items = (0..10).map(move |i| {
1870			counter_clone.fetch_add(1, Ordering::SeqCst);
1871			i * 100
1872		});
1873
1874		vec.extend_unbounded(items);
1875		assert_eq!(counter.load(Ordering::SeqCst), 10);
1876		assert_eq!(vec.len(), 10);
1877
1878		for i in 0..10 {
1879			assert_eq!(vec[i], i * 100);
1880		}
1881	}
1882
1883	#[test]
1884	fn test_from_iterator() {
1885		// Test FromIterator implementation
1886		let items = vec![1, 2, 3, 4, 5];
1887		let vec: AppendVec<i32> = items.into_iter().collect();
1888
1889		assert_eq!(vec.len(), 5);
1890		for i in 0..5 {
1891			assert_eq!(vec[i], (i + 1) as i32);
1892		}
1893
1894		// Test with a larger iterator that spans buckets
1895		let large_items = (0..300).map(|i| i * 2);
1896		let vec2: AppendVec<usize> = large_items.collect();
1897
1898		assert_eq!(vec2.len(), 300);
1899		for i in 0..300 {
1900			assert_eq!(vec2[i], i * 2);
1901		}
1902	}
1903
1904	#[test]
1905	#[should_panic(expected = "must be idle with exclusive reference")]
1906	fn test_extend_unbounded_panics_on_concurrent_use() {
1907		let mut vec = AppendVec::<i32>::new();
1908
1909		// Simulate concurrent modification by manipulating the counters
1910		vec.push(1);
1911		vec.push(2);
1912
1913		// Force the last_safe to be different from next_index
1914		vec.last_safe.store(1, Ordering::Relaxed);
1915
1916		// This should panic
1917		vec.extend_unbounded(vec![3, 4, 5]);
1918	}
1919}