1use std::{array, cmp::Ordering, fmt, iter, mem, ops::Range, sync::Arc};
5
6use super::{
7 AggregateRow, FadingIds, GroupInfo, GroupPath, Parallelism, Projection, Rebuild, SortDirection,
8 Structure, ViewSpec,
9 aggregate::{GroupValues, KeyedGroup, ViewAggregates, aggregate_groups},
10 directed,
11 display::{AggregateValues, Group, GroupData, GroupId},
12 sorted_rows,
13};
14use crate::{
15 model::{CellValue, ColumnId, ColumnIx, ColumnSet, GridColumns, GridRow, OwnedValue},
16 store::{RowId, StoreSnapshot},
17};
18
19type KeyFn<R> = Arc<dyn Fn(&R) -> CellValue<'_> + Send + Sync>;
21
22pub struct GroupKey<R: GridRow> {
25 id: &'static str,
26 title: Arc<str>,
27 depends_on: ColumnSet,
28 key: KeyFn<R>,
29}
30
31impl<R: GridRow> Clone for GroupKey<R> {
32 fn clone(&self) -> Self {
33 Self {
34 id: self.id,
35 title: self.title.clone(),
36 depends_on: self.depends_on,
37 key: self.key.clone(),
38 }
39 }
40}
41
42impl<R: GridRow> fmt::Debug for GroupKey<R> {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 f.debug_struct("GroupKey")
45 .field("id", &self.id)
46 .field("title", &self.title)
47 .field("depends_on", &self.depends_on)
48 .finish_non_exhaustive()
49 }
50}
51
52impl<R: GridRow> GroupKey<R> {
53 pub fn new(
61 id: &'static str,
62 depends_on: ColumnSet,
63 key: impl Fn(&R) -> CellValue<'_> + Send + Sync + 'static,
64 ) -> Self {
65 Self {
66 id,
67 title: id.into(),
68 depends_on,
69 key: Arc::new(key),
70 }
71 }
72
73 pub fn with_title(mut self, title: impl Into<Arc<str>>) -> Self {
76 self.title = title.into();
77 self
78 }
79
80 pub fn id(&self) -> &'static str {
82 self.id
83 }
84
85 pub fn title(&self) -> &str {
87 &self.title
88 }
89
90 pub fn depends_on(&self) -> ColumnSet {
92 self.depends_on
93 }
94
95 pub(crate) fn value<'r>(&self, row: &'r R) -> CellValue<'r> {
97 (self.key)(row)
98 }
99}
100
101enum GroupLevel<R: GridRow> {
103 Column(R::Column),
104 Key(GroupKey<R>),
105}
106
107impl<R: GridRow> Clone for GroupLevel<R> {
108 fn clone(&self) -> Self {
109 match self {
110 Self::Column(column) => Self::Column(*column),
111 Self::Key(key) => Self::Key(key.clone()),
112 }
113 }
114}
115
116pub struct GroupBy<R: GridRow> {
119 level: GroupLevel<R>,
120 direction: SortDirection,
121}
122
123impl<R: GridRow> Clone for GroupBy<R> {
124 fn clone(&self) -> Self {
125 Self {
126 level: self.level.clone(),
127 direction: self.direction,
128 }
129 }
130}
131
132impl<R: GridRow> fmt::Debug for GroupBy<R> {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 let mut debug = f.debug_struct("GroupBy");
135 match &self.level {
136 GroupLevel::Column(column) => debug.field("column", column),
137 GroupLevel::Key(key) => debug.field("key", key),
138 };
139 debug.field("direction", &self.direction).finish()
140 }
141}
142
143impl<R: GridRow> GroupBy<R> {
144 pub fn column(column: R::Column) -> Self {
146 Self {
147 level: GroupLevel::Column(column),
148 direction: SortDirection::Ascending,
149 }
150 }
151
152 pub fn key(key: GroupKey<R>) -> Self {
154 Self {
155 level: GroupLevel::Key(key),
156 direction: SortDirection::Ascending,
157 }
158 }
159
160 pub fn with_direction(mut self, direction: SortDirection) -> Self {
162 self.direction = direction;
163 self
164 }
165
166 pub fn direction(&self) -> SortDirection {
168 self.direction
169 }
170
171 pub fn as_column(&self) -> Option<R::Column> {
173 match &self.level {
174 GroupLevel::Column(column) => Some(*column),
175 GroupLevel::Key(_) => None,
176 }
177 }
178
179 pub fn as_key(&self) -> Option<&GroupKey<R>> {
181 match &self.level {
182 GroupLevel::Column(_) => None,
183 GroupLevel::Key(key) => Some(key),
184 }
185 }
186
187 pub fn id(&self) -> ColumnId {
189 match &self.level {
190 GroupLevel::Column(column) => column.column_id(),
191 GroupLevel::Key(key) => ColumnId::new_static(key.id),
192 }
193 }
194
195 pub(crate) fn value<'r>(&self, row: &'r R) -> CellValue<'r> {
197 match &self.level {
198 GroupLevel::Column(column) => row.value(*column),
199 GroupLevel::Key(key) => key.value(row),
200 }
201 }
202}
203
204pub(crate) struct GroupSpec<R: GridRow> {
206 levels: Arc<[GroupBy<R>]>,
207}
208
209impl<R: GridRow> Clone for GroupSpec<R> {
210 fn clone(&self) -> Self {
211 Self {
212 levels: self.levels.clone(),
213 }
214 }
215}
216
217impl<R: GridRow> GroupSpec<R> {
218 pub(crate) fn levels(&self) -> &[GroupBy<R>] {
220 &self.levels
221 }
222}
223
224pub struct GroupOrderContext<'a> {
226 path: &'a GroupPath,
227 row_count: usize,
228 aggregates: AggregateRow<'a>,
229}
230
231impl<'a> GroupOrderContext<'a> {
232 pub(crate) fn new(path: &'a GroupPath, row_count: usize, aggregates: AggregateRow<'a>) -> Self {
234 Self {
235 path,
236 row_count,
237 aggregates,
238 }
239 }
240
241 pub fn path(&self) -> &'a GroupPath {
243 self.path
244 }
245
246 pub fn value(&self) -> &'a OwnedValue {
248 self.path
249 .value(self.path.depth())
250 .expect("a group's path is not the root")
251 }
252
253 pub fn depth(&self) -> u16 {
255 self.path.depth()
256 }
257
258 pub fn row_count(&self) -> usize {
260 self.row_count
261 }
262
263 pub fn aggregate(&self, column: ColumnIx) -> Option<&'a OwnedValue> {
265 self.aggregates.get(column)
266 }
267}
268
269pub trait GroupOrder<R: GridRow>: Send + Sync + 'static {
276 fn compare(&self, a: &GroupOrderContext<'_>, b: &GroupOrderContext<'_>) -> Ordering;
278
279 fn depends_on(&self) -> ColumnSet {
282 ColumnSet::EMPTY
283 }
284}
285
286#[derive(Clone, Copy, Debug, Default)]
288pub struct KeyOrder;
289
290impl<R: GridRow> GroupOrder<R> for KeyOrder {
291 fn compare(&self, _: &GroupOrderContext<'_>, _: &GroupOrderContext<'_>) -> Ordering {
292 Ordering::Equal
293 }
294}
295
296#[derive(Clone, Copy, Debug)]
299pub struct AggregateOrder {
300 column: ColumnIx,
301 direction: SortDirection,
302}
303
304impl AggregateOrder {
305 pub fn new(column: impl GridColumns, direction: SortDirection) -> Self {
307 Self {
308 column: column.ix(),
309 direction,
310 }
311 }
312
313 pub fn column(&self) -> ColumnIx {
315 self.column
316 }
317
318 pub fn direction(&self) -> SortDirection {
320 self.direction
321 }
322}
323
324impl<R: GridRow> GroupOrder<R> for AggregateOrder {
325 fn compare(&self, a: &GroupOrderContext<'_>, b: &GroupOrderContext<'_>) -> Ordering {
326 match (a.aggregate(self.column), b.aggregate(self.column)) {
327 (Some(a), Some(b)) => directed(a.cmp_total(b), self.direction),
328 _ => Ordering::Equal,
329 }
330 }
331
332 fn depends_on(&self) -> ColumnSet {
333 let mut columns = ColumnSet::EMPTY;
334 columns.insert(self.column);
335 columns
336 }
337}
338
339pub trait GroupFooter: Send + Sync + 'static {
342 fn has_footer(&self, group: &GroupInfo<'_>) -> bool;
344}
345
346#[derive(Clone, Copy, Debug, Default)]
348pub struct NoGroupFooter;
349
350impl GroupFooter for NoGroupFooter {
351 fn has_footer(&self, _: &GroupInfo<'_>) -> bool {
352 false
353 }
354}
355
356#[derive(Clone, Copy, Debug, Default)]
358pub struct EveryGroupFooter;
359
360impl GroupFooter for EveryGroupFooter {
361 fn has_footer(&self, _: &GroupInfo<'_>) -> bool {
362 true
363 }
364}
365
366impl<R: GridRow> ViewSpec<R> {
367 pub fn with_group_by(mut self, levels: impl IntoIterator<Item = GroupBy<R>>) -> Self {
372 let mut unique: Vec<GroupBy<R>> = Vec::new();
373 for level in levels {
374 debug_assert!(
375 level
376 .as_key()
377 .is_none_or(|key| R::Column::all().iter().all(|column| column.id() != key.id)),
378 "the group key id {:?} is a column id",
379 level.id()
380 );
381 if !unique.iter().any(|kept| kept.id() == level.id()) {
382 unique.push(level);
383 }
384 }
385 self.structure = if unique.is_empty() {
386 Structure::Flat
387 } else {
388 Structure::Groups(GroupSpec {
389 levels: unique.into(),
390 })
391 };
392 self
393 }
394
395 pub fn group_by(&self) -> &[GroupBy<R>] {
397 match self.structure() {
398 Structure::Groups(groups) => groups.levels(),
399 Structure::Flat | Structure::Tree(_) => &[],
400 }
401 }
402
403 pub fn with_group_order(mut self, order: impl GroupOrder<R>) -> Self {
405 self.group_order = Some(Arc::new(order));
406 self
407 }
408
409 pub fn group_order(&self) -> &dyn GroupOrder<R> {
411 match &self.group_order {
412 Some(order) => &**order,
413 None => &KeyOrder,
414 }
415 }
416
417 pub fn with_group_footer(mut self, footer: impl GroupFooter) -> Self {
419 self.group_footer = Some(Arc::new(footer));
420 self
421 }
422
423 pub(crate) fn group_footer(&self) -> &dyn GroupFooter {
425 match &self.group_footer {
426 Some(footer) => &**footer,
427 None => &NoGroupFooter,
428 }
429 }
430}
431
432pub(super) fn rebuild<R: GridRow>(
435 engine: &Rebuild,
436 snapshot: &StoreSnapshot<R>,
437 spec: &ViewSpec<R>,
438 grouping: &GroupSpec<R>,
439) -> Projection {
440 let parallelism = Parallelism::for_rows(snapshot.len(), engine.max_threads());
441 rebuild_with(snapshot, spec, grouping, parallelism)
442}
443
444pub(super) fn rebuild_with<R: GridRow>(
461 snapshot: &StoreSnapshot<R>,
462 spec: &ViewSpec<R>,
463 grouping: &GroupSpec<R>,
464 parallelism: Parallelism,
465) -> Projection {
466 let levels = grouping.levels();
467 let keys = sort_keys(spec, levels);
468 match keys.len() {
471 0..=2 => build::<R, 2>(snapshot, spec, levels, &keys, parallelism),
472 3 => build::<R, 3>(snapshot, spec, levels, &keys, parallelism),
473 _ => build::<R, MAX_CACHED_KEYS>(snapshot, spec, levels, &keys, parallelism),
474 }
475}
476
477fn build<R: GridRow, const N: usize>(
479 snapshot: &StoreSnapshot<R>,
480 spec: &ViewSpec<R>,
481 levels: &[GroupBy<R>],
482 keys: &[SortKey<'_, R>],
483 parallelism: Parallelism,
484) -> Projection {
485 let level_count = levels.len() as u16;
486 let (mut sorted, fading) = sort_rows::<R, N>(snapshot, spec, keys, parallelism);
487 let fading = if fading > 0 {
488 FadingIds::new(snapshot)
489 } else {
490 FadingIds::default()
491 };
492 let mut table = find_groups(levels, &sorted);
493 if !fading.is_empty() && drop_fading_groups(&mut sorted, &table, level_count, &fading) {
494 table = find_groups(levels, &sorted);
495 }
496
497 let aggregates = ViewAggregates::new(spec);
498 #[cfg(debug_assertions)]
499 warn_unaggregated_order(spec, aggregates.columns());
500 let mut computed =
501 aggregate_groups(&aggregates, &table.groups, level_count, &sorted, |entry| {
502 (!fading.contains(entry.2)).then_some(&**entry.3)
503 });
504 let columns = aggregates.columns();
505 let width = columns.len();
506 let order = order_groups(spec.group_order(), &table, &computed, columns);
507
508 let expansion = spec.expansion();
511 let mut caption_ids = vec![0u32; order.len()];
512 let mut groups = Vec::with_capacity(order.len());
513 let mut values = Vec::with_capacity(order.len() * width);
514 let mut rows = Vec::with_capacity(sorted.len());
515 for (id, &key_ix) in order.iter().enumerate() {
516 let key_ix = key_ix as usize;
517 caption_ids[key_ix] = id as u32;
518 let keyed = &table.groups[key_ix];
519 let start = rows.len() as u32;
520 let len = keyed.rows.end - keyed.rows.start;
521 if usize::from(keyed.depth) + 1 == levels.len() {
522 rows.extend(
523 sorted[keyed.rows.start as usize..keyed.rows.end as usize]
524 .iter()
525 .map(|entry| entry.2),
526 );
527 }
528 let path = mem::take(&mut table.paths[key_ix]);
529 let expanded = expansion.is_group_expanded(&path, levels.len());
530 groups.push(Group {
531 parent: table.parents[key_ix].map(|parent| GroupId::new(caption_ids[parent] as usize)),
532 end: (id + keyed.end as usize - key_ix) as u32,
534 key_ix: key_ix as u32,
535 rows: start..start + len,
536 live: computed.live[key_ix],
537 line: u32::MAX,
538 expanded,
539 footer: false,
540 path,
541 });
542 values.extend(
543 computed.values[key_ix * width..(key_ix + 1) * width]
544 .iter_mut()
545 .map(|value| mem::replace(value, OwnedValue::Empty)),
546 );
547 }
548
549 let mut groups = GroupData::new(level_count, groups, AggregateValues::new(columns, values));
550 let footer = spec.group_footer();
551 let footers: Vec<bool> = groups
552 .table(&rows)
553 .iter()
554 .map(|group| footer.has_footer(&group))
555 .collect();
556 for (group, footer) in groups.groups.iter_mut().zip(footers) {
557 group.footer = footer;
558 }
559 Projection::with_groups(snapshot, rows, groups)
560 .with_row_count(computed.total_live)
561 .with_totals(AggregateValues::new(columns, computed.totals))
562}
563
564const MAX_CACHED_KEYS: usize = 4;
570
571struct SortKey<'s, R: GridRow> {
573 source: KeySource<'s, R>,
574 direction: SortDirection,
575}
576
577enum KeySource<'s, R: GridRow> {
578 Level(&'s GroupBy<R>),
579 Column(R::Column),
580}
581
582impl<R: GridRow> SortKey<'_, R> {
583 #[inline]
584 fn value<'r>(&self, row: &'r R) -> CellValue<'r> {
585 match &self.source {
586 KeySource::Level(level) => level.value(row),
587 KeySource::Column(column) => row.value(*column),
588 }
589 }
590}
591
592fn sort_keys<'s, R: GridRow>(
595 spec: &'s ViewSpec<R>,
596 levels: &'s [GroupBy<R>],
597) -> Vec<SortKey<'s, R>> {
598 levels
599 .iter()
600 .map(|level| SortKey {
601 source: KeySource::Level(level),
602 direction: level.direction(),
603 })
604 .chain(spec.sort().iter().map(|&(column, direction)| SortKey {
605 source: KeySource::Column(column),
606 direction,
607 }))
608 .collect()
609}
610
611type GroupEntry<'a, R, const N: usize> = ([CellValue<'a>; N], u64, RowId, &'a Arc<R>);
615
616#[inline(always)]
618fn compare_grouped<R: GridRow, const N: usize>(
619 a: &GroupEntry<'_, R, N>,
620 b: &GroupEntry<'_, R, N>,
621 cached: &[SortDirection; N],
622 rest: &[SortKey<'_, R>],
623) -> Ordering {
624 for ix in 0..N {
625 let ordering = directed(a.0[ix].cmp_total(&b.0[ix]), cached[ix]);
626 if ordering.is_ne() {
627 return ordering;
628 }
629 }
630 rest.iter()
631 .map(|key| directed(key.value(a.3).cmp_total(&key.value(b.3)), key.direction))
632 .find(|ordering| ordering.is_ne())
633 .unwrap_or(Ordering::Equal)
634 .then_with(|| a.1.cmp(&b.1))
635}
636
637fn sort_rows<'a, R: GridRow, const N: usize>(
640 snapshot: &'a StoreSnapshot<R>,
641 spec: &ViewSpec<R>,
642 keys: &[SortKey<'_, R>],
643 parallelism: Parallelism,
644) -> (Vec<GroupEntry<'a, R, N>>, usize) {
645 let cached: [SortDirection; N] = array::from_fn(|ix| {
646 keys.get(ix)
647 .map_or(SortDirection::Ascending, |key| key.direction)
648 });
649 let rest = keys.get(N..).unwrap_or_default();
650 sorted_rows(
651 snapshot,
652 spec,
653 parallelism,
654 |id, row, seq| {
656 let keys =
657 array::from_fn(|ix| keys.get(ix).map_or(CellValue::Empty, |key| key.value(row)));
658 (keys, seq, id, row)
659 },
660 |a, b| compare_grouped(a, b, &cached, rest),
661 |entry| *entry,
662 )
663}
664
665fn drop_fading_groups<R: GridRow, const N: usize>(
670 sorted: &mut Vec<GroupEntry<'_, R, N>>,
671 table: &KeyTable,
672 levels: u16,
673 fading: &FadingIds,
674) -> bool {
675 let is_fading = |group: &KeyedGroup| {
676 usize::from(group.depth) + 1 == usize::from(levels)
677 && sorted[group.rows.start as usize..group.rows.end as usize]
678 .iter()
679 .all(|entry| fading.contains(entry.2))
680 };
681 if !table.groups.iter().any(is_fading) {
682 return false;
683 }
684 let dropped: Vec<Range<usize>> = table
686 .groups
687 .iter()
688 .filter(|group| is_fading(group))
689 .map(|group| group.rows.start as usize..group.rows.end as usize)
690 .collect();
691 let mut kept = 0;
692 let mut next = 0;
693 for range in dropped.into_iter().chain([sorted.len()..sorted.len()]) {
694 sorted.copy_within(next..range.start, kept);
695 kept += range.start - next;
696 next = range.end;
697 }
698 sorted.truncate(kept);
699 true
700}
701
702#[derive(Default)]
705struct KeyTable {
706 groups: Vec<KeyedGroup>,
707 paths: Vec<GroupPath>,
708 parents: Vec<Option<usize>>,
710}
711
712fn find_groups<'a, R: GridRow, const N: usize>(
717 levels: &[GroupBy<R>],
718 sorted: &[GroupEntry<'a, R, N>],
719) -> KeyTable {
720 let ids: Vec<ColumnId> = levels.iter().map(GroupBy::id).collect();
721 let mut table = KeyTable::default();
722 let mut previous: Vec<CellValue<'a>> = Vec::with_capacity(levels.len());
723 let mut keys: Vec<CellValue<'a>> = Vec::with_capacity(levels.len());
724 let mut open: Vec<usize> = Vec::with_capacity(levels.len());
726 let close = |table: &mut KeyTable, open: &mut Vec<usize>, depth: usize, row_ix: usize| {
727 while open.len() > depth {
728 let group = open.pop().expect("open groups");
729 table.groups[group].end = table.groups.len() as u32;
730 table.groups[group].rows.end = row_ix as u32;
731 }
732 };
733 for (row_ix, entry) in sorted.iter().enumerate() {
734 keys.clear();
736 keys.extend(
737 levels
738 .iter()
739 .enumerate()
740 .map(|(depth, level)| match entry.0.get(depth) {
741 Some(&key) => key,
742 None => level.value(entry.3),
743 }),
744 );
745 let changed = if row_ix == 0 {
746 0
747 } else {
748 keys.iter()
749 .zip(&previous)
750 .position(|(key, previous)| key.cmp_total(previous).is_ne())
751 .unwrap_or(levels.len())
752 };
753 close(&mut table, &mut open, changed, row_ix);
754 for depth in changed..levels.len() {
755 let parent = open.last().copied();
756 let level = (ids[depth].clone(), OwnedValue::from_cell(keys[depth]));
757 let path = match parent {
758 Some(parent) => GroupPath::new(
759 table.paths[parent]
760 .levels()
761 .iter()
762 .cloned()
763 .chain(iter::once(level)),
764 ),
765 None => GroupPath::new([level]),
766 };
767 open.push(table.groups.len());
768 table.groups.push(KeyedGroup {
769 depth: depth as u16,
770 end: 0,
771 rows: row_ix as u32..row_ix as u32,
772 });
773 table.paths.push(path);
774 table.parents.push(parent);
775 }
776 mem::swap(&mut previous, &mut keys);
777 }
778 close(&mut table, &mut open, 0, sorted.len());
779 table
780}
781
782fn order_groups<R: GridRow>(
785 order: &dyn GroupOrder<R>,
786 table: &KeyTable,
787 computed: &GroupValues,
788 columns: ColumnSet,
789) -> Vec<u32> {
790 let width = columns.len();
791 let context = |ix: u32| {
792 let ix = ix as usize;
793 let live = computed.live[ix] as usize;
794 GroupOrderContext::new(
795 &table.paths[ix],
796 live,
797 AggregateRow::new(
798 columns,
799 &computed.values[ix * width..(ix + 1) * width],
800 live,
801 ),
802 )
803 };
804 let compare = |a: u32, b: u32| order.compare(&context(a), &context(b));
805 let mut ordered = Vec::with_capacity(table.groups.len());
806 let mut siblings = Vec::new();
807 order_siblings(
808 &table.groups,
809 0..table.groups.len(),
810 0,
811 &compare,
812 &mut siblings,
813 &mut ordered,
814 );
815 ordered
816}
817
818fn order_siblings(
822 groups: &[KeyedGroup],
823 span: Range<usize>,
824 depth: usize,
825 compare: &impl Fn(u32, u32) -> Ordering,
826 siblings: &mut Vec<Vec<u32>>,
827 ordered: &mut Vec<u32>,
828) {
829 if siblings.len() <= depth {
830 siblings.resize_with(depth + 1, Vec::new);
831 }
832 let mut level = mem::take(&mut siblings[depth]);
833 level.clear();
834 let mut next = span.start;
835 while next < span.end {
836 level.push(next as u32);
837 next = groups[next].end as usize;
838 }
839 level.sort_by(|&a, &b| compare(a, b));
840 for &group in &level {
841 ordered.push(group);
842 let group = group as usize;
843 let subgroups = group + 1..groups[group].end as usize;
844 if !subgroups.is_empty() {
845 order_siblings(groups, subgroups, depth + 1, compare, siblings, ordered);
846 }
847 }
848 siblings[depth] = level;
849}
850
851#[cfg(debug_assertions)]
854fn warn_unaggregated_order<R: GridRow>(spec: &ViewSpec<R>, aggregated: ColumnSet) {
855 let order_columns = spec.group_order().depends_on();
856 if let Some(column) = R::Column::all()
857 .iter()
858 .find(|column| order_columns.contains(column.ix()) && !aggregated.contains(column.ix()))
859 {
860 log::warn!(
861 "the group order reads column {:?}, which the view does not aggregate: groups keep the key order",
862 column.id()
863 );
864 }
865}