1use rudb_common::{Error, Result};
34
35use crate::bits::BitVector;
36use crate::link::Link;
37use crate::rid::{NO_PARENT, PART_ROWS, Rid};
38
39pub const SPARSE_RATIO: u64 = 1000;
45
46pub const STOP_AFTER: u64 = 3;
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum Form {
56 Full,
58 Sparse,
60 Dense,
62}
63
64#[derive(Debug, Clone, PartialEq, Eq)]
66pub struct Rids {
67 rows: u64,
68 body: Body,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq)]
72enum Body {
73 Full,
74 Sparse(Vec<Rid>),
75 Dense { words: Vec<u64>, members: u64 },
76}
77
78impl Rids {
79 #[must_use]
81 pub fn full(rows: u64) -> Self {
82 if rows == 0 { Self::none(0) } else { Self { rows, body: Body::Full } }
83 }
84
85 #[must_use]
87 pub fn none(rows: u64) -> Self {
88 Self { rows, body: Body::Sparse(Vec::new()) }
89 }
90
91 pub fn from_sorted(rows: u64, members: Vec<Rid>) -> Result<Self> {
98 let mut previous = None;
99 for &member in &members {
100 if member >= rows || previous.is_some_and(|previous| member <= previous) {
101 return Err(Error::internal(format!(
102 "row {member} is out of order or past the end of a table of {rows} rows"
103 )));
104 }
105 previous = Some(member);
106 }
107 Ok(Self::settle_sparse(rows, members))
108 }
109
110 pub fn from_words(rows: u64, words: Vec<u64>) -> Result<Self> {
116 if count(words.len()) != rows.div_ceil(64) {
117 return Err(Error::internal(format!(
118 "{} words is not a bitmap over {rows} rows",
119 words.len()
120 )));
121 }
122 let tail = rows % 64;
123 if tail != 0 && words.last().is_some_and(|last| last >> tail != 0) {
124 return Err(Error::internal("a bitmap has rows set past the end of its table"));
125 }
126 Ok(Self::settle_dense(rows, words))
127 }
128
129 #[must_use]
131 pub fn rows(&self) -> u64 {
132 self.rows
133 }
134
135 #[must_use]
137 pub fn len(&self) -> u64 {
138 match &self.body {
139 Body::Full => self.rows,
140 Body::Sparse(members) => count(members.len()),
141 Body::Dense { members, .. } => *members,
142 }
143 }
144
145 #[must_use]
147 pub fn is_empty(&self) -> bool {
148 self.len() == 0
149 }
150
151 #[must_use]
153 pub fn is_full(&self) -> bool {
154 matches!(self.body, Body::Full)
155 }
156
157 #[must_use]
159 pub fn form(&self) -> Form {
160 match self.body {
161 Body::Full => Form::Full,
162 Body::Sparse(_) => Form::Sparse,
163 Body::Dense { .. } => Form::Dense,
164 }
165 }
166
167 #[must_use]
169 pub fn bytes(&self) -> usize {
170 match &self.body {
171 Body::Full => 0,
172 Body::Sparse(members) => members.len() * size_of::<Rid>(),
173 Body::Dense { words, .. } => words.len() * size_of::<u64>(),
174 }
175 }
176
177 #[must_use]
179 pub fn contains(&self, rid: Rid) -> bool {
180 if rid >= self.rows {
181 return false;
182 }
183 match &self.body {
184 Body::Full => true,
185 Body::Sparse(members) => members.binary_search(&rid).is_ok(),
186 Body::Dense { words, .. } => bit(words, rid),
187 }
188 }
189
190 #[must_use]
195 pub fn any_between(&self, low: Rid, high: Rid) -> bool {
196 let high = high.min(self.rows.saturating_sub(1));
197 if low > high || self.rows == 0 {
198 return false;
199 }
200 match &self.body {
201 Body::Full => true,
202 Body::Sparse(members) => {
203 let from = members.partition_point(|&member| member < low);
204 members.get(from).is_some_and(|&member| member <= high)
205 }
206 Body::Dense { words, .. } => {
207 let (first, last) = (index(low / 64), index(high / 64));
208 (first..=last).any(|at| {
209 let mut word = words[at];
210 if at == first {
211 word &= u64::MAX << (low % 64);
212 }
213 if at == last {
214 word &= u64::MAX >> (63 - high % 64);
215 }
216 word != 0
217 })
218 }
219 }
220 }
221
222 pub fn iter(&self) -> impl Iterator<Item = Rid> + '_ {
224 let (full, sparse, dense) = match &self.body {
225 Body::Full => (Some(0..self.rows), None, None),
226 Body::Sparse(members) => (None, Some(members.iter().copied()), None),
227 Body::Dense { words, .. } => (None, None, Some(ones(words))),
228 };
229 full.into_iter()
230 .flatten()
231 .chain(sparse.into_iter().flatten())
232 .chain(dense.into_iter().flatten())
233 }
234
235 pub fn intersect(&self, other: &Self) -> Result<Self> {
241 self.same_table(other)?;
242 Ok(match (&self.body, &other.body) {
243 (Body::Full, _) => other.clone(),
244 (_, Body::Full) => self.clone(),
245 (Body::Dense { words: left, .. }, Body::Dense { words: right, .. }) => {
246 let words = left.iter().zip(right).map(|(left, right)| left & right).collect();
247 Self::settle_dense(self.rows, words)
248 }
249 (Body::Sparse(members), _) => Self::settle_sparse(
252 self.rows,
253 members.iter().copied().filter(|&member| other.contains(member)).collect(),
254 ),
255 (_, Body::Sparse(members)) => Self::settle_sparse(
256 self.rows,
257 members.iter().copied().filter(|&member| self.contains(member)).collect(),
258 ),
259 })
260 }
261
262 pub fn union(&self, other: &Self) -> Result<Self> {
268 self.same_table(other)?;
269 if self.is_full() || other.is_full() {
270 return Ok(Self::full(self.rows));
271 }
272 let mut words = self.words();
273 for member in other.iter() {
274 words[index(member / 64)] |= 1 << (member % 64);
275 }
276 Ok(Self::settle_dense(self.rows, words))
277 }
278
279 pub fn forward(&self, link: &Link) -> Result<Pushed> {
289 self.push(link, false)
290 }
291
292 pub fn forward_or_stop(&self, link: &Link) -> Result<Pushed> {
305 self.push(link, true)
306 }
307
308 pub fn reach(&self, link: &Link) -> Result<(u64, u64)> {
319 if self.rows != link.parents() {
320 return Err(Error::internal(format!(
321 "a set over {} rows reached through a link whose parent has {}",
322 self.rows,
323 link.parents()
324 )));
325 }
326 let parts = link.children().div_ceil(count(PART_ROWS));
327 let reached = (0..parts)
328 .filter(|&part| match link.part_bounds(index(part)) {
329 Some(Some((low, high))) => self.any_between(low, high),
330 _ => false,
331 })
332 .count();
333 Ok((count(reached), parts))
334 }
335
336 fn push(&self, link: &Link, stopping: bool) -> Result<Pushed> {
337 if self.rows != link.parents() {
338 return Err(Error::internal(format!(
339 "a set over {} rows pushed through a link whose parent has {}",
340 self.rows,
341 link.parents()
342 )));
343 }
344 let children = link.children();
345 let parts = children.div_ceil(count(PART_ROWS));
346 if self.is_full() && link.linked() == children {
348 return Ok(Pushed { rids: Self::full(children), parts, skipped: 0, stopped: false });
349 }
350 if let (Body::Sparse(members), Some(_)) = (&self.body, link.runs()) {
351 return Self::push_members(members, link, children, parts);
352 }
353 if let Some(runs) = link.runs() {
354 return Ok(self.push_runs(runs, children, parts, stopping));
355 }
356 let mut words = vec![0_u64; index(children.div_ceil(64))];
357 let mut parents = vec![NO_PARENT; PART_ROWS];
358 let mut skipped = 0_u64;
359 let mark = children.div_ceil(STOP_AFTER);
363 let mut asked = !stopping;
364 let mut kept = 0_u64;
365 for part in 0..parts {
366 let first = part * count(PART_ROWS);
367 if !asked && first >= mark {
368 asked = true;
369 if kept == first {
370 return Ok(Pushed {
371 rids: Self::full(children),
372 parts,
373 skipped,
374 stopped: true,
375 });
376 }
377 }
378 let reach = match link.part_bounds(index(part)) {
379 Some(Some((low, high))) => self.any_between(low, high),
380 _ => false,
381 };
382 if !reach {
383 skipped += 1;
384 continue;
385 }
386 let run = index((children - first).min(count(PART_ROWS)));
387 link.forward_run(first, &mut parents[..run])?;
388 for (at, &parent) in parents[..run].iter().enumerate() {
389 if parent != NO_PARENT && self.contains(parent) {
390 let child = first + count(at);
391 words[index(child / 64)] |= 1 << (child % 64);
392 kept += 1;
393 }
394 }
395 }
396 Ok(Pushed { rids: Self::settle_dense(children, words), parts, skipped, stopped: false })
397 }
398
399 fn push_runs(&self, runs: &BitVector, children: u64, parts: u64, stopping: bool) -> Pushed {
414 let mut words = vec![0_u64; index(children.div_ceil(64))];
415 let bits = runs.words();
416 let len = runs.len();
417 let mark = children.div_ceil(STOP_AFTER);
418 let mut asked = !stopping;
419 let (mut parent, mut at, mut kept) = (0_u64, 0_usize, 0_u64);
422 for held in self.iter() {
423 if held > parent {
424 let Some(next) = past_zeros(bits, at, held - parent) else { break };
425 at = next;
426 parent = held;
427 }
428 if at > len {
429 break;
430 }
431 let run = count(ones_from(bits, at, len));
432 let child = count(at) - parent;
433 if run > 0 {
434 if !asked && child >= mark {
435 asked = true;
436 if kept == child {
437 return Pushed {
438 rids: Self::full(children),
439 parts,
440 skipped: 0,
441 stopped: true,
442 };
443 }
444 }
445 set_range(&mut words, child, child + run);
446 kept += run;
447 }
448 at += index(run) + 1;
450 parent += 1;
451 }
452 let per_part = PART_ROWS / 64;
453 let skipped =
454 count(words.chunks(per_part).filter(|part| part.iter().all(|&word| word == 0)).count());
455 Pushed { rids: Self::settle_dense(children, words), parts, skipped, stopped: false }
456 }
457
458 fn push_members(members: &[Rid], link: &Link, children: u64, parts: u64) -> Result<Pushed> {
466 let mut kept = Vec::new();
467 for &member in members {
468 let children = link.backward(member).ok_or_else(|| {
469 Error::internal(format!("parent {member} has no run in a monotone link"))
470 })?;
471 kept.extend(children);
472 }
473 let part = count(PART_ROWS);
474 let reached = count(kept.chunk_by(|a, b| a / part == b / part).count());
475 Ok(Pushed {
476 rids: Self::settle_sparse(children, kept),
477 parts,
478 skipped: parts.saturating_sub(reached),
479 stopped: false,
480 })
481 }
482
483 #[must_use]
489 pub fn offsets_in(&self, first: Rid, len: usize) -> Vec<u32> {
490 let end = first.saturating_add(count(len)).min(self.rows);
491 let offset = |rid: Rid| u32::try_from(rid - first).unwrap_or(u32::MAX);
492 match &self.body {
493 Body::Full => (first..end).map(offset).collect(),
494 Body::Sparse(members) => {
495 let from = members.partition_point(|&member| member < first);
496 members[from..]
497 .iter()
498 .take_while(|&&member| member < end)
499 .map(|&m| offset(m))
500 .collect()
501 }
502 Body::Dense { words, .. } => {
503 let mut out = Vec::new();
504 let mut at = first;
505 while at < end {
506 let word = words.get(index(at / 64)).copied().unwrap_or(0) >> (at % 64);
507 let span = (64 - at % 64).min(end - at);
508 let mut bits = if span == 64 { word } else { word & ((1 << span) - 1) };
509 while bits != 0 {
510 out.push(offset(at + u64::from(bits.trailing_zeros())));
511 bits &= bits - 1;
512 }
513 at += span;
514 }
515 out
516 }
517 }
518 }
519
520 pub fn backward(&self, link: &Link) -> Result<Self> {
530 if self.rows != link.children() {
531 return Err(Error::internal(format!(
532 "a set over {} rows pushed back through a link whose child has {}",
533 self.rows,
534 link.children()
535 )));
536 }
537 let mut words = vec![0_u64; index(link.parents().div_ceil(64))];
538 let mut parents = vec![NO_PARENT; PART_ROWS];
539 let children = link.children();
540 for part in 0..children.div_ceil(count(PART_ROWS)) {
541 let first = part * count(PART_ROWS);
542 let last = (first + count(PART_ROWS)).min(children) - 1;
543 if !self.any_between(first, last) {
544 continue;
545 }
546 let run = index(last - first + 1);
547 link.forward_run(first, &mut parents[..run])?;
548 for (at, &parent) in parents[..run].iter().enumerate() {
549 if parent != NO_PARENT && self.contains(first + count(at)) {
550 words[index(parent / 64)] |= 1 << (parent % 64);
551 }
552 }
553 }
554 Ok(Self::settle_dense(link.parents(), words))
555 }
556
557 fn same_table(&self, other: &Self) -> Result<()> {
558 if self.rows == other.rows {
559 Ok(())
560 } else {
561 Err(Error::internal(format!(
562 "a set over {} rows combined with one over {}",
563 self.rows, other.rows
564 )))
565 }
566 }
567
568 fn words(&self) -> Vec<u64> {
570 let mut words = vec![0_u64; index(self.rows.div_ceil(64))];
571 match &self.body {
572 Body::Dense { words: held, .. } => words.copy_from_slice(held),
573 _ => {
574 for member in self.iter() {
575 words[index(member / 64)] |= 1 << (member % 64);
576 }
577 }
578 }
579 words
580 }
581
582 fn settle_dense(rows: u64, words: Vec<u64>) -> Self {
584 let members = words.iter().map(|word| u64::from(word.count_ones())).sum::<u64>();
585 match shape(rows, members) {
586 Form::Full => Self::full(rows),
587 Form::Sparse => Self { rows, body: Body::Sparse(ones(&words).collect()) },
588 Form::Dense => Self { rows, body: Body::Dense { words, members } },
589 }
590 }
591
592 fn settle_sparse(rows: u64, members: Vec<Rid>) -> Self {
594 match shape(rows, count(members.len())) {
595 Form::Full => Self::full(rows),
596 Form::Sparse => Self { rows, body: Body::Sparse(members) },
597 Form::Dense => {
598 let mut words = vec![0_u64; index(rows.div_ceil(64))];
599 for member in &members {
600 words[index(member / 64)] |= 1 << (member % 64);
601 }
602 Self { rows, body: Body::Dense { words, members: count(members.len()) } }
603 }
604 }
605 }
606}
607
608#[derive(Debug, Clone, PartialEq, Eq)]
610pub struct Pushed {
611 pub rids: Rids,
613 pub parts: u64,
615 pub skipped: u64,
617 pub stopped: bool,
620}
621
622fn shape(rows: u64, members: u64) -> Form {
624 if rows > 0 && members == rows {
625 Form::Full
626 } else if members == 0 || members.saturating_mul(SPARSE_RATIO) < rows {
627 Form::Sparse
628 } else {
629 Form::Dense
630 }
631}
632
633fn bit(words: &[u64], at: u64) -> bool {
635 words.get(index(at / 64)).is_some_and(|word| word >> (at % 64) & 1 == 1)
636}
637
638fn past_zeros(bits: &[u64], mut at: usize, n: u64) -> Option<usize> {
644 let mut left = n - 1;
645 loop {
646 let shift = at % 64;
647 let zeros = !*bits.get(at / 64)? >> shift;
648 let found = u64::from(zeros.count_ones());
649 if found > left {
650 #[expect(clippy::cast_possible_truncation, reason = "under the zeros in one word")]
651 let within = crate::bits::nth_set(zeros, left as u32) as usize;
652 return Some(at + within + 1);
653 }
654 left -= found;
655 at += 64 - shift;
656 }
657}
658
659fn ones_from(bits: &[u64], at: usize, len: usize) -> usize {
661 let mut end = at;
662 while end < len {
663 let shift = end % 64;
664 let word = bits.get(end / 64).copied().unwrap_or(0) >> shift;
667 let found = (!word).trailing_zeros() as usize;
668 if found < 64 - shift {
669 return (end + found).min(len) - at;
670 }
671 end += 64 - shift;
672 }
673 len - at
674}
675
676fn set_range(words: &mut [u64], from: u64, to: u64) {
678 let (mut at, to) = (index(from), index(to));
679 while at < to {
680 let shift = at % 64;
681 let take = (64 - shift).min(to - at);
682 let mask = if take == 64 { u64::MAX } else { ((1_u64 << take) - 1) << shift };
683 words[at / 64] |= mask;
684 at += take;
685 }
686}
687
688fn ones(words: &[u64]) -> impl Iterator<Item = Rid> + '_ {
690 words.iter().enumerate().flat_map(|(at, &word)| {
691 let base = count(at) * 64;
692 let mut rest = word;
693 std::iter::from_fn(move || {
694 if rest == 0 {
695 return None;
696 }
697 let low = u64::from(rest.trailing_zeros());
698 rest &= rest - 1;
699 Some(base + low)
700 })
701 })
702}
703
704fn count(rows: usize) -> u64 {
706 u64::try_from(rows).unwrap_or(u64::MAX)
707}
708
709fn index(rows: u64) -> usize {
711 usize::try_from(rows).unwrap_or(usize::MAX)
712}
713
714#[cfg(test)]
715mod tests {
716 use super::{Form, Rids, SPARSE_RATIO, STOP_AFTER};
717 use crate::link::Link;
718 use crate::rid::{NO_PARENT, PART_ROWS, Rid};
719
720 fn members(rids: &Rids) -> Vec<Rid> {
722 (0..rids.rows()).filter(|&rid| rids.contains(rid)).collect()
723 }
724
725 #[test]
726 fn the_offsets_of_a_bitmap_are_its_members_in_the_range() {
727 let rows = 5000;
728 let members: Vec<Rid> = (0..rows).filter(|rid| rid % 3 == 0 || rid % 64 == 63).collect();
729 let set = Rids::from_sorted(rows, members.clone()).expect("sorted");
730 assert_eq!(set.form(), Form::Dense);
731 for (first, len) in [(0, 64), (1, 63), (63, 2), (100, 1000), (4990, 64), (0, 5000), (7, 0)]
732 {
733 let slow = members
734 .iter()
735 .filter(|&&rid| rid >= first && rid < first + len)
736 .map(|&rid| u32::try_from(rid - first).expect("small"))
737 .collect::<Vec<_>>();
738 let len = usize::try_from(len).expect("small");
739 assert_eq!(set.offsets_in(first, len), slow, "from {first} for {len}");
740 }
741 }
742
743 #[test]
744 fn the_form_follows_the_count_and_not_the_constructor() {
745 let rows = 10 * SPARSE_RATIO;
746 assert_eq!(Rids::from_sorted(rows, vec![1, 2, 3]).expect("sorted").form(), Form::Sparse);
747 let many: Vec<Rid> = (0..rows).step_by(2).collect();
748 assert_eq!(Rids::from_sorted(rows, many).expect("sorted").form(), Form::Dense);
749 let every: Vec<Rid> = (0..rows).collect();
750 assert_eq!(Rids::from_sorted(rows, every).expect("sorted").form(), Form::Full);
751 let mut words = vec![0_u64; usize::try_from(rows.div_ceil(64)).expect("small")];
752 words[0] = 1;
753 assert_eq!(Rids::from_words(rows, words).expect("bitmap").form(), Form::Sparse);
754 }
755
756 #[test]
759 fn the_same_members_are_the_same_set_whichever_way_they_came_in() {
760 let rows = 5000;
761 let members: Vec<Rid> = (0..rows).filter(|rid| rid % 3 == 0).collect();
762 let mut words = vec![0_u64; usize::try_from(rows.div_ceil(64)).expect("small")];
763 for member in &members {
764 words[usize::try_from(member / 64).expect("small")] |= 1 << (member % 64);
765 }
766 let listed = Rids::from_sorted(rows, members).expect("sorted");
767 let mapped = Rids::from_words(rows, words).expect("bitmap");
768 assert_eq!(listed, mapped);
769 }
770
771 #[test]
772 fn a_member_out_of_order_or_past_the_end_is_refused() {
773 assert!(Rids::from_sorted(10, vec![3, 2]).is_err());
774 assert!(Rids::from_sorted(10, vec![3, 3]).is_err());
775 assert!(Rids::from_sorted(10, vec![10]).is_err());
776 assert!(Rids::from_words(10, vec![1 << 10]).is_err(), "a bit past the end");
777 assert!(Rids::from_words(10, vec![0, 0]).is_err(), "a word too many");
778 }
779
780 #[test]
781 fn a_full_set_holds_nothing_and_answers_everything() {
782 let full = Rids::full(1_000_000);
783 assert_eq!(full.bytes(), 0);
784 assert_eq!(full.len(), 1_000_000);
785 assert!(full.contains(999_999));
786 assert!(!full.contains(1_000_000));
787 }
788
789 #[test]
792 fn reach_counts_the_parts_a_push_would_decode() {
793 let parents = 100;
794 let parents_of: Vec<Rid> = (0..count(PART_ROWS) * 4)
795 .map(|child| child * parents / (count(PART_ROWS) * 4))
796 .collect();
797 let link = Link::build(&parents_of, parents).expect("every parent exists");
798 let one = Rids::from_sorted(parents, vec![30]).expect("a parent that exists");
799 assert_eq!(one.reach(&link).expect("the same parent"), (1, 4));
800 let two = Rids::from_sorted(parents, vec![10, 90]).expect("parents that exist");
801 assert_eq!(two.reach(&link).expect("the same parent"), (2, 4));
802 assert_eq!(Rids::full(parents).reach(&link).expect("the same parent"), (4, 4));
803 assert!(Rids::full(parents + 1).reach(&link).is_err(), "a set over another table");
804 }
805
806 #[test]
807 fn any_between_looks_only_inside_the_range_in_every_form() {
808 let rows = 4096;
809 for members in [vec![700], (0..rows).filter(|rid| rid % 2 == 0 && *rid != 700).collect()] {
810 let rids = Rids::from_sorted(rows, members.clone()).expect("sorted");
811 for (low, high) in [(0, 63), (64, 699), (699, 701), (700, 700), (1000, 5000)] {
812 let expected = members.iter().any(|&member| (low..=high).contains(&member));
813 assert_eq!(
814 rids.any_between(low, high),
815 expected,
816 "{low}..={high} over {:?}",
817 rids.form()
818 );
819 }
820 }
821 assert!(Rids::full(10).any_between(3, 3));
822 assert!(!Rids::full(10).any_between(10, 20), "past the end is outside the table");
823 }
824
825 #[test]
826 fn intersect_and_union_agree_with_the_slow_answer_across_forms() {
827 let rows = 20_000;
828 let sets = [
829 Rids::none(rows),
830 Rids::from_sorted(rows, vec![5, 700, 19_999]).expect("sorted"),
831 Rids::from_sorted(rows, (0..rows).filter(|rid| rid % 3 == 0).collect())
832 .expect("sorted"),
833 Rids::from_sorted(rows, (0..rows).filter(|rid| rid % 5 == 0).collect())
834 .expect("sorted"),
835 Rids::full(rows),
836 ];
837 for left in &sets {
838 for right in &sets {
839 let both = left.intersect(right).expect("same table");
840 let either = left.union(right).expect("same table");
841 let (left_members, right_members) = (members(left), members(right));
842 let expected_both: Vec<Rid> = left_members
843 .iter()
844 .copied()
845 .filter(|rid| right_members.contains(rid))
846 .collect();
847 let mut expected_either = left_members.clone();
848 expected_either.extend(right_members.iter().copied());
849 expected_either.sort_unstable();
850 expected_either.dedup();
851 assert_eq!(members(&both), expected_both);
852 assert_eq!(members(&either), expected_either);
853 assert_eq!(both.iter().collect::<Vec<_>>(), expected_both, "iteration is in order");
854 }
855 }
856 assert!(Rids::full(3).intersect(&Rids::full(4)).is_err(), "two different tables");
857 }
858
859 fn link(children: u64, parents: u64, parent_of: impl Fn(u64) -> Rid) -> Link {
861 let of: Vec<Rid> = (0..children).map(parent_of).collect();
862 Link::build(&of, parents).expect("a link")
863 }
864
865 #[test]
868 fn a_forward_push_finds_exactly_the_children_that_point_into_the_set() {
869 let parents = 3000;
870 let children = 10 * count(PART_ROWS) + 17;
871 let clustered = link(children, parents, |child| child * parents / children);
872 let scattered = link(children, parents, |child| {
873 if child / count(PART_ROWS) == 4 { NO_PARENT } else { (child * 7919) % parents }
874 });
875 for link in [&clustered, &scattered] {
876 for set in [
877 Rids::none(parents),
878 Rids::from_sorted(parents, vec![0, 1500, 2999]).expect("sorted"),
879 Rids::from_sorted(parents, (0..parents).filter(|p| p % 4 == 1).collect())
880 .expect("sorted"),
881 Rids::full(parents),
882 ] {
883 let pushed = set.forward(link).expect("the same table");
884 let expected: Vec<Rid> = (0..children)
885 .filter(|&child| link.forward(child).is_some_and(|parent| set.contains(parent)))
886 .collect();
887 assert_eq!(
888 members(&pushed.rids),
889 expected,
890 "{:?} through {:?}",
891 set.form(),
892 link.form()
893 );
894 }
895 }
896 }
897
898 #[test]
901 fn a_push_a_parent_at_a_time_keeps_exactly_the_children_of_the_parents_held() {
902 let parents: u64 = 2000;
903 let sizes: Vec<u64> =
906 (0..parents).map(|p| if p % 100 == 42 { 300 } else { p % 7 }).collect();
907 let of: Vec<Rid> =
908 (0..parents).flat_map(|p| std::iter::repeat_n(p, index(sizes[index(p)]))).collect();
909 let children = count(of.len());
910 let link = Link::build(&of, parents).expect("a link");
911 assert_eq!(link.form(), crate::link::Form::Monotone);
912 for set in [
913 Rids::none(parents),
914 Rids::from_sorted(parents, vec![0, 42, 1999]).expect("sorted"),
915 Rids::from_sorted(parents, (0..parents).filter(|p| p % 3 != 0).collect())
916 .expect("sorted"),
917 Rids::from_sorted(parents, (0..parents).filter(|p| p % 5 == 2).collect())
918 .expect("sorted"),
919 Rids::from_sorted(parents, (0..parents).filter(|p| p % 97 == 42).collect())
921 .expect("sorted"),
922 Rids::from_sorted(parents, (1990..parents).collect()).expect("sorted"),
923 ] {
924 let pushed = set.forward(&link).expect("the same table");
925 let expected: Vec<Rid> =
926 (0..children).filter(|&child| set.contains(of[index(child)])).collect();
927 assert_eq!(members(&pushed.rids), expected, "{:?}", set.form());
928 let parts = children.div_ceil(count(PART_ROWS));
929 let untouched = (0..parts)
930 .filter(|part| !expected.iter().any(|child| child / count(PART_ROWS) == *part))
931 .count();
932 assert_eq!(pushed.skipped, count(untouched), "{:?}", set.form());
933 }
934 }
935
936 #[test]
940 fn a_sparse_push_a_member_at_a_time_keeps_exactly_the_children_of_its_members() {
941 let parents: u64 = 20 * SPARSE_RATIO;
942 let sizes: Vec<u64> =
943 (0..parents).map(|p| if p % 1000 == 42 { 3000 } else { p % 5 }).collect();
944 let of: Vec<Rid> =
945 (0..parents).flat_map(|p| std::iter::repeat_n(p, index(sizes[index(p)]))).collect();
946 let children = count(of.len());
947 let link = Link::build(&of, parents).expect("a link");
948 assert_eq!(link.form(), crate::link::Form::Monotone);
949 let set =
950 Rids::from_sorted(parents, vec![0, 5, 42, 7042, 7043, parents - 1]).expect("sorted");
951 assert_eq!(set.form(), Form::Sparse);
952 let pushed = set.forward_or_stop(&link).expect("the same table");
953 let expected: Vec<Rid> =
954 (0..children).filter(|&child| set.contains(of[index(child)])).collect();
955 assert_eq!(members(&pushed.rids), expected);
956 let parts = children.div_ceil(count(PART_ROWS));
957 let untouched = (0..parts)
958 .filter(|part| !expected.iter().any(|child| child / count(PART_ROWS) == *part))
959 .count();
960 assert_eq!(
961 (pushed.parts, pushed.skipped, pushed.stopped),
962 (parts, count(untouched), false)
963 );
964 }
965
966 #[test]
968 fn the_offsets_in_a_range_are_its_members_counted_from_its_start() {
969 let rows = 10 * SPARSE_RATIO;
970 let sparse = Rids::from_sorted(rows, vec![3, 100, 101, 9999]).expect("sorted");
971 let dense = Rids::from_sorted(rows, (0..rows).step_by(3).collect()).expect("sorted");
972 for set in [sparse, dense, Rids::full(rows), Rids::none(rows)] {
973 for (first, len) in [(0, 200), (100, 2), (9990, 50), (rows, 10)] {
974 let expected: Vec<u32> =
975 (0..len).filter(|&at| set.contains(first + u64::from(at))).collect();
976 assert_eq!(
977 set.offsets_in(first, index(u64::from(len))),
978 expected,
979 "{:?}",
980 set.form()
981 );
982 }
983 }
984 }
985
986 fn index(rows: u64) -> usize {
987 usize::try_from(rows).expect("small")
988 }
989
990 fn count(rows: usize) -> u64 {
991 u64::try_from(rows).expect("small")
992 }
993
994 #[test]
997 fn a_push_that_removes_nothing_by_the_third_stops_and_one_that_removes_something_finishes() {
998 let parents = 3000;
999 let children = 4 * STOP_AFTER * count(PART_ROWS);
1000 let clustered = link(children, parents, |child| child * parents / children);
1001 let every = Rids::full(parents);
1002 let all_but_last: Vec<Rid> = (0..parents - 1).collect();
1003 let most = Rids::from_sorted(parents, all_but_last).expect("sorted");
1004 let stopped = most.forward_or_stop(&clustered).expect("the same table");
1005 assert!(stopped.stopped, "nothing was removed in the first third");
1006 assert!(stopped.rids.is_full(), "a stopped push keeps every row");
1007 assert_eq!(stopped.parts, 4 * STOP_AFTER);
1008 assert!(!every.forward_or_stop(&clustered).expect("the same table").stopped);
1010
1011 let all_but_first: Vec<Rid> = (1..parents).collect();
1012 let early = Rids::from_sorted(parents, all_but_first).expect("sorted");
1013 let finished = early.forward_or_stop(&clustered).expect("the same table");
1014 assert!(!finished.stopped, "the first parent's children were removed before the third");
1015 assert_eq!(finished, early.forward(&clustered).expect("the same table"));
1016 assert_eq!(
1017 finished.rids.len(),
1018 children - count((0..children).filter(|child| child * parents / children == 0).count())
1019 );
1020
1021 let orphans =
1023 link(children, parents, |child| if child == 5 { NO_PARENT } else { child % parents });
1024 assert!(!every.forward_or_stop(&orphans).expect("the same table").stopped);
1025 }
1026
1027 #[test]
1030 fn a_clustered_child_skips_every_part_that_points_outside_the_set() {
1031 let parents = 1000;
1032 let children = 100 * count(PART_ROWS);
1033 let link = link(children, parents, |child| child * parents / children);
1034 let set = Rids::from_sorted(parents, (100..200).collect()).expect("sorted");
1035 let pushed = set.forward(&link).expect("the same table");
1036 assert_eq!(pushed.parts, 100);
1037 assert!(pushed.skipped >= 88, "only {} of 100 parts were skipped", pushed.skipped);
1039 assert_eq!(pushed.rids.len(), children / 10);
1040 }
1041
1042 #[test]
1043 fn nothing_in_the_set_skips_every_part_and_everything_skips_the_pass() {
1044 let link = link(5000, 100, |child| child % 100);
1045 let pushed = Rids::none(100).forward(&link).expect("the same table");
1046 assert_eq!((pushed.skipped, pushed.rids.len()), (pushed.parts, 0));
1047 let pushed = Rids::full(100).forward(&link).expect("the same table");
1048 assert!(pushed.rids.is_full(), "every child matched, so every child is in");
1049 assert_eq!(pushed.skipped, 0);
1050 }
1051
1052 #[test]
1053 fn a_backward_push_finds_exactly_the_parents_the_set_points_at() {
1054 let parents = 500;
1055 let children = 7 * count(PART_ROWS) + 3;
1056 let clustered = link(children, parents, |child| child * parents / children);
1057 let scattered = link(children, parents, |child| {
1058 if child % 11 == 0 { NO_PARENT } else { (child * 31) % parents }
1059 });
1060 for link in [&clustered, &scattered] {
1061 let set = Rids::from_sorted(children, (0..children).filter(|c| c % 97 == 3).collect())
1062 .expect("sorted");
1063 let pushed = set.backward(link).expect("the same table");
1064 let mut expected: Vec<Rid> =
1065 set.iter().filter_map(|child| link.forward(child)).collect();
1066 expected.sort_unstable();
1067 expected.dedup();
1068 assert_eq!(members(&pushed), expected, "through {:?}", link.form());
1069 }
1070 }
1071
1072 #[test]
1073 fn a_set_over_the_wrong_table_is_refused_rather_than_pushed() {
1074 let link = link(100, 10, |child| child % 10);
1075 assert!(Rids::full(11).forward(&link).is_err());
1076 assert!(Rids::full(10).backward(&link).is_err());
1077 }
1078}