diff --git a/benches/lib.rs b/benches/lib.rs index dcde85ae..d1f8acc4 100644 --- a/benches/lib.rs +++ b/benches/lib.rs @@ -129,6 +129,15 @@ fn union_with(c: &mut Criterion) { }); } +fn sub(c: &mut Criterion) { + c.bench_function("sub", |b| { + let bitmap1: RoaringBitmap = (1..100_000).collect(); + let bitmap2: RoaringBitmap = (10..2_000_000).collect(); + + b.iter(|| &bitmap1 - &bitmap2); + }); +} + fn xor(c: &mut Criterion) { c.bench_function("xor", |b| { let bitmap1: RoaringBitmap = (1..100).collect(); @@ -319,6 +328,7 @@ criterion_group!( intersect_with, or, union_with, + sub, xor, symmetric_deference_with, is_subset, diff --git a/src/bitmap/container.rs b/src/bitmap/container.rs index 31bc628c..8aa785c0 100644 --- a/src/bitmap/container.rs +++ b/src/bitmap/container.rs @@ -1,4 +1,4 @@ -use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, SubAssign}; +use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign}; use std::{fmt, ops::Range}; use super::store::{self, Store}; @@ -118,6 +118,21 @@ impl Container { } } +impl BitOr<&Container> for &Container { + type Output = Container; + + fn bitor(self, rhs: &Container) -> Container { + let store = BitOr::bitor(&self.store, &rhs.store); + let mut container = Container { + key: self.key, + len: store.len(), + store, + }; + container.ensure_correct_store(); + container + } +} + impl BitOrAssign for Container { fn bitor_assign(&mut self, rhs: Container) { BitOrAssign::bitor_assign(&mut self.store, rhs.store); @@ -134,6 +149,21 @@ impl BitOrAssign<&Container> for Container { } } +impl BitAnd<&Container> for &Container { + type Output = Container; + + fn bitand(self, rhs: &Container) -> Container { + let store = BitAnd::bitand(&self.store, &rhs.store); + let mut container = Container { + key: self.key, + len: store.len(), + store, + }; + container.ensure_correct_store(); + container + } +} + impl BitAndAssign for Container { fn bitand_assign(&mut self, rhs: Container) { BitAndAssign::bitand_assign(&mut self.store, rhs.store); @@ -150,6 +180,21 @@ impl BitAndAssign<&Container> for Container { } } +impl Sub<&Container> for &Container { + type Output = Container; + + fn sub(self, rhs: &Container) -> Container { + let store = Sub::sub(&self.store, &rhs.store); + let mut container = Container { + key: self.key, + len: store.len(), + store, + }; + container.ensure_correct_store(); + container + } +} + impl SubAssign<&Container> for Container { fn sub_assign(&mut self, rhs: &Container) { SubAssign::sub_assign(&mut self.store, &rhs.store); @@ -158,6 +203,21 @@ impl SubAssign<&Container> for Container { } } +impl BitXor<&Container> for &Container { + type Output = Container; + + fn bitxor(self, rhs: &Container) -> Container { + let store = BitXor::bitxor(&self.store, &rhs.store); + let mut container = Container { + key: self.key, + len: store.len(), + store, + }; + container.ensure_correct_store(); + container + } +} + impl BitXorAssign for Container { fn bitxor_assign(&mut self, rhs: Container) { BitXorAssign::bitxor_assign(&mut self.store, rhs.store); diff --git a/src/bitmap/inherent.rs b/src/bitmap/inherent.rs index 902afe1e..04a20a15 100644 --- a/src/bitmap/inherent.rs +++ b/src/bitmap/inherent.rs @@ -16,6 +16,7 @@ impl RoaringBitmap { pub fn new() -> RoaringBitmap { RoaringBitmap { containers: Vec::new(), + len: 0, } } @@ -42,7 +43,13 @@ impl RoaringBitmap { &mut self.containers[loc] } }; - container.insert(index) + + if container.insert(index) { + self.len += 1; + true + } else { + false + } } /// Inserts a range of values from the set specific as [start..end). Returns @@ -94,7 +101,9 @@ impl RoaringBitmap { // If the end range value is in the same container, just call into // the one container. if start_container_key == end_container_key { - return self.containers[start_i].insert_range(start_index..end_index); + let inserted = self.containers[start_i].insert_range(start_index..end_index); + self.len += inserted; + return inserted; } // For the first container, insert start_index..u16::MAX, with @@ -138,6 +147,8 @@ impl RoaringBitmap { }; c.insert_range(0..end_index); + self.len += inserted; + inserted } @@ -162,12 +173,20 @@ impl RoaringBitmap { let (key, index) = util::split(value); match self.containers.last_mut() { - Some(container) if container.key == key => container.push(index), + Some(container) if container.key == key => { + if container.push(index) { + self.len += 1; + true + } else { + false + } + } Some(container) if container.key > key => false, _otherwise => { let mut container = Container::new(key); container.push(index); self.containers.push(container); + self.len += 1; true } } @@ -194,12 +213,13 @@ impl RoaringBitmap { if self.containers[loc].len == 0 { self.containers.remove(loc); } + self.len -= 1; true } else { false } } - _ => false, + Err(_) => false, } } /// Removes a range of values from the set specific as [start..end). @@ -230,7 +250,7 @@ impl RoaringBitmap { let (start_hi, start_lo) = util::split(range.start as u32); let (end_hi, end_lo) = util::split((range.end - 1) as u32); let mut index = 0; - let mut result = 0; + let mut removed = 0; while index < self.containers.len() { let key = self.containers[index].key; if key >= start_hi && key <= end_hi { @@ -246,11 +266,11 @@ impl RoaringBitmap { }; // remove container? if a == 0 && b == u32::from(u16::max_value()) + 1 { - result += self.containers[index].len; + removed += self.containers[index].len; self.containers.remove(index); continue; } else { - result += self.containers[index].remove_range(a, b); + removed += self.containers[index].remove_range(a, b); if self.containers[index].len == 0 { self.containers.remove(index); continue; @@ -259,7 +279,10 @@ impl RoaringBitmap { } index += 1; } - result + + self.len -= removed; + + removed } /// Returns `true` if this set contains the specified integer. @@ -298,6 +321,7 @@ impl RoaringBitmap { /// ``` pub fn clear(&mut self) { self.containers.clear(); + self.len = 0; } /// Returns `true` if there are no integers in this set. @@ -314,7 +338,7 @@ impl RoaringBitmap { /// assert_eq!(rb.is_empty(), false); /// ``` pub fn is_empty(&self) -> bool { - self.containers.is_empty() + self.len == 0 } /// Returns the number of distinct integers added to the set. @@ -335,7 +359,7 @@ impl RoaringBitmap { /// assert_eq!(rb.len(), 2); /// ``` pub fn len(&self) -> u64 { - self.containers.iter().map(|container| container.len).sum() + self.len } /// Returns the minimum value in the set (if the set is non-empty). diff --git a/src/bitmap/mod.rs b/src/bitmap/mod.rs index 7a354050..00c7c5a1 100644 --- a/src/bitmap/mod.rs +++ b/src/bitmap/mod.rs @@ -33,4 +33,5 @@ pub use self::iter::Iter; #[derive(PartialEq, Clone)] pub struct RoaringBitmap { containers: Vec, + len: u64, } diff --git a/src/bitmap/ops.rs b/src/bitmap/ops.rs index 11f42a6d..59dc822f 100644 --- a/src/bitmap/ops.rs +++ b/src/bitmap/ops.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use std::mem; use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign}; +use std::{cmp, mem}; use retain_mut::RetainMut; @@ -191,11 +191,44 @@ impl BitOr<&RoaringBitmap> for &RoaringBitmap { /// An `union` between two sets. fn bitor(self, rhs: &RoaringBitmap) -> RoaringBitmap { - if self.len() <= rhs.len() { - BitOr::bitor(rhs.clone(), self) - } else { - BitOr::bitor(self.clone(), rhs) + let len = cmp::max(self.containers.len(), rhs.containers.len()); + let mut containers = Vec::with_capacity(len); + let mut len = 0; + + let mut iter_lhs = self.containers.iter().peekable(); + let mut iter_rhs = rhs.containers.iter().peekable(); + + loop { + match (iter_lhs.peek(), iter_rhs.peek()) { + (Some(lhs), Some(rhs)) => { + let container = match lhs.key.cmp(&rhs.key) { + Ordering::Less => iter_lhs.next().cloned().unwrap(), + Ordering::Greater => iter_rhs.next().cloned().unwrap(), + Ordering::Equal => { + let (lhs, rhs) = iter_lhs.next().zip(iter_rhs.next()).unwrap(); + BitOr::bitor(lhs, rhs) + } + }; + len += container.len; + containers.push(container); + } + (Some(_), None) => { + iter_lhs.by_ref().cloned().for_each(|container| { + len += container.len; + containers.push(container); + }); + } + (None, Some(_)) => { + iter_rhs.by_ref().cloned().for_each(|container| { + len += container.len; + containers.push(container); + }); + } + (None, None) => break, + } } + + RoaringBitmap { containers, len } } } @@ -210,8 +243,16 @@ impl BitOrAssign for RoaringBitmap { for container in rhs.containers { let key = container.key; match self.containers.binary_search_by_key(&key, |c| c.key) { - Err(loc) => self.containers.insert(loc, container), - Ok(loc) => BitOrAssign::bitor_assign(&mut self.containers[loc], container), + Err(loc) => { + self.len += container.len; + self.containers.insert(loc, container); + } + Ok(loc) => { + let this_container = &mut self.containers[loc]; + self.len -= this_container.len; + BitOrAssign::bitor_assign(this_container, container); + self.len += this_container.len; + } } } } @@ -223,8 +264,16 @@ impl BitOrAssign<&RoaringBitmap> for RoaringBitmap { for container in &rhs.containers { let key = container.key; match self.containers.binary_search_by_key(&key, |c| c.key) { - Err(loc) => self.containers.insert(loc, container.clone()), - Ok(loc) => BitOrAssign::bitor_assign(&mut self.containers[loc], container), + Err(loc) => { + self.len += container.len; + self.containers.insert(loc, container.clone()); + } + Ok(loc) => { + let this_container = &mut self.containers[loc]; + self.len -= this_container.len; + BitOrAssign::bitor_assign(this_container, container); + self.len += this_container.len; + } } } } @@ -264,11 +313,30 @@ impl BitAnd<&RoaringBitmap> for &RoaringBitmap { /// An `intersection` between two sets. fn bitand(self, rhs: &RoaringBitmap) -> RoaringBitmap { - if rhs.len() < self.len() { - BitAnd::bitand(self.clone(), rhs) - } else { - BitAnd::bitand(rhs.clone(), self) + let mut containers = Vec::new(); + let mut len = 0; + + let mut iter_lhs = self.containers.iter().peekable(); + let mut iter_rhs = rhs.containers.iter().peekable(); + + loop { + match (iter_lhs.peek(), iter_rhs.peek()) { + (None, None) => break, + (Some(lhs), Some(rhs)) => { + if lhs.key == rhs.key { + let (lhs, rhs) = iter_lhs.next().zip(iter_rhs.next()).unwrap(); + let container = BitAnd::bitand(lhs, rhs); + if container.len != 0 { + len += container.len; + containers.push(container); + } + } + } + _otherwise => (), + } } + + RoaringBitmap { containers, len } } } @@ -280,34 +348,58 @@ impl BitAndAssign for RoaringBitmap { mem::swap(self, &mut rhs); } + let mut removed = 0; self.containers.retain_mut(|cont| { let key = cont.key; match rhs.containers.binary_search_by_key(&key, |c| c.key) { Ok(loc) => { let rhs_cont = &mut rhs.containers[loc]; let rhs_cont = mem::replace(rhs_cont, Container::new(rhs_cont.key)); + removed += cont.len; BitAndAssign::bitand_assign(cont, rhs_cont); - cont.len != 0 + if cont.len != 0 { + removed -= cont.len; + true + } else { + false + } + } + Err(_) => { + removed += cont.len; + false } - Err(_) => false, } - }) + }); + + self.len -= removed; } } impl BitAndAssign<&RoaringBitmap> for RoaringBitmap { /// An `intersection` between two sets. fn bitand_assign(&mut self, rhs: &RoaringBitmap) { + let mut removed = 0; self.containers.retain_mut(|cont| { let key = cont.key; match rhs.containers.binary_search_by_key(&key, |c| c.key) { Ok(loc) => { + removed += cont.len; BitAndAssign::bitand_assign(cont, &rhs.containers[loc]); - cont.len != 0 + if cont.len != 0 { + removed -= cont.len; + true + } else { + false + } + } + Err(_) => { + removed += cont.len; + false } - Err(_) => false, } - }) + }); + + self.len -= removed; } } @@ -336,7 +428,7 @@ impl Sub for &RoaringBitmap { /// A `difference` between two sets. fn sub(self, rhs: RoaringBitmap) -> RoaringBitmap { - Sub::sub(self.clone(), rhs) + Sub::sub(self, &rhs) } } @@ -345,7 +437,45 @@ impl Sub<&RoaringBitmap> for &RoaringBitmap { /// A `difference` between two sets. fn sub(self, rhs: &RoaringBitmap) -> RoaringBitmap { - Sub::sub(self.clone(), rhs) + let mut containers = Vec::new(); + let mut len = 0; + + let mut iter_lhs = self.containers.iter().peekable(); + let mut iter_rhs = rhs.containers.iter().peekable(); + + loop { + match (iter_lhs.peek(), iter_rhs.peek()) { + (None, None) => break, + (Some(_), None) => { + let container = iter_lhs.next().cloned().unwrap(); + len += container.len; + containers.push(container); + } + (None, Some(_)) => { + iter_rhs.next().unwrap(); + } + (Some(lhs), Some(rhs)) => match lhs.key.cmp(&rhs.key) { + Ordering::Less => { + let container = iter_lhs.next().cloned().unwrap(); + len += container.len; + containers.push(container); + } + Ordering::Equal => { + let (lhs, rhs) = iter_lhs.next().zip(iter_rhs.next()).unwrap(); + let container = Sub::sub(lhs, rhs); + if container.len != 0 { + len += container.len; + containers.push(container); + } + } + Ordering::Greater => { + iter_rhs.next().unwrap(); + } + }, + } + } + + RoaringBitmap { containers, len } } } @@ -359,15 +489,24 @@ impl SubAssign for RoaringBitmap { impl SubAssign<&RoaringBitmap> for RoaringBitmap { /// A `difference` between two sets. fn sub_assign(&mut self, rhs: &RoaringBitmap) { + let mut removed = 0; self.containers.retain_mut(|cont| { match rhs.containers.binary_search_by_key(&cont.key, |c| c.key) { Ok(loc) => { + removed += cont.len; SubAssign::sub_assign(cont, &rhs.containers[loc]); - cont.len != 0 + if cont.len != 0 { + removed -= cont.len; + true + } else { + false + } } Err(_) => true, } - }) + }); + + self.len -= removed; } } @@ -405,11 +544,38 @@ impl BitXor<&RoaringBitmap> for &RoaringBitmap { /// A `symmetric difference` between two sets. fn bitxor(self, rhs: &RoaringBitmap) -> RoaringBitmap { - if self.len() < rhs.len() { - BitXor::bitxor(self, rhs.clone()) - } else { - BitXor::bitxor(self.clone(), rhs) + let mut containers = Vec::new(); + let mut len = 0; + + let mut iter_lhs = self.containers.iter().peekable(); + let mut iter_rhs = rhs.containers.iter().peekable(); + + loop { + match (iter_lhs.peek(), iter_rhs.peek()) { + (None, None) => break, + (Some(_), None) => containers.extend(iter_lhs.by_ref().cloned()), + (None, Some(_)) => containers.extend(iter_rhs.by_ref().cloned()), + (Some(lhs), Some(rhs)) => { + let container = match lhs.key.cmp(&rhs.key) { + Ordering::Equal => { + let (lhs, rhs) = iter_lhs.next().zip(iter_rhs.next()).unwrap(); + let container = BitXor::bitxor(lhs, rhs); + if container.len != 0 { + container + } else { + continue; + } + } + Ordering::Less => iter_lhs.next().cloned().unwrap(), + Ordering::Greater => iter_rhs.next().cloned().unwrap(), + }; + len += container.len; + containers.push(container); + } + } } + + RoaringBitmap { containers, len } } } @@ -419,33 +585,46 @@ impl BitXorAssign for RoaringBitmap { let mut left = mem::take(&mut self.containers).into_iter().peekable(); let mut right = rhs.containers.into_iter().peekable(); + self.len = 0; + loop { match (left.peek(), right.peek()) { (None, None) => break, (Some(_), None) => { - self.containers.extend(left); + self.containers.reserve(left.len()); + left.for_each(|container| { + self.len += container.len; + self.containers.push(container); + }); break; } (None, Some(_)) => { - self.containers.extend(right); + self.containers.reserve(right.len()); + right.for_each(|container| { + self.len += container.len; + self.containers.push(container); + }); break; } (Some(l), Some(r)) => match l.key.cmp(&r.key) { Ordering::Equal => { - let mut lhs = left.next().unwrap(); + let mut container = left.next().unwrap(); let rhs = right.next().unwrap(); - BitXorAssign::bitxor_assign(&mut lhs, rhs); - if lhs.len != 0 { - self.containers.push(lhs); + BitXorAssign::bitxor_assign(&mut container, rhs); + if container.len != 0 { + self.len += container.len; + self.containers.push(container); } } Ordering::Less => { - let lhs = left.next().unwrap(); - self.containers.push(lhs); + let container = left.next().unwrap(); + self.len += container.len; + self.containers.push(container); } Ordering::Greater => { - let rhs = right.next().unwrap(); - self.containers.push(rhs); + let container = right.next().unwrap(); + self.len += container.len; + self.containers.push(container); } }, } @@ -459,33 +638,45 @@ impl BitXorAssign<&RoaringBitmap> for RoaringBitmap { let mut left = mem::take(&mut self.containers).into_iter().peekable(); let mut right = rhs.containers.iter().peekable(); + self.len = 0; + loop { match (left.peek(), right.peek()) { (None, None) => break, (Some(_), None) => { - self.containers.extend(left); + self.containers.reserve(left.len()); + left.for_each(|container| { + self.len += container.len; + self.containers.push(container); + }); break; } (None, Some(_)) => { - self.containers.extend(right.cloned()); + self.containers.reserve(right.len()); + right.cloned().for_each(|container| { + self.len += container.len; + self.containers.push(container); + }); break; } (Some(l), Some(r)) => match l.key.cmp(&r.key) { Ordering::Equal => { - let mut lhs = left.next().unwrap(); - let rhs = right.next().unwrap(); - BitXorAssign::bitxor_assign(&mut lhs, rhs); - if lhs.len != 0 { - self.containers.push(lhs); + let (mut container, rhs) = left.next().zip(right.next()).unwrap(); + BitXorAssign::bitxor_assign(&mut container, rhs); + if container.len != 0 { + self.len += container.len; + self.containers.push(container); } } Ordering::Less => { - let lhs = left.next().unwrap(); - self.containers.push(lhs); + let container = left.next().unwrap(); + self.len += container.len; + self.containers.push(container); } Ordering::Greater => { - let rhs = right.next().unwrap(); - self.containers.push(rhs.clone()); + let container = right.next().unwrap(); + self.len += container.len; + self.containers.push(container.clone()); } }, } diff --git a/src/bitmap/serialization.rs b/src/bitmap/serialization.rs index da49a7d7..3015cc9c 100644 --- a/src/bitmap/serialization.rs +++ b/src/bitmap/serialization.rs @@ -149,6 +149,7 @@ impl RoaringBitmap { } let mut containers = Vec::with_capacity(size); + let mut total_len = 0; for _ in 0..size { let key = description_bytes.read_u16::()?; @@ -167,8 +168,12 @@ impl RoaringBitmap { }; containers.push(Container { key, len, store }); + total_len += len; } - Ok(RoaringBitmap { containers }) + Ok(RoaringBitmap { + containers, + len: total_len, + }) } } diff --git a/src/bitmap/store.rs b/src/bitmap/store.rs index a4b348fd..0d6d0167 100644 --- a/src/bitmap/store.rs +++ b/src/bitmap/store.rs @@ -1,5 +1,5 @@ use std::cmp::Ordering::{Equal, Greater, Less}; -use std::ops::{BitAndAssign, BitOrAssign, BitXorAssign, SubAssign}; +use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Sub, SubAssign}; use std::{borrow::Borrow, ops::Range}; use std::{mem, slice, vec}; @@ -307,6 +307,31 @@ impl Store { } } +impl BitOr<&Store> for &Store { + type Output = Store; + + fn bitor(self, rhs: &Store) -> Store { + match (self, rhs) { + (&Array(ref vec1), &Array(ref vec2)) => Array(union_arrays(vec1, vec2)), + (&Bitmap(_), &Array(_)) => { + let mut lhs = self.clone(); + BitOrAssign::bitor_assign(&mut lhs, rhs); + lhs + } + (&Bitmap(_), &Bitmap(_)) => { + let mut lhs = self.clone(); + BitOrAssign::bitor_assign(&mut lhs, rhs); + lhs + } + (&Array(_), &Bitmap(_)) => { + let mut rhs = rhs.clone(); + BitOrAssign::bitor_assign(&mut rhs, self); + rhs + } + } + } +} + impl BitOrAssign for Store { fn bitor_assign(&mut self, mut rhs: Store) { match (self, &mut rhs) { @@ -356,6 +381,31 @@ impl BitOrAssign<&Store> for Store { } } +impl BitAnd<&Store> for &Store { + type Output = Store; + + fn bitand(self, rhs: &Store) -> Store { + match (self, rhs) { + (&Array(ref vec1), &Array(ref vec2)) => Array(intersect_arrays(vec1, vec2)), + (&Bitmap(_), &Array(_)) => { + let mut rhs = rhs.clone(); + BitAndAssign::bitand_assign(&mut rhs, self); + rhs + } + (&Bitmap(_), &Bitmap(_)) => { + let mut lhs = self.clone(); + BitAndAssign::bitand_assign(&mut lhs, rhs); + lhs + } + (&Array(_), &Bitmap(_)) => { + let mut lhs = self.clone(); + BitAndAssign::bitand_assign(&mut lhs, rhs); + lhs + } + } + } +} + impl BitAndAssign for Store { #[allow(clippy::suspicious_op_assign_impl)] fn bitand_assign(&mut self, mut rhs: Store) { @@ -423,6 +473,31 @@ impl BitAndAssign<&Store> for Store { } } +impl Sub<&Store> for &Store { + type Output = Store; + + fn sub(self, rhs: &Store) -> Store { + match (self, rhs) { + (&Array(ref vec1), &Array(ref vec2)) => Array(difference_arrays(vec1, vec2)), + (&Bitmap(_), &Array(_)) => { + let mut lhs = self.clone(); + BitOrAssign::bitor_assign(&mut lhs, rhs); + lhs + } + (&Bitmap(_), &Bitmap(_)) => { + let mut lhs = self.clone(); + BitOrAssign::bitor_assign(&mut lhs, rhs); + lhs + } + (&Array(_), &Bitmap(_)) => { + let mut lhs = self.clone(); + BitOrAssign::bitor_assign(&mut lhs, rhs); + lhs + } + } + } +} + impl SubAssign<&Store> for Store { fn sub_assign(&mut self, rhs: &Store) { match (self, rhs) { @@ -450,6 +525,31 @@ impl SubAssign<&Store> for Store { } } +impl BitXor<&Store> for &Store { + type Output = Store; + + fn bitxor(self, rhs: &Store) -> Store { + match (self, rhs) { + (&Array(ref vec1), &Array(ref vec2)) => Array(symmetric_difference_arrays(vec1, vec2)), + (&Bitmap(_), &Array(_)) => { + let mut lhs = self.clone(); + BitXorAssign::bitxor_assign(&mut lhs, rhs); + lhs + } + (&Bitmap(_), &Bitmap(_)) => { + let mut lhs = self.clone(); + BitXorAssign::bitxor_assign(&mut lhs, rhs); + lhs + } + (&Array(_), &Bitmap(_)) => { + let mut lhs = rhs.clone(); + BitXorAssign::bitxor_assign(&mut lhs, self); + lhs + } + } + } +} + impl BitXorAssign for Store { fn bitxor_assign(&mut self, mut rhs: Store) { // TODO improve this function @@ -670,15 +770,101 @@ fn union_arrays(arr1: &[u16], arr2: &[u16]) -> Vec { match a.cmp(&b) { Less => { out.push(*a); - i += 1 + i += 1; } Greater => { out.push(*b); - j += 1 + j += 1; + } + Equal => { + out.push(*a); + i += 1; + j += 1; + } + } + } + + // Store remaining elements of the arrays + out.extend_from_slice(&arr1[i..]); + out.extend_from_slice(&arr2[j..]); + + out +} + +#[inline] +fn intersect_arrays(arr1: &[u16], arr2: &[u16]) -> Vec { + let mut out = Vec::new(); + + // Traverse both arrays + let mut i = 0; + let mut j = 0; + while i < arr1.len() && j < arr2.len() { + let a = unsafe { arr1.get_unchecked(i) }; + let b = unsafe { arr2.get_unchecked(j) }; + match a.cmp(&b) { + Less => i += 1, + Greater => j += 1, + Equal => { + out.push(*a); + i += 1; + j += 1; + } + } + } + + out +} + +#[inline] +fn difference_arrays(arr1: &[u16], arr2: &[u16]) -> Vec { + let mut out = Vec::new(); + + // Traverse both arrays + let mut i = 0; + let mut j = 0; + while i < arr1.len() && j < arr2.len() { + let a = unsafe { arr1.get_unchecked(i) }; + let b = unsafe { arr2.get_unchecked(j) }; + match a.cmp(&b) { + Less => { + out.push(*a); + i += 1; } + Greater => j += 1, Equal => { + i += 1; + j += 1; + } + } + } + + // Store remaining elements of the left array + out.extend_from_slice(&arr1[i..]); + + out +} + +#[inline] +fn symmetric_difference_arrays(arr1: &[u16], arr2: &[u16]) -> Vec { + let mut out = Vec::new(); + + // Traverse both arrays + let mut i = 0; + let mut j = 0; + while i < arr1.len() && j < arr2.len() { + let a = unsafe { arr1.get_unchecked(i) }; + let b = unsafe { arr2.get_unchecked(j) }; + match a.cmp(&b) { + Less => { out.push(*a); i += 1; + } + Greater => { + out.push(*b); + j += 1; + } + Equal => { + i += 1; j += 1; } }