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