Skip to main content

reifydb_type/util/
cowvec.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::{borrow::Borrow, mem, ops::Deref, sync::Arc, vec};
5
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
8use crate::storage::DataVec;
9
10#[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
11pub struct CowVec<T>
12where
13	T: Clone + PartialEq,
14{
15	inner: Arc<Vec<T>>,
16}
17
18impl<T> CowVec<T>
19where
20	T: Clone + PartialEq,
21{
22	pub fn with_capacity(capacity: usize) -> Self {
23		// Allocate with extra capacity to ensure alignment for SIMD
24		// operations Round up capacity to next multiple of 8 for
25		// better cache performance
26		let aligned_capacity = (capacity + 7) & !7;
27		Self {
28			inner: Arc::new(Vec::with_capacity(aligned_capacity)),
29		}
30	}
31
32	/// Create a new CowVec with aligned capacity for SIMD operations
33	pub fn with_aligned_capacity(capacity: usize) -> Self {
34		// For SIMD, we want capacity aligned to at least 32 bytes
35		// (256-bit SIMD) This ensures we can engine data in chunks
36		// without bounds checking
37		let simd_alignment = 32 / mem::size_of::<T>().max(1);
38		let aligned_capacity = capacity.div_ceil(simd_alignment) * simd_alignment;
39		Self {
40			inner: Arc::new(Vec::with_capacity(aligned_capacity)),
41		}
42	}
43
44	pub fn len(&self) -> usize {
45		self.inner.len()
46	}
47
48	pub fn is_empty(&self) -> bool {
49		self.len() == 0
50	}
51
52	pub fn capacity(&self) -> usize {
53		self.inner.capacity()
54	}
55}
56
57#[macro_export]
58macro_rules! cow_vec {
59    () => {
60        $crate::util::cowvec::CowVec::new(Vec::new())
61    };
62    ($($elem:expr),+ $(,)?) => {
63        $crate::util::cowvec::CowVec::new(vec![$($elem),+])
64    };
65}
66
67impl<T> Default for CowVec<T>
68where
69	T: Clone + PartialEq,
70{
71	fn default() -> Self {
72		Self {
73			inner: Arc::new(Vec::new()),
74		}
75	}
76}
77
78impl<T: Clone + PartialEq> PartialEq<[T]> for &CowVec<T> {
79	fn eq(&self, other: &[T]) -> bool {
80		self.inner.as_slice() == other
81	}
82}
83
84impl<T: Clone + PartialEq> PartialEq<[T]> for CowVec<T> {
85	fn eq(&self, other: &[T]) -> bool {
86		self.inner.as_slice() == other
87	}
88}
89
90impl<T: Clone + PartialEq> PartialEq<CowVec<T>> for [T] {
91	fn eq(&self, other: &CowVec<T>) -> bool {
92		self == other.inner.as_slice()
93	}
94}
95
96impl<T: Clone + PartialEq> Clone for CowVec<T> {
97	fn clone(&self) -> Self {
98		CowVec {
99			inner: Arc::clone(&self.inner),
100		}
101	}
102}
103
104impl<T: Clone + PartialEq> CowVec<T> {
105	pub fn new(vec: Vec<T>) -> Self {
106		CowVec {
107			inner: Arc::new(vec),
108		}
109	}
110
111	pub fn from_rc(rc: Arc<Vec<T>>) -> Self {
112		CowVec {
113			inner: rc,
114		}
115	}
116
117	/// Try to extract the inner Vec without cloning.
118	/// Returns `Ok(Vec<T>)` if this is the sole owner, `Err(self)` otherwise.
119	pub fn try_into_vec(self) -> Result<Vec<T>, Self> {
120		match Arc::try_unwrap(self.inner) {
121			Ok(vec) => Ok(vec),
122			Err(arc) => Err(CowVec {
123				inner: arc,
124			}),
125		}
126	}
127
128	/// Extract the inner Vec, cloning if shared.
129	pub fn into_inner(self) -> Vec<T> {
130		match Arc::try_unwrap(self.inner) {
131			Ok(vec) => vec,
132			Err(arc) => (*arc).clone(),
133		}
134	}
135
136	pub fn as_slice(&self) -> &[T] {
137		&self.inner
138	}
139
140	pub fn is_owned(&self) -> bool {
141		Arc::strong_count(&self.inner) == 1
142	}
143
144	pub fn is_shared(&self) -> bool {
145		Arc::strong_count(&self.inner) > 1
146	}
147
148	pub fn get(&self, idx: usize) -> Option<&T> {
149		self.inner.get(idx)
150	}
151
152	pub fn make_mut(&mut self) -> &mut Vec<T> {
153		Arc::make_mut(&mut self.inner)
154	}
155
156	pub fn set(&mut self, idx: usize, value: T) {
157		self.make_mut()[idx] = value;
158	}
159
160	pub fn push(&mut self, value: T) {
161		self.make_mut().push(value);
162	}
163
164	/// Clear all elements, retaining the allocated capacity when solely owned.
165	pub fn clear(&mut self) {
166		self.make_mut().clear();
167	}
168
169	pub fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
170		self.make_mut().extend(iter);
171	}
172
173	pub fn extend_from_slice(&mut self, slice: &[T]) {
174		self.make_mut().extend_from_slice(slice);
175	}
176
177	pub fn reorder(&mut self, indices: &[usize]) {
178		let vec = self.make_mut();
179		let len = vec.len();
180		assert_eq!(len, indices.len());
181
182		let mut visited = vec![false; len];
183		for start in 0..len {
184			if visited[start] || indices[start] == start {
185				continue;
186			}
187			let mut current = start;
188			while !visited[current] {
189				visited[current] = true;
190				let next = indices[current];
191				if next == start {
192					break;
193				}
194				vec.swap(current, next);
195				current = next;
196			}
197		}
198	}
199
200	/// Get aligned chunks for SIMD processing
201	/// Returns slices that are guaranteed to be aligned and sized for SIMD
202	/// operations
203	pub fn aligned_chunks(&self, chunk_size: usize) -> impl Iterator<Item = &[T]> {
204		self.inner.chunks(chunk_size)
205	}
206
207	/// Get mutable aligned chunks for SIMD processing
208	pub fn aligned_chunks_mut(&mut self, chunk_size: usize) -> impl Iterator<Item = &mut [T]> {
209		self.make_mut().chunks_mut(chunk_size)
210	}
211
212	/// Returns true if the data is suitably aligned for SIMD operations
213	pub fn is_simd_aligned(&self) -> bool {
214		let alignment = 32; // 256-bit SIMD alignment
215		let ptr = self.inner.as_ptr() as usize;
216		ptr.is_multiple_of(alignment)
217	}
218
219	pub fn take(&self, n: usize) -> Self {
220		let len = n.min(self.len());
221		CowVec::new(self.inner[..len].to_vec())
222	}
223}
224
225impl<T: Clone + PartialEq> IntoIterator for CowVec<T> {
226	type Item = T;
227	type IntoIter = vec::IntoIter<T>;
228
229	fn into_iter(self) -> Self::IntoIter {
230		match Arc::try_unwrap(self.inner) {
231			Ok(vec) => vec.into_iter(),
232			Err(arc) => (*arc).clone().into_iter(),
233		}
234	}
235}
236
237impl<T: Clone + PartialEq> Deref for CowVec<T> {
238	type Target = [T];
239
240	fn deref(&self) -> &Self::Target {
241		self.as_slice()
242	}
243}
244
245impl<T: Clone + PartialEq> Borrow<[T]> for CowVec<T> {
246	fn borrow(&self) -> &[T] {
247		self.as_slice()
248	}
249}
250
251impl<T> Serialize for CowVec<T>
252where
253	T: Clone + PartialEq + Serialize,
254{
255	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
256	where
257		S: Serializer,
258	{
259		self.inner.serialize(serializer)
260	}
261}
262
263impl<'de, T> Deserialize<'de> for CowVec<T>
264where
265	T: Clone + PartialEq + Deserialize<'de>,
266{
267	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
268	where
269		D: Deserializer<'de>,
270	{
271		let vec = Vec::<T>::deserialize(deserializer)?;
272		Ok(CowVec {
273			inner: Arc::new(vec),
274		})
275	}
276}
277
278impl<T: Clone + PartialEq> DataVec<T> for CowVec<T> {
279	fn spawn(&self, capacity: usize) -> Self {
280		CowVec::with_capacity(capacity)
281	}
282
283	fn push(&mut self, value: T) {
284		CowVec::push(self, value)
285	}
286
287	fn clear(&mut self) {
288		CowVec::clear(self)
289	}
290
291	fn len(&self) -> usize {
292		CowVec::len(self)
293	}
294
295	fn as_slice(&self) -> &[T] {
296		CowVec::as_slice(self)
297	}
298
299	fn get(&self, idx: usize) -> Option<&T> {
300		CowVec::get(self, idx)
301	}
302
303	fn extend_from_slice(&mut self, other: &[T]) {
304		CowVec::extend_from_slice(self, other)
305	}
306
307	fn extend_iter(&mut self, iter: impl Iterator<Item = T>) {
308		CowVec::extend(self, iter)
309	}
310
311	fn capacity(&self) -> usize {
312		CowVec::capacity(self)
313	}
314
315	fn take(&self, n: usize) -> Self {
316		CowVec::take(self, n)
317	}
318}
319
320#[cfg(test)]
321pub mod tests {
322	use super::CowVec;
323
324	#[test]
325	fn test_new() {
326		let cow = CowVec::new(vec![1, 2, 3]);
327		assert_eq!(cow.get(0), Some(&1));
328		assert_eq!(cow.get(1), Some(&2));
329		assert_eq!(cow.get(2), Some(&3));
330	}
331
332	#[test]
333	fn test_is_owned() {
334		let mut owned = CowVec::new(Vec::with_capacity(16));
335		owned.extend([1, 2]);
336
337		assert!(owned.is_owned());
338
339		let shared = owned.clone();
340		assert!(!owned.is_owned());
341		assert!(!shared.is_owned());
342
343		drop(shared);
344
345		assert!(owned.is_owned());
346	}
347
348	#[test]
349	fn test_is_shared() {
350		let mut owned = CowVec::new(Vec::with_capacity(16));
351		owned.extend([1, 2]);
352
353		assert!(!owned.is_shared());
354
355		let shared = owned.clone();
356		assert!(owned.is_shared());
357		assert!(shared.is_shared());
358
359		drop(shared);
360
361		assert!(!owned.is_shared());
362	}
363
364	#[test]
365	fn test_extend() {
366		let mut owned = CowVec::new(Vec::with_capacity(16));
367		owned.extend([1, 2]);
368
369		let ptr_before_owned = ptr_of(&owned);
370		owned.extend([9, 9, 24]);
371		assert_eq!(ptr_before_owned, ptr_of(&owned)); // no copy
372		assert_eq!(owned.len(), 5);
373
374		let mut shared = owned.clone();
375
376		let ptr_before_shared = ptr_of(&shared);
377		shared.extend([9, 9, 24]);
378		assert_ne!(ptr_before_shared, ptr_of(&shared)); // copy-on-write
379		assert_eq!(owned.len(), 5);
380	}
381
382	#[test]
383	fn test_push() {
384		let mut owned = CowVec::new(Vec::with_capacity(16));
385		owned.extend([1, 2]);
386
387		let ptr_before_owned = ptr_of(&owned);
388		owned.push(99);
389		assert_eq!(ptr_before_owned, ptr_of(&owned)); // no copy
390		assert_eq!(owned.len(), 3);
391
392		let mut shared = owned.clone();
393
394		let ptr_before_shared = ptr_of(&shared);
395		shared.push(99);
396		assert_ne!(ptr_before_shared, ptr_of(&shared)); // copy-on-write
397		assert_eq!(owned.len(), 3);
398	}
399
400	#[test]
401	fn test_set() {
402		let mut owned = CowVec::new(Vec::with_capacity(16));
403		owned.extend([1, 2]);
404
405		let ptr_before_owned = ptr_of(&owned);
406		owned.set(1, 99);
407		assert_eq!(ptr_before_owned, ptr_of(&owned)); // no copy
408		assert_eq!(*owned, [1, 99]);
409
410		let mut shared = owned.clone();
411
412		let ptr_before_shared = ptr_of(&shared);
413		shared.set(1, 99);
414		assert_ne!(ptr_before_shared, ptr_of(&shared)); // copy-on-write
415		assert_eq!(*owned, [1, 99]);
416	}
417
418	#[test]
419	fn test_reorder() {
420		let mut owned = CowVec::new(Vec::with_capacity(16));
421		owned.extend([1, 2]);
422
423		let ptr_before_owned = ptr_of(&owned);
424		owned.reorder(&[1usize, 0]);
425		assert_eq!(ptr_before_owned, ptr_of(&owned)); // no copy
426		assert_eq!(*owned, [2, 1]);
427
428		let mut shared = owned.clone();
429
430		let ptr_before_shared = ptr_of(&shared);
431		shared.reorder(&[1usize, 0]);
432		assert_ne!(ptr_before_shared, ptr_of(&shared)); // copy-on-write
433		assert_eq!(*shared, [1, 2]);
434	}
435
436	#[test]
437	fn test_reorder_identity() {
438		let mut cow = CowVec::new(vec![10, 20, 30]);
439		cow.reorder(&[0, 1, 2]); // no-op
440		assert_eq!(cow.as_slice(), &[10, 20, 30]);
441	}
442
443	#[test]
444	fn test_reorder_basic() {
445		let mut cow = CowVec::new(vec![10, 20, 30]);
446		cow.reorder(&[2, 0, 1]);
447		assert_eq!(cow.as_slice(), &[30, 10, 20]);
448	}
449
450	fn ptr_of(v: &CowVec<i32>) -> *const i32 {
451		v.as_slice().as_ptr()
452	}
453}