reifydb_type/util/
cowvec.rs

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