use crate::AndNot;
use smallvec::SmallVec;
use std::cmp::Ordering;
use std::iter::FromIterator;
use std::ops::{BitAnd, BitOr};
use std::{fmt, slice};
const DEFAULT_STACK_ALLOC: usize = 1;
#[derive(Serialize, Deserialize, Debug, Clone)]
struct IDLRange {
range: u64,
mask: u64,
}
impl Ord for IDLRange {
fn cmp(&self, other: &Self) -> Ordering {
self.range.cmp(&other.range)
}
}
impl PartialOrd for IDLRange {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialEq for IDLRange {
fn eq(&self, other: &Self) -> bool {
self.range == other.range
}
}
impl Eq for IDLRange {}
impl IDLRange {
fn new(range: u64, mask: u64) -> Self {
IDLRange { range, mask }
}
fn push_id(&mut self, value: u64) {
let nmask = 1 << value;
self.mask ^= nmask;
}
}
#[derive(Serialize, Deserialize, PartialEq, Clone)]
pub struct IDLBitRange {
list: SmallVec<[IDLRange; DEFAULT_STACK_ALLOC]>,
}
impl Default for IDLBitRange {
fn default() -> Self {
Self::new()
}
}
impl IDLBitRange {
pub fn new() -> Self {
IDLBitRange {
list: SmallVec::new(),
}
}
fn with_capacity(cap: usize) -> Self {
IDLBitRange {
list: SmallVec::with_capacity(cap),
}
}
pub fn from_u64(id: u64) -> Self {
let mut new = IDLBitRange::new();
unsafe {
new.push_id(id);
}
new
}
fn bstbitand(&self, candidate: &IDLRange) -> Self {
let mut result = IDLBitRange::new();
if let Ok(idx) = self.list.binary_search(candidate) {
let existing = self.list.get(idx).unwrap();
let mask = existing.mask & candidate.mask;
if mask > 0 {
let newrange = IDLRange::new(candidate.range, mask);
result.list.push(newrange);
};
};
result
}
pub fn contains(&self, id: u64) -> bool {
let bvalue: u64 = id % 64;
let range: u64 = id - bvalue;
let candidate = IDLRange::new(range, 1 << bvalue);
if let Ok(idx) = self.list.binary_search(&candidate) {
let existing = self.list.get(idx).unwrap();
let mask = existing.mask & candidate.mask;
mask > 0
} else {
false
}
}
pub fn insert_id(&mut self, value: u64) {
let bvalue: u64 = value % 64;
let range: u64 = value - bvalue;
let candidate = IDLRange::new(range, 1 << bvalue);
let r = self.list.binary_search(&candidate);
match r {
Ok(idx) => {
let existing = self.list.get_mut(idx).unwrap();
existing.mask |= candidate.mask;
}
Err(idx) => {
self.list.insert(idx, candidate);
}
}
}
pub fn remove_id(&mut self, value: u64) {
let bvalue: u64 = value % 64;
let range: u64 = value - bvalue;
let candidate = IDLRange::new(range, 1 << bvalue);
if let Ok(idx) = self.list.binary_search(&candidate) {
let existing = self.list.get_mut(idx).unwrap();
existing.mask &= !candidate.mask;
if existing.mask == 0 {
self.list.remove(idx);
}
}
}
pub unsafe fn push_id(&mut self, value: u64) {
let bvalue: u64 = value % 64;
let range: u64 = value - bvalue;
if let Some(last) = self.list.last_mut() {
if last.range == range {
(*last).push_id(bvalue);
return;
}
}
let newrange = IDLRange::new(range, 1 << bvalue);
self.list.push(newrange);
}
#[inline(always)]
pub fn len(&self) -> usize {
self.list
.iter()
.fold(0, |acc, i| (i.mask.count_ones() as usize) + acc)
}
#[inline(always)]
pub fn below_threshold(&self, threshold: usize) -> bool {
let mut ic: usize = 0;
for i in self.list.iter() {
ic += i.mask.count_ones() as usize;
if ic >= threshold {
return false;
}
}
true
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.list.len() == 0
}
#[inline(always)]
pub fn len_range(&self) -> usize {
self.list.len()
}
#[inline(always)]
pub fn sum(&self) -> u64 {
let mut result: u64 = 0;
for id in self {
result += id;
}
result
}
#[inline(always)]
fn bitand_inner(&self, rhs: &Self) -> Self {
let llen = self.len_range();
let rlen = rhs.len_range();
if llen == 1 {
return rhs.bstbitand(self.list.first().unwrap());
} else if rlen == 1 {
return self.bstbitand(rhs.list.first().unwrap());
}
let mut result = if llen < rlen {
IDLBitRange::with_capacity(llen)
} else {
IDLBitRange::with_capacity(rlen)
};
let mut liter = self.list.iter();
let mut riter = rhs.list.iter();
let mut lnextrange = liter.next();
let mut rnextrange = riter.next();
while lnextrange.is_some() && rnextrange.is_some() {
let l = lnextrange.unwrap();
let r = rnextrange.unwrap();
match l.range.cmp(&r.range) {
Ordering::Equal => {
let mask = l.mask & r.mask;
if mask > 0 {
let newrange = IDLRange::new(l.range, mask);
result.list.push(newrange);
}
lnextrange = liter.next();
rnextrange = riter.next();
}
Ordering::Less => lnextrange = liter.next(),
Ordering::Greater => rnextrange = riter.next(),
}
}
result
}
#[inline(always)]
fn bitor_inner(&self, rhs: &Self) -> Self {
let llen = self.len_range();
let rlen = rhs.len_range();
let mut result = if llen > rlen {
IDLBitRange::with_capacity(llen)
} else {
IDLBitRange::with_capacity(rlen)
};
let mut liter = self.list.iter();
let mut riter = rhs.list.iter();
let mut lnextrange = liter.next();
let mut rnextrange = riter.next();
while lnextrange.is_some() && rnextrange.is_some() {
let l = lnextrange.unwrap();
let r = rnextrange.unwrap();
let (range, mask) = match l.range.cmp(&r.range) {
Ordering::Equal => {
lnextrange = liter.next();
rnextrange = riter.next();
(l.range, l.mask | r.mask)
}
Ordering::Less => {
lnextrange = liter.next();
(l.range, l.mask)
}
Ordering::Greater => {
rnextrange = riter.next();
(r.range, r.mask)
}
};
let newrange = IDLRange::new(range, mask);
result.list.push(newrange);
}
while lnextrange.is_some() {
let l = lnextrange.unwrap();
let newrange = IDLRange::new(l.range, l.mask);
result.list.push(newrange);
lnextrange = liter.next();
}
while rnextrange.is_some() {
let r = rnextrange.unwrap();
let newrange = IDLRange::new(r.range, r.mask);
result.list.push(newrange);
rnextrange = riter.next();
}
result
}
#[inline(always)]
fn bitandnot_inner(&self, rhs: &Self) -> Self {
let llen = self.len_range();
let rlen = rhs.len_range();
let mut result = if llen > rlen {
IDLBitRange::with_capacity(llen)
} else {
IDLBitRange::with_capacity(rlen)
};
let mut liter = self.list.iter();
let mut riter = rhs.list.iter();
let mut lnextrange = liter.next();
let mut rnextrange = riter.next();
while lnextrange.is_some() && rnextrange.is_some() {
let l = lnextrange.unwrap();
let r = rnextrange.unwrap();
match l.range.cmp(&r.range) {
Ordering::Equal => {
let mask = l.mask & (!r.mask);
if mask > 0 {
let newrange = IDLRange::new(l.range, mask);
result.list.push(newrange);
}
lnextrange = liter.next();
rnextrange = riter.next();
}
Ordering::Less => {
result.list.push(l.clone());
lnextrange = liter.next();
}
Ordering::Greater => {
rnextrange = riter.next();
}
}
}
while lnextrange.is_some() {
let l = lnextrange.unwrap();
let newrange = IDLRange::new(l.range, l.mask);
result.list.push(newrange);
lnextrange = liter.next();
}
result
}
}
impl FromIterator<u64> for IDLBitRange {
fn from_iter<I: IntoIterator<Item = u64>>(iter: I) -> Self {
let iter = iter.into_iter();
let (lower_bound, _) = iter.size_hint();
let mut new = IDLBitRange {
list: SmallVec::with_capacity(lower_bound),
};
let mut max_seen = 0;
iter.for_each(|i| {
if i >= max_seen {
unsafe {
new.push_id(i);
}
max_seen = i;
} else {
new.insert_id(i);
}
});
new
}
}
impl BitAnd for &IDLBitRange {
type Output = IDLBitRange;
fn bitand(self, rhs: &IDLBitRange) -> IDLBitRange {
self.bitand_inner(rhs)
}
}
impl BitAnd for IDLBitRange {
type Output = IDLBitRange;
fn bitand(self, rhs: IDLBitRange) -> IDLBitRange {
self.bitand_inner(&rhs)
}
}
impl BitOr for &IDLBitRange {
type Output = IDLBitRange;
fn bitor(self, rhs: &IDLBitRange) -> IDLBitRange {
self.bitor_inner(rhs)
}
}
impl BitOr for IDLBitRange {
type Output = IDLBitRange;
fn bitor(self, rhs: Self) -> IDLBitRange {
self.bitor_inner(&rhs)
}
}
impl AndNot for IDLBitRange {
type Output = IDLBitRange;
fn andnot(self, rhs: Self) -> IDLBitRange {
self.bitandnot_inner(&rhs)
}
}
impl AndNot for &IDLBitRange {
type Output = IDLBitRange;
fn andnot(self, rhs: &IDLBitRange) -> IDLBitRange {
self.bitandnot_inner(rhs)
}
}
#[derive(Debug)]
pub struct IDLBitRangeIter<'a> {
rangeiter: slice::Iter<'a, IDLRange>,
currange: Option<&'a IDLRange>,
curbit: u64,
}
impl<'a> Iterator for IDLBitRangeIter<'a> {
type Item = u64;
fn next(&mut self) -> Option<u64> {
while self.currange.is_some() {
let range = self.currange.unwrap();
while self.curbit < 64 {
let m: u64 = 1 << self.curbit;
let candidate: u64 = range.mask & m;
if candidate > 0 {
let result = Some(self.curbit + range.range);
self.curbit += 1;
return result;
}
self.curbit += 1;
}
self.currange = self.rangeiter.next();
self.curbit = 0;
}
None
}
}
impl<'a> IntoIterator for &'a IDLBitRange {
type Item = u64;
type IntoIter = IDLBitRangeIter<'a>;
fn into_iter(self) -> IDLBitRangeIter<'a> {
let mut liter = (&self.list).into_iter();
let nrange = liter.next();
IDLBitRangeIter {
rangeiter: liter,
currange: nrange,
curbit: 0,
}
}
}
impl fmt::Display for IDLBitRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"IDLBitRange (compressed ranges) {:?} (decompressed) <optimised out>",
self.list.len()
)
}
}
impl fmt::Debug for IDLBitRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"IDLBitRange (compressed) {:?} (decompressed) [ ",
self.list
)?;
for id in self {
write!(f, "{}, ", id)?;
}
write!(f, "]")
}
}
#[cfg(test)]
mod tests {
use super::IDLBitRange;
use crate::AndNot;
use std::iter::FromIterator;
#[test]
fn test_store_zero() {
let idl_a = IDLBitRange::from_iter(vec![0]);
assert!(idl_a.contains(0));
}
#[test]
fn test_contains() {
let idl_a = IDLBitRange::from_iter(vec![0, 1, 2]);
assert!(idl_a.contains(2));
assert!(!idl_a.contains(3));
assert!(!idl_a.contains(65));
}
#[test]
fn test_remove_id() {
let mut idl_a = IDLBitRange::from_iter(vec![0, 1, 2, 3, 4]);
let idl_ex = IDLBitRange::from_iter(vec![0, 1, 3, 4]);
idl_a.remove_id(2);
assert!(idl_ex == idl_a);
idl_a.remove_id(2);
assert!(idl_ex == idl_a);
}
#[test]
fn test_len() {
let idl_a = IDLBitRange::new();
assert_eq!(idl_a.len(), 0);
let idl_b = IDLBitRange::from_iter(vec![0, 1, 2]);
assert_eq!(idl_b.len(), 3);
let idl_c = IDLBitRange::from_iter(vec![0, 64, 128]);
assert_eq!(idl_c.len(), 3);
}
#[test]
fn test_from_iter() {
let idl_a = IDLBitRange::from_iter(vec![1, 2, 64, 68]);
let idl_b = IDLBitRange::from_iter(vec![64, 68, 2, 1]);
let idl_c = IDLBitRange::from_iter(vec![68, 64, 1, 2]);
let idl_d = IDLBitRange::from_iter(vec![2, 1, 68, 64]);
let idl_expect = IDLBitRange::from_iter(vec![1, 2, 64, 68]);
assert_eq!(idl_a, idl_expect);
assert_eq!(idl_b, idl_expect);
assert_eq!(idl_c, idl_expect);
assert_eq!(idl_d, idl_expect);
}
#[test]
fn test_range_intersection_1() {
let idl_a = IDLBitRange::from_iter(vec![1, 2, 3]);
let idl_b = IDLBitRange::from_iter(vec![2]);
let idl_expect = IDLBitRange::from_iter(vec![2]);
let idl_result = idl_a & idl_b;
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_intersection_2() {
let idl_a = IDLBitRange::from_iter(vec![1, 2, 3]);
let idl_b = IDLBitRange::from_iter(vec![4, 67]);
let idl_expect = IDLBitRange::new();
let idl_result = idl_a & idl_b;
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_intersection_3() {
let idl_a = IDLBitRange::from_iter(vec![1, 2, 3, 4, 35, 64, 65, 128, 150]);
let idl_b = IDLBitRange::from_iter(vec![2, 3, 8, 35, 64, 128, 130, 150, 152, 180]);
let idl_expect = IDLBitRange::from_iter(vec![2, 3, 35, 64, 128, 150]);
let idl_result = idl_a & idl_b;
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_intersection_4() {
let idl_a = IDLBitRange::from_iter(vec![
2, 3, 8, 35, 64, 128, 130, 150, 152, 180, 256, 800, 900,
]);
let idl_b = IDLBitRange::from_iter(1..1024);
let idl_expect = IDLBitRange::from_iter(vec![
2, 3, 8, 35, 64, 128, 130, 150, 152, 180, 256, 800, 900,
]);
let idl_result = idl_a & idl_b;
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_intersection_5() {
let idl_a = IDLBitRange::from_iter(1..204800);
let idl_b = IDLBitRange::from_iter(102400..307200);
let idl_expect = IDLBitRange::from_iter(102400..204800);
let idl_result = idl_a & idl_b;
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_intersection_6() {
let idl_a = IDLBitRange::from_iter(vec![307199]);
let idl_b = IDLBitRange::from_iter(102400..307200);
let idl_expect = IDLBitRange::from_iter(vec![307199]);
let idl_result = idl_a & idl_b;
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_union_1() {
let idl_a = IDLBitRange::from_iter(vec![1, 2, 3]);
let idl_b = IDLBitRange::from_iter(vec![2]);
let idl_expect = IDLBitRange::from_iter(vec![1, 2, 3]);
let idl_result = idl_a | idl_b;
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_union_2() {
let idl_a = IDLBitRange::from_iter(vec![1, 2, 3]);
let idl_b = IDLBitRange::from_iter(vec![4, 67]);
let idl_expect = IDLBitRange::from_iter(vec![1, 2, 3, 4, 67]);
let idl_result = idl_a | idl_b;
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_union_3() {
let idl_a = IDLBitRange::from_iter(vec![
2, 3, 8, 35, 64, 128, 130, 150, 152, 180, 256, 800, 900,
]);
let idl_b = IDLBitRange::from_iter(1..1024);
let idl_expect = IDLBitRange::from_iter(1..1024);
let idl_result = idl_a | idl_b;
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_not_1() {
let idl_a = IDLBitRange::from_iter(vec![1, 2, 3, 4, 5, 6]);
let idl_b = IDLBitRange::from_iter(vec![3, 4]);
let idl_expect = IDLBitRange::from_iter(vec![1, 2, 5, 6]);
let idl_result = idl_a.andnot(idl_b);
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_not_2() {
let idl_a = IDLBitRange::from_iter(vec![1, 2, 3, 4, 5, 6]);
let idl_b = IDLBitRange::from_iter(vec![10]);
let idl_expect = IDLBitRange::from_iter(vec![1, 2, 3, 4, 5, 6]);
let idl_result = idl_a.andnot(idl_b);
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_not_3() {
let idl_a = IDLBitRange::from_iter(vec![2, 3, 4, 5, 6]);
let idl_b = IDLBitRange::from_iter(vec![1]);
let idl_expect = IDLBitRange::from_iter(vec![2, 3, 4, 5, 6]);
let idl_result = idl_a.andnot(idl_b);
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_not_4() {
let idl_a = IDLBitRange::from_iter(vec![1, 2, 3, 64, 65, 66]);
let idl_b = IDLBitRange::from_iter(vec![65]);
let idl_expect = IDLBitRange::from_iter(vec![1, 2, 3, 64, 66]);
let idl_result = idl_a.andnot(idl_b);
assert_eq!(idl_result, idl_expect);
}
#[test]
fn test_range_threshold() {
let idl_a = IDLBitRange::from_iter(vec![1, 2, 3, 64, 65, 66]);
let idl_b = IDLBitRange::from_iter(vec![65]);
assert!(idl_a.below_threshold(1) == false);
assert!(idl_a.below_threshold(6) == false);
assert!(idl_a.below_threshold(8) == true);
assert!(idl_b.below_threshold(1) == false);
assert!(idl_b.below_threshold(8) == true);
}
}