1use std::ops::{Range, RangeBounds};
2
3use usize_bounds::UsizeBounds;
4
5pub struct SqrtBucket<T, S, Ff, Fr, Fq> {
6 buf: Vec<T>,
7 summary: Vec<S>,
8 force: Ff,
9 reduce: Fr,
10 query: Fq,
11 bucket_size: usize,
12}
13
14pub enum BucketBorrow<'a, T, S> {
15 Slice(&'a mut [T]),
16 Summary(&'a mut S),
17}
18
19impl<T, S, Ff, Fr, Fq> SqrtBucket<T, S, Ff, Fr, Fq>
20where
21 Fr: FnMut(&[T]) -> S,
22 Ff: FnMut(&S, &mut [T]),
23{
24 pub fn new(buf: Vec<T>, force: Ff, reduce: Fr, query: Fq) -> Self {
25 Self::new_with_bucket_size(buf, force, reduce, query, 384)
26 }
27
28 pub fn new_with_bucket_size(
29 buf: Vec<T>,
30 force: Ff,
31 mut reduce: Fr,
32 query: Fq,
33 bucket_size: usize,
34 ) -> Self {
35 let summary: Vec<S> =
36 buf.chunks(bucket_size).map(&mut reduce).collect();
37 Self { buf, summary, force, reduce, query, bucket_size }
38 }
39
40 pub fn query<Q, B, R>(&mut self, range: B, args: Q) -> R
41 where
42 B: RangeBounds<usize>,
43 Fq: for<'a> FnMut(&mut [BucketBorrow<'a, T, S>], Q) -> R,
44 {
45 let n = self.buf.len();
46 let b = self.bucket_size;
47 let Range { start, end } = range.to_range(n);
48
49 let mut borrowed = vec![];
50 let mut affected = vec![];
51 for ((l, chunk_i), summary_i) in
52 (0..n).step_by(b).zip(self.buf.chunks_mut(b)).zip(&mut self.summary)
53 {
54 let i = l / b;
55 let r = n.min(l + b);
56 if r <= start {
57 continue;
58 }
59 if end <= l {
60 break;
61 }
62 if start <= l && r <= end {
63 borrowed.push(BucketBorrow::Summary(summary_i));
64 } else {
65 (self.force)(summary_i, chunk_i);
66 affected.push((i, (l, r)));
67 let jl = l.max(start) - l;
68 let jr = r.min(end) - l;
69 borrowed.push(BucketBorrow::Slice(&mut chunk_i[jl..jr]));
70 }
71 }
72 let res = (self.query)(&mut borrowed, args);
73 for (i, (l, r)) in affected {
74 self.summary[i] = (self.reduce)(&mut self.buf[l..r]);
75 }
76 res
77 }
78}
79
80