Skip to main content

reifydb_type/util/
cowvec.rs

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