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	pub fn as_slice(&self) -> &[T] {
129		&self.inner
130	}
131
132	pub fn is_owned(&self) -> bool {
133		Arc::strong_count(&self.inner) == 1
134	}
135
136	pub fn is_shared(&self) -> bool {
137		Arc::strong_count(&self.inner) > 1
138	}
139
140	pub fn get(&self, idx: usize) -> Option<&T> {
141		self.inner.get(idx)
142	}
143
144	pub fn make_mut(&mut self) -> &mut Vec<T> {
145		Arc::make_mut(&mut self.inner)
146	}
147
148	pub fn set(&mut self, idx: usize, value: T) {
149		self.make_mut()[idx] = value;
150	}
151
152	pub fn push(&mut self, value: T) {
153		self.make_mut().push(value);
154	}
155
156	/// Clear all elements, retaining the allocated capacity when solely owned.
157	pub fn clear(&mut self) {
158		self.make_mut().clear();
159	}
160
161	pub fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
162		self.make_mut().extend(iter);
163	}
164
165	pub fn extend_from_slice(&mut self, slice: &[T]) {
166		self.make_mut().extend_from_slice(slice);
167	}
168
169	pub fn reorder(&mut self, indices: &[usize]) {
170		let vec = self.make_mut();
171		let len = vec.len();
172		assert_eq!(len, indices.len());
173
174		let mut visited = vec![false; len];
175		for start in 0..len {
176			if visited[start] || indices[start] == start {
177				continue;
178			}
179			let mut current = start;
180			while !visited[current] {
181				visited[current] = true;
182				let next = indices[current];
183				if next == start {
184					break;
185				}
186				vec.swap(current, next);
187				current = next;
188			}
189		}
190	}
191
192	/// Get aligned chunks for SIMD processing
193	/// Returns slices that are guaranteed to be aligned and sized for SIMD
194	/// operations
195	pub fn aligned_chunks(&self, chunk_size: usize) -> impl Iterator<Item = &[T]> {
196		self.inner.chunks(chunk_size)
197	}
198
199	/// Get mutable aligned chunks for SIMD processing
200	pub fn aligned_chunks_mut(&mut self, chunk_size: usize) -> impl Iterator<Item = &mut [T]> {
201		self.make_mut().chunks_mut(chunk_size)
202	}
203
204	/// Returns true if the data is suitably aligned for SIMD operations
205	pub fn is_simd_aligned(&self) -> bool {
206		let alignment = 32; // 256-bit SIMD alignment
207		let ptr = self.inner.as_ptr() as usize;
208		ptr.is_multiple_of(alignment)
209	}
210
211	pub fn take(&self, n: usize) -> Self {
212		let len = n.min(self.len());
213		CowVec::new(self.inner[..len].to_vec())
214	}
215}
216
217impl<T: Clone + PartialEq> IntoIterator for CowVec<T> {
218	type Item = T;
219	type IntoIter = vec::IntoIter<T>;
220
221	fn into_iter(self) -> Self::IntoIter {
222		match Arc::try_unwrap(self.inner) {
223			Ok(vec) => vec.into_iter(),
224			Err(arc) => (*arc).clone().into_iter(),
225		}
226	}
227}
228
229impl<T: Clone + PartialEq> Deref for CowVec<T> {
230	type Target = [T];
231
232	fn deref(&self) -> &Self::Target {
233		self.as_slice()
234	}
235}
236
237impl<T: Clone + PartialEq> Borrow<[T]> for CowVec<T> {
238	fn borrow(&self) -> &[T] {
239		self.as_slice()
240	}
241}
242
243impl<T> Serialize for CowVec<T>
244where
245	T: Clone + PartialEq + Serialize,
246{
247	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
248	where
249		S: Serializer,
250	{
251		self.inner.serialize(serializer)
252	}
253}
254
255impl<'de, T> Deserialize<'de> for CowVec<T>
256where
257	T: Clone + PartialEq + Deserialize<'de>,
258{
259	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
260	where
261		D: Deserializer<'de>,
262	{
263		let vec = Vec::<T>::deserialize(deserializer)?;
264		Ok(CowVec {
265			inner: Arc::new(vec),
266		})
267	}
268}
269
270impl<T: Clone + PartialEq> DataVec<T> for CowVec<T> {
271	fn spawn(&self, capacity: usize) -> Self {
272		CowVec::with_capacity(capacity)
273	}
274
275	fn push(&mut self, value: T) {
276		CowVec::push(self, value)
277	}
278
279	fn clear(&mut self) {
280		CowVec::clear(self)
281	}
282
283	fn len(&self) -> usize {
284		CowVec::len(self)
285	}
286
287	fn as_slice(&self) -> &[T] {
288		CowVec::as_slice(self)
289	}
290
291	fn get(&self, idx: usize) -> Option<&T> {
292		CowVec::get(self, idx)
293	}
294
295	fn extend_from_slice(&mut self, other: &[T]) {
296		CowVec::extend_from_slice(self, other)
297	}
298
299	fn extend_iter(&mut self, iter: impl Iterator<Item = T>) {
300		CowVec::extend(self, iter)
301	}
302
303	fn capacity(&self) -> usize {
304		CowVec::capacity(self)
305	}
306
307	fn take(&self, n: usize) -> Self {
308		CowVec::take(self, n)
309	}
310}
311
312#[cfg(test)]
313pub mod tests {
314	use super::CowVec;
315
316	#[test]
317	fn test_new() {
318		let cow = CowVec::new(vec![1, 2, 3]);
319		assert_eq!(cow.get(0), Some(&1));
320		assert_eq!(cow.get(1), Some(&2));
321		assert_eq!(cow.get(2), Some(&3));
322	}
323
324	#[test]
325	fn test_is_owned() {
326		let mut owned = CowVec::new(Vec::with_capacity(16));
327		owned.extend([1, 2]);
328
329		assert!(owned.is_owned());
330
331		let shared = owned.clone();
332		assert!(!owned.is_owned());
333		assert!(!shared.is_owned());
334
335		drop(shared);
336
337		assert!(owned.is_owned());
338	}
339
340	#[test]
341	fn test_is_shared() {
342		let mut owned = CowVec::new(Vec::with_capacity(16));
343		owned.extend([1, 2]);
344
345		assert!(!owned.is_shared());
346
347		let shared = owned.clone();
348		assert!(owned.is_shared());
349		assert!(shared.is_shared());
350
351		drop(shared);
352
353		assert!(!owned.is_shared());
354	}
355
356	#[test]
357	fn test_extend() {
358		let mut owned = CowVec::new(Vec::with_capacity(16));
359		owned.extend([1, 2]);
360
361		let ptr_before_owned = ptr_of(&owned);
362		owned.extend([9, 9, 24]);
363		assert_eq!(ptr_before_owned, ptr_of(&owned)); // no copy
364		assert_eq!(owned.len(), 5);
365
366		let mut shared = owned.clone();
367
368		let ptr_before_shared = ptr_of(&shared);
369		shared.extend([9, 9, 24]);
370		assert_ne!(ptr_before_shared, ptr_of(&shared)); // copy-on-write
371		assert_eq!(owned.len(), 5);
372	}
373
374	#[test]
375	fn test_push() {
376		let mut owned = CowVec::new(Vec::with_capacity(16));
377		owned.extend([1, 2]);
378
379		let ptr_before_owned = ptr_of(&owned);
380		owned.push(99);
381		assert_eq!(ptr_before_owned, ptr_of(&owned)); // no copy
382		assert_eq!(owned.len(), 3);
383
384		let mut shared = owned.clone();
385
386		let ptr_before_shared = ptr_of(&shared);
387		shared.push(99);
388		assert_ne!(ptr_before_shared, ptr_of(&shared)); // copy-on-write
389		assert_eq!(owned.len(), 3);
390	}
391
392	#[test]
393	fn test_set() {
394		let mut owned = CowVec::new(Vec::with_capacity(16));
395		owned.extend([1, 2]);
396
397		let ptr_before_owned = ptr_of(&owned);
398		owned.set(1, 99);
399		assert_eq!(ptr_before_owned, ptr_of(&owned)); // no copy
400		assert_eq!(*owned, [1, 99]);
401
402		let mut shared = owned.clone();
403
404		let ptr_before_shared = ptr_of(&shared);
405		shared.set(1, 99);
406		assert_ne!(ptr_before_shared, ptr_of(&shared)); // copy-on-write
407		assert_eq!(*owned, [1, 99]);
408	}
409
410	#[test]
411	fn test_reorder() {
412		let mut owned = CowVec::new(Vec::with_capacity(16));
413		owned.extend([1, 2]);
414
415		let ptr_before_owned = ptr_of(&owned);
416		owned.reorder(&[1usize, 0]);
417		assert_eq!(ptr_before_owned, ptr_of(&owned)); // no copy
418		assert_eq!(*owned, [2, 1]);
419
420		let mut shared = owned.clone();
421
422		let ptr_before_shared = ptr_of(&shared);
423		shared.reorder(&[1usize, 0]);
424		assert_ne!(ptr_before_shared, ptr_of(&shared)); // copy-on-write
425		assert_eq!(*shared, [1, 2]);
426	}
427
428	#[test]
429	fn test_reorder_identity() {
430		let mut cow = CowVec::new(vec![10, 20, 30]);
431		cow.reorder(&[0, 1, 2]); // no-op
432		assert_eq!(cow.as_slice(), &[10, 20, 30]);
433	}
434
435	#[test]
436	fn test_reorder_basic() {
437		let mut cow = CowVec::new(vec![10, 20, 30]);
438		cow.reorder(&[2, 0, 1]);
439		assert_eq!(cow.as_slice(), &[30, 10, 20]);
440	}
441
442	fn ptr_of(v: &CowVec<i32>) -> *const i32 {
443		v.as_slice().as_ptr()
444	}
445}