Skip to main content

rudb_graph/
rids.rs

1//! A set of row ids of one table, and pushing one through a link.
2//!
3//! spec/graph/04-in-memory.md section 4.3. This is the type a semi join reduction produces and
4//! consumes: a predicate on a parent table leaves a set of parent rows, the set is pushed through
5//! the forward link to become a set of child rows, and the child's scan reads only those. Section
6//! 5.4 of the execution document is the argument for why that is worth doing and this module is the
7//! part of it that has to be cheap.
8//!
9//! # Three forms, and why the choice is not the caller's
10//!
11//! Full is every row, which is a flag and nothing allocated. It exists because a reduction that
12//! removed nothing has to cost nothing downstream, and without it that reduction costs a bitmap of
13//! all ones and a test per row to learn nothing.
14//!
15//! Sparse is a sorted list of row ids, used below one member in [`SPARSE_RATIO`] rows. A test is a
16//! binary search, which is fine because the consumer of a set that small walks it rather than
17//! testing into it.
18//!
19//! Dense is one bit per row. On TPC-H SF100 `lineitem` that is 75 MB and `orders` is 18.75 MB, which
20//! fits the last level cache of nothing, and the reason it is still the right form is that a scan
21//! tests it in row id order, so the access is a stream rather than a scatter.
22//!
23//! Every constructor picks the form from the count, so the form is a function of the members and
24//! the table size and nothing else. That is what makes two sets over the same rows with the same
25//! members compare equal, and it means a caller never has to ask which one it got.
26//!
27//! # What is left out
28//!
29//! Section 4.3 gives the dense form a rank index. Nothing here asks a rank of one yet, and an index
30//! nothing reads is an eighth more memory to build on every push, so it arrives with the first
31//! caller that needs it.
32
33use rudb_common::{Error, Result};
34
35use crate::bits::BitVector;
36use crate::link::Link;
37use crate::rid::{NO_PARENT, PART_ROWS, Rid};
38
39/// Below one member in this many rows, a set is held as a sorted list rather than a bitmap.
40///
41/// Section 4.3's number. At one in a thousand the list is eight bytes a member against a bitmap's
42/// thousand bits, so the list is about a sixteenth of the size, and it stays smaller until one in
43/// sixty four, so the threshold is on the side of the bitmap. That side is the one a scan wants.
44pub const SPARSE_RATIO: u64 = 1000;
45
46/// A push that stops early decides at the first part past one in this many child rows.
47///
48/// Section 5.4's third. Less and a set that removes rows only toward the end of a table clustered
49/// by its parent is given up on while it is still about to pay. More and the push that removes
50/// nothing costs most of what finishing it would have.
51pub const STOP_AFTER: u64 = 3;
52
53/// Which form a set is held in, for a plan output to say.
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum Form {
56    /// Every row, with nothing allocated.
57    Full,
58    /// A sorted list of row ids.
59    Sparse,
60    /// One bit per row.
61    Dense,
62}
63
64/// A set of row ids of one table of a known number of rows.
65#[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    /// Every row of a table of `rows`.
80    #[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    /// No row of a table of `rows`.
86    #[must_use]
87    pub fn none(rows: u64) -> Self {
88        Self { rows, body: Body::Sparse(Vec::new()) }
89    }
90
91    /// The set holding exactly `members`, which have to be strictly increasing and below `rows`.
92    ///
93    /// # Errors
94    ///
95    /// If a member is out of order, repeated or past the end. A set that silently dropped one of
96    /// those would be a reduction that removed a row which joins.
97    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    /// The set whose members are the set bits of `words`, least significant bit of word zero first.
111    ///
112    /// # Errors
113    ///
114    /// If `words` is not the number of words `rows` bits take, or a bit past `rows` is set.
115    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    /// Rows in the table this is a set over.
130    #[must_use]
131    pub fn rows(&self) -> u64 {
132        self.rows
133    }
134
135    /// Rows in the set.
136    #[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    /// Whether no row is in the set.
146    #[must_use]
147    pub fn is_empty(&self) -> bool {
148        self.len() == 0
149    }
150
151    /// Whether every row is in the set.
152    #[must_use]
153    pub fn is_full(&self) -> bool {
154        matches!(self.body, Body::Full)
155    }
156
157    /// Which form the set is held in.
158    #[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    /// Bytes the set holds on to.
168    #[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    /// Whether `rid` is in the set.
178    #[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    /// Whether any member is between `low` and `high`, both included.
191    ///
192    /// The question a part skip asks: the link's zone map says the children of this part point at
193    /// parents in that range, and a range holding no member is a part that cannot contribute.
194    #[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    /// The members, in increasing order.
223    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    /// The rows in both sets.
236    ///
237    /// # Errors
238    ///
239    /// If the two are over tables of different sizes, which is two different tables.
240    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            // A sparse side is small by definition, so the answer is the part of it the other side
250            // holds, which is one test per member of the small one.
251            (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    /// The rows in either set.
263    ///
264    /// # Errors
265    ///
266    /// If the two are over tables of different sizes.
267    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    /// Pushes a set of parent rows forward through `link`, to the child rows that point into it.
280    ///
281    /// One pass over the link in child order, which is section 4.3's first push. A part whose zone
282    /// map says its children point only at parents outside the set is never decoded, which is
283    /// section 5.5's part skip and on a child clustered by the parent is most of the table.
284    ///
285    /// # Errors
286    ///
287    /// If this set is not over the link's parent table.
288    pub fn forward(&self, link: &Link) -> Result<Pushed> {
289        self.push(link, false)
290    }
291
292    /// The same push, giving up once it is plain that the set removes nothing.
293    ///
294    /// Section 5.4's early stop. A push that has covered the first [`STOP_AFTER`]th of the child and
295    /// kept every row of it stops there and hands back every row, so a reduction that was never
296    /// going to remove anything costs a third of a push and then nothing, where finishing would
297    /// cost the rest of the push and a bit test per row of the scan. The answer is then a superset
298    /// of the children that point into the set, which is all a join that still matches every row
299    /// needs, and [`Pushed::stopped`] says so.
300    ///
301    /// # Errors
302    ///
303    /// If this set is not over the link's parent table.
304    pub fn forward_or_stop(&self, link: &Link) -> Result<Pushed> {
305        self.push(link, true)
306    }
307
308    /// How many parts of the child a push of this set would decode, and how many there are.
309    ///
310    /// The zone test the push makes before it decodes a part, made for every part and nothing else,
311    /// which is one range test per thousand child rows. A push saves the scan what it skips and
312    /// costs a decode of the link and a bit test for every row of what it does not, so this is how
313    /// a caller finds out which of the two it is before paying for either.
314    ///
315    /// # Errors
316    ///
317    /// If this set is not over the link's parent table.
318    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        // Every child that has a parent is a member, which is every child when every child matched.
347        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        // Asked once, at the first part boundary past the mark, because a push that has removed a
360        // row by then has shown the set is worth finishing and asking again later would only give up
361        // work already paid for.
362        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    /// The push over a monotone link, a held parent at a time.
400    ///
401    /// The children of one parent are one run of ones in the link, so a parent the set holds keeps
402    /// the whole run and one it does not keep none of it. The walk goes from one held parent to the
403    /// next by counting the zeros between them a word at a time, and sets the range of bits for
404    /// each run it lands on, so a parent the set does not hold costs its share of a word and not a
405    /// step of its own. Stepping every parent and testing the set for each cost about fifty seven
406    /// instructions a parent, which on TPC-H q21 was 85 million a push to keep a tenth of `orders`,
407    /// see spec/perf/52-a-push-a-parent-at-a-time.md for where the step a parent came from.
408    ///
409    /// A part is counted as skipped when none of its rows is kept, which for a link in parent order
410    /// is the part the zone map would have ruled out. The early stop is asked at the first run
411    /// that starts past the mark rather than at a part boundary, which is the same question asked a
412    /// few rows later at most.
413    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        // `at` is where the run of parent `parent` starts, which is past `parent` zeros, so the
420        // children before it are `at - parent`.
421        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            // The zero after the run, which moves on to the next parent.
449            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    /// The push of a sparse set over a monotone link, a member at a time.
459    ///
460    /// A member's children are one run that [`Link::backward`] finds with two selects, so this costs
461    /// what the set holds and not what the parent holds. On TPC-H q18 the set is the 57 orders over
462    /// 300 in quantity, and [`Self::push_runs`] stepped over all 1.5 million orders to find their
463    /// 399 lines. The early stop is not asked, since a sparse set holds at most one parent in
464    /// [`SPARSE_RATIO`] and the answer is exact either way.
465    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    /// The members from `first` for `len` rows, as offsets from `first`, in order.
484    ///
485    /// What a scan keeps of a part the set was pushed into. A sparse set answers from the members in
486    /// the range, which is one search and then the members, where testing each row of the part was
487    /// a search a row.
488    #[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    /// Pushes a set of child rows backward through `link`, to the parents they point at.
521    ///
522    /// The second push of section 4.3, a pass over the link setting a bit per surviving child. It
523    /// reads the link in child order just as the forward push does, so it needs no backward
524    /// structure, and a child without a parent contributes nothing.
525    ///
526    /// # Errors
527    ///
528    /// If this set is not over the link's child table.
529    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    /// The set as a bitmap, whatever form it is held in.
569    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    /// The form a bitmap's members call for.
583    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    /// The form a sorted list's members call for.
593    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/// What pushing a set through a link produced, and how much of the link it had to read.
609#[derive(Debug, Clone, PartialEq, Eq)]
610pub struct Pushed {
611    /// The child rows that point into the set.
612    pub rids: Rids,
613    /// Parts of the child table there are.
614    pub parts: u64,
615    /// Parts the zone map ruled out without their link being decoded.
616    pub skipped: u64,
617    /// Whether the push gave up early, so that `rids` is every row rather than exactly the ones
618    /// that point into the set. Only [`Rids::forward_or_stop`] does.
619    pub stopped: bool,
620}
621
622/// Which form `members` rows out of `rows` belong in.
623fn 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
633/// Whether bit `at` of a bitmap is set.
634fn bit(words: &[u64], at: u64) -> bool {
635    words.get(index(at / 64)).is_some_and(|word| word >> (at % 64) & 1 == 1)
636}
637
638/// The bit just past the `n`th zero from bit `at` on, for `n` of one or more, or `None` when the
639/// words run out first.
640///
641/// A word at a time: the zeros left in the word are counted, and either they are too few and the
642/// walk moves on, or the one wanted is among them and is found with one select in the word.
643fn 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
659/// How many one bits in a row start at bit `at`, stopping at `len`.
660fn ones_from(bits: &[u64], at: usize, len: usize) -> usize {
661    let mut end = at;
662    while end < len {
663        let shift = end % 64;
664        // The shift brings in zeros at the top, which the negation turns into ones, so the count
665        // stops at the end of the word at the latest.
666        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
676/// Sets the bits from `from` up to but not including `to`.
677fn 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
688/// The set bits of a bitmap, in order.
689fn 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
704/// A count in the `u64` every interface here uses.
705fn count(rows: usize) -> u64 {
706    u64::try_from(rows).unwrap_or(u64::MAX)
707}
708
709/// A row count as an index. Every set here fits in memory, so one that does not is a bug upstream.
710fn 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    /// The members of a set, the slow way, for comparing against.
721    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    /// The reason the form is chosen by the count: the same members over the same table are the
757    /// same set, however they were built.
758    #[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    /// A part is reached when some child in it points at a parent in the set, which is the part a
790    /// push would decode, and one whose children all point elsewhere is not.
791    #[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    /// A child of `children` rows whose parents are `parent_of(child)`, over `parents` parents.
860    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    /// The forward push against the definition, over both forms of link, including a part of
866    /// children that point at no parent at all.
867    #[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    /// The monotone push a parent at a time against the definition a child at a time, on a link
899    /// where some parents have no children and some have runs that cross words and parts.
900    #[test]
901    fn a_push_a_parent_at_a_time_keeps_exactly_the_children_of_the_parents_held() {
902        let parents: u64 = 2000;
903        // Parent p has p % 7 children, and every hundredth one has three hundred, so runs are
904        // empty, short and longer than a word.
905        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            // Held parents far apart, so the walk crosses words of zeros and runs between them.
920            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    /// A sparse set over a monotone link is pushed a member at a time. The answer and the parts it
937    /// skips are the same as the definition's, including a member with no children, the last parent
938    /// and a member whose run crosses a part.
939    #[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    /// The offsets a scan keeps out of a part are the members in it, for each of the three forms.
967    #[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    /// A set that holds every parent a child points at stops at the first part past the third and
995    /// hands back every row, and a set that removes one row before the third finishes and is exact.
996    #[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        // The full set never reaches the loop, since it cannot remove anything to begin with.
1009        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        // A child with no parent is a row removed, the same as a child whose parent is not held.
1022        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    /// Section 5.5's claim, on the shape it is made about: a child clustered by its parent, and a
1028    /// set of parents that is one contiguous stretch of them, reads only the parts over that stretch.
1029    #[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        // A tenth of the parents is a tenth of the parts, give or take the two at the edges.
1038        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}