1use std::mem::ManuallyDrop;
2use std::ops::{Deref, DerefMut};
3
4use polars_arrow::offset::OffsetsBuffer;
5use polars_utils::idx_vec::IdxVec;
6use rayon::iter::plumbing::UnindexedConsumer;
7use rayon::prelude::*;
8
9use crate::prelude::*;
10use crate::runtime::RAYON;
11use crate::utils::{NoNull, flatten, slice_slice};
12
13#[derive(Debug, Clone, PartialEq, Eq, Default)]
16pub struct GroupsIdx {
17 pub(crate) sorted_by_first_idx: bool,
18 first: Vec<IdxSize>,
20 all: Vec<IdxVec>,
22}
23
24pub type IdxItem = (IdxSize, IdxVec);
25pub type BorrowIdxItem<'a> = (IdxSize, &'a IdxVec);
26
27impl Drop for GroupsIdx {
28 fn drop(&mut self) {
29 let v = std::mem::take(&mut self.all);
30 #[cfg(not(target_family = "wasm"))]
33 if v.len() > 1 << 16 {
34 std::thread::spawn(move || drop(v));
35 } else {
36 drop(v);
37 }
38
39 #[cfg(target_family = "wasm")]
40 drop(v);
41 }
42}
43
44impl From<Vec<IdxItem>> for GroupsIdx {
45 fn from(v: Vec<IdxItem>) -> Self {
46 v.into_iter().collect()
47 }
48}
49
50impl From<Vec<Vec<IdxItem>>> for GroupsIdx {
51 fn from(v: Vec<Vec<IdxItem>>) -> Self {
52 let (cap, offsets) = flatten::cap_and_offsets(&v);
55 let mut first = Vec::with_capacity(cap);
56 let first_ptr = first.as_ptr() as usize;
57 let mut all = Vec::with_capacity(cap);
58 let all_ptr = all.as_ptr() as usize;
59
60 RAYON.install(|| {
61 v.into_par_iter()
62 .zip(offsets)
63 .for_each(|(mut inner, offset)| {
64 unsafe {
65 let first = (first_ptr as *const IdxSize as *mut IdxSize).add(offset);
66 let all = (all_ptr as *const IdxVec as *mut IdxVec).add(offset);
67
68 let inner_ptr = inner.as_mut_ptr();
69 for i in 0..inner.len() {
70 let (first_val, vals) = std::ptr::read(inner_ptr.add(i));
71 std::ptr::write(first.add(i), first_val);
72 std::ptr::write(all.add(i), vals);
73 }
74 inner.set_len(0);
77 }
78 });
79 });
80 unsafe {
81 all.set_len(cap);
82 first.set_len(cap);
83 }
84 GroupsIdx {
85 sorted_by_first_idx: false,
86 first,
87 all,
88 }
89 }
90}
91
92impl GroupsIdx {
93 pub fn new(first: Vec<IdxSize>, all: Vec<IdxVec>, sorted_by_first_idx: bool) -> Self {
94 Self {
95 sorted_by_first_idx,
96 first,
97 all,
98 }
99 }
100
101 pub fn sort_by_first_idx(&mut self) {
102 if self.sorted_by_first_idx {
103 return;
104 }
105 let mut idx = 0;
106 let first = std::mem::take(&mut self.first);
107 let mut idx_vals = first
109 .into_iter()
110 .map(|v| {
111 let out = [idx, v];
112 idx += 1;
113 out
114 })
115 .collect_trusted::<Vec<_>>();
116 idx_vals.sort_unstable_by_key(|v| v[1]);
117
118 let take_first = || idx_vals.iter().map(|v| v[1]).collect_trusted::<Vec<_>>();
119 let take_all = || {
120 idx_vals
121 .iter()
122 .map(|v| unsafe {
123 let idx = v[0] as usize;
124 std::mem::take(self.all.get_unchecked_mut(idx))
125 })
126 .collect_trusted::<Vec<_>>()
127 };
128 let (first, all) = RAYON.install(|| rayon::join(take_first, take_all));
129 self.first = first;
130 self.all = all;
131 self.sorted_by_first_idx = true
132 }
133 pub fn is_sorted_by_first_idx(&self) -> bool {
134 self.sorted_by_first_idx
135 }
136
137 pub fn iter(
138 &self,
139 ) -> std::iter::Zip<
140 std::iter::Copied<std::slice::Iter<'_, IdxSize>>,
141 std::slice::Iter<'_, IdxVec>,
142 > {
143 self.into_iter()
144 }
145
146 #[inline(always)]
147 pub fn all(&self) -> &[IdxVec] {
148 &self.all
149 }
150
151 #[inline(always)]
152 pub fn first(&self) -> &[IdxSize] {
153 &self.first
154 }
155
156 #[inline(always)]
157 pub(crate) fn len(&self) -> usize {
158 self.first.len()
159 }
160
161 #[inline(always)]
162 pub(crate) unsafe fn get_unchecked(&self, index: usize) -> BorrowIdxItem<'_> {
163 let first = *self.first.get_unchecked(index);
164 let all = self.all.get_unchecked(index);
165 (first, all)
166 }
167
168 pub fn new_empty() -> Self {
170 Self {
171 sorted_by_first_idx: false,
172 first: vec![0],
173 all: vec![vec![].into()],
174 }
175 }
176}
177
178impl FromIterator<IdxItem> for GroupsIdx {
179 fn from_iter<T: IntoIterator<Item = IdxItem>>(iter: T) -> Self {
180 let (first, all) = iter.into_iter().unzip();
181 GroupsIdx {
182 sorted_by_first_idx: false,
183 first,
184 all,
185 }
186 }
187}
188
189impl<'a> IntoIterator for &'a GroupsIdx {
190 type Item = BorrowIdxItem<'a>;
191 type IntoIter = std::iter::Zip<
192 std::iter::Copied<std::slice::Iter<'a, IdxSize>>,
193 std::slice::Iter<'a, IdxVec>,
194 >;
195
196 fn into_iter(self) -> Self::IntoIter {
197 self.first.iter().copied().zip(self.all.iter())
198 }
199}
200
201impl IntoIterator for GroupsIdx {
202 type Item = IdxItem;
203 type IntoIter = std::iter::Zip<std::vec::IntoIter<IdxSize>, std::vec::IntoIter<IdxVec>>;
204
205 fn into_iter(mut self) -> Self::IntoIter {
206 let first = std::mem::take(&mut self.first);
207 let all = std::mem::take(&mut self.all);
208 first.into_iter().zip(all)
209 }
210}
211
212impl FromParallelIterator<IdxItem> for GroupsIdx {
213 fn from_par_iter<I>(par_iter: I) -> Self
214 where
215 I: IntoParallelIterator<Item = IdxItem>,
216 {
217 let (first, all) = par_iter.into_par_iter().unzip();
218 GroupsIdx {
219 sorted_by_first_idx: false,
220 first,
221 all,
222 }
223 }
224}
225
226impl<'a> IntoParallelIterator for &'a GroupsIdx {
227 type Iter = rayon::iter::Zip<
228 rayon::iter::Copied<rayon::slice::Iter<'a, IdxSize>>,
229 rayon::slice::Iter<'a, IdxVec>,
230 >;
231 type Item = BorrowIdxItem<'a>;
232
233 fn into_par_iter(self) -> Self::Iter {
234 self.first.par_iter().copied().zip(self.all.par_iter())
235 }
236}
237
238impl IntoParallelIterator for GroupsIdx {
239 type Iter = rayon::iter::Zip<rayon::vec::IntoIter<IdxSize>, rayon::vec::IntoIter<IdxVec>>;
240 type Item = IdxItem;
241
242 fn into_par_iter(mut self) -> Self::Iter {
243 let first = std::mem::take(&mut self.first);
244 let all = std::mem::take(&mut self.all);
245 first.into_par_iter().zip(all.into_par_iter())
246 }
247}
248
249pub type GroupsSlice = Vec<[IdxSize; 2]>;
258
259#[derive(Debug, Clone, PartialEq, Eq)]
260pub enum GroupsType {
261 Idx(GroupsIdx),
262 Slice {
263 groups: GroupsSlice,
265 overlapping: bool,
268 monotonic: bool,
272 },
273}
274
275impl Default for GroupsType {
276 fn default() -> Self {
277 GroupsType::Idx(GroupsIdx::default())
278 }
279}
280
281pub fn slice_groups_are_monotonic(groups: &GroupsSlice) -> bool {
285 if groups.len() < 2 {
286 return true;
287 }
288
289 let (offset, len) = (groups[0][0], groups[0][1]);
290 let mut prev_start = offset;
291 let mut prev_end = offset + len;
292
293 for g in &groups[1..] {
294 let start = g[0];
295 let end = g[0] + g[1];
296
297 if start < prev_start || end < prev_end {
298 return false;
299 }
300
301 prev_start = start;
302 prev_end = end;
303 }
304 true
305}
306
307impl GroupsType {
308 pub fn new_slice(groups: GroupsSlice, overlapping: bool, monotonic: bool) -> Self {
309 #[cfg(debug_assertions)]
310 {
311 fn groups_overlap(groups: &GroupsSlice) -> bool {
312 if groups.len() < 2 {
313 return false;
314 }
315 let mut groups = groups.clone();
316 groups.sort();
317 let mut prev_end = groups[0][1];
318
319 for g in &groups[1..] {
320 let start = g[0];
321 let end = g[1];
322 if start < prev_end {
323 return true;
324 }
325 if end > prev_end {
326 prev_end = end;
327 }
328 }
329 false
330 }
331
332 assert!(overlapping || !groups_overlap(&groups));
333 assert!(!monotonic || slice_groups_are_monotonic(&groups));
334 }
335
336 Self::Slice {
337 groups,
338 overlapping,
339 monotonic,
340 }
341 }
342
343 pub fn into_idx(self) -> GroupsIdx {
344 match self {
345 GroupsType::Idx(groups) => groups,
346 GroupsType::Slice { groups, .. } => {
347 polars_warn!(
348 "Had to reallocate groups, missed an optimization opportunity. Please open an issue."
349 );
350 groups
351 .iter()
352 .map(|&[first, len]| (first, (first..first + len).collect::<IdxVec>()))
353 .collect()
354 },
355 }
356 }
357
358 pub(crate) fn prepare_list_agg(
359 &self,
360 total_len: usize,
361 ) -> (Option<IdxCa>, OffsetsBuffer<i64>, bool) {
362 let mut can_fast_explode = true;
363 match self {
364 GroupsType::Idx(groups) => {
365 let mut list_offset = Vec::with_capacity(self.len() + 1);
366 let mut gather_offsets = Vec::with_capacity(total_len);
367
368 let mut len_so_far = 0i64;
369 list_offset.push(len_so_far);
370
371 for idx in groups {
372 let idx = idx.1;
373 gather_offsets.extend_from_slice(idx);
374 len_so_far += idx.len() as i64;
375 list_offset.push(len_so_far);
376 can_fast_explode &= !idx.is_empty();
377 }
378 unsafe {
379 (
380 Some(IdxCa::from_vec(PlSmallStr::EMPTY, gather_offsets)),
381 OffsetsBuffer::new_unchecked(list_offset.into()),
382 can_fast_explode,
383 )
384 }
385 },
386 GroupsType::Slice { groups, .. } => {
387 let mut list_offset = Vec::with_capacity(self.len() + 1);
388 let mut gather_offsets = Vec::with_capacity(total_len);
389 let mut len_so_far = 0i64;
390 list_offset.push(len_so_far);
391
392 for g in groups {
393 let len = g[1];
394 let offset = g[0];
395 gather_offsets.extend(offset..offset + len);
396
397 len_so_far += len as i64;
398 list_offset.push(len_so_far);
399 can_fast_explode &= len > 0;
400 }
401
402 unsafe {
403 (
404 Some(IdxCa::from_vec(PlSmallStr::EMPTY, gather_offsets)),
405 OffsetsBuffer::new_unchecked(list_offset.into()),
406 can_fast_explode,
407 )
408 }
409 },
410 }
411 }
412
413 pub fn iter(&self) -> GroupsTypeIter<'_> {
414 GroupsTypeIter::new(self)
415 }
416
417 pub fn sort_by_first_idx(&mut self) {
418 match self {
419 GroupsType::Idx(groups) => {
420 if !groups.is_sorted_by_first_idx() {
421 groups.sort_by_first_idx()
422 }
423 },
424 GroupsType::Slice { .. } => {
425 },
427 }
428 }
429
430 pub(crate) fn is_sorted_by_first_idx(&self) -> bool {
431 match self {
432 GroupsType::Idx(groups) => groups.is_sorted_by_first_idx(),
433 GroupsType::Slice {
435 overlapping,
436 monotonic,
437 ..
438 } => !*overlapping || *monotonic,
439 }
440 }
441
442 pub fn is_overlapping(&self) -> bool {
443 matches!(
444 self,
445 GroupsType::Slice {
446 overlapping: true,
447 ..
448 }
449 )
450 }
451
452 pub fn is_monotonic(&self) -> bool {
453 matches!(
454 self,
455 GroupsType::Slice {
456 monotonic: true,
457 ..
458 }
459 )
460 }
461
462 pub fn take_group_firsts(self) -> Vec<IdxSize> {
463 match self {
464 GroupsType::Idx(mut groups) => std::mem::take(&mut groups.first),
465 GroupsType::Slice { groups, .. } => {
466 groups.into_iter().map(|[first, _len]| first).collect()
467 },
468 }
469 }
470
471 pub fn check_lengths(self: &GroupsType, other: &GroupsType) -> PolarsResult<()> {
474 if std::ptr::eq(self, other) {
475 return Ok(());
476 }
477 polars_ensure!(self.iter().zip(other.iter()).all(|(a, b)| {
478 a.len() == b.len()
479 }), ShapeMismatch: "expressions must have matching group lengths");
480 Ok(())
481 }
482
483 pub unsafe fn take_group_lasts(self) -> Vec<IdxSize> {
487 match self {
488 GroupsType::Idx(groups) => groups
489 .all
490 .iter()
491 .map(|idx| *idx.get_unchecked(idx.len() - 1))
492 .collect(),
493 GroupsType::Slice { groups, .. } => groups
494 .into_iter()
495 .map(|[first, len]| first + len - 1)
496 .collect(),
497 }
498 }
499
500 pub fn par_iter(&self) -> GroupsTypeParIter<'_> {
501 GroupsTypeParIter::new(self)
502 }
503
504 pub fn unwrap_idx(&self) -> &GroupsIdx {
510 match self {
511 GroupsType::Idx(groups) => groups,
512 GroupsType::Slice { .. } => panic!("groups are slices not index"),
513 }
514 }
515
516 pub fn unwrap_slice(&self) -> &GroupsSlice {
522 match self {
523 GroupsType::Slice { groups, .. } => groups,
524 GroupsType::Idx(_) => panic!("groups are index not slices"),
525 }
526 }
527
528 pub fn get(&self, index: usize) -> GroupsIndicator<'_> {
529 match self {
530 GroupsType::Idx(groups) => {
531 let first = groups.first[index];
532 let all = &groups.all[index];
533 GroupsIndicator::Idx((first, all))
534 },
535 GroupsType::Slice { groups, .. } => GroupsIndicator::Slice(groups[index]),
536 }
537 }
538
539 pub fn idx_mut(&mut self) -> &mut GroupsIdx {
545 match self {
546 GroupsType::Idx(groups) => groups,
547 GroupsType::Slice { .. } => panic!("groups are slices not index"),
548 }
549 }
550
551 pub fn len(&self) -> usize {
552 match self {
553 GroupsType::Idx(groups) => groups.len(),
554 GroupsType::Slice { groups, .. } => groups.len(),
555 }
556 }
557
558 pub fn is_empty(&self) -> bool {
559 self.len() == 0
560 }
561
562 pub fn group_count(&self) -> IdxCa {
563 match self {
564 GroupsType::Idx(groups) => {
565 let ca: NoNull<IdxCa> = groups
566 .iter()
567 .map(|(_first, idx)| idx.len() as IdxSize)
568 .collect_trusted();
569 ca.into_inner()
570 },
571 GroupsType::Slice { groups, .. } => {
572 let ca: NoNull<IdxCa> = groups.iter().map(|[_first, len]| *len).collect_trusted();
573 ca.into_inner()
574 },
575 }
576 }
577
578 pub fn as_list_chunked(&self) -> ListChunked {
579 match self {
580 GroupsType::Idx(groups) => groups
581 .iter()
582 .map(|(_first, idx)| {
583 let ca: NoNull<IdxCa> = idx.iter().map(|&v| v as IdxSize).collect();
584 ca.into_inner().into_series()
585 })
586 .collect_trusted(),
587 GroupsType::Slice { groups, .. } => groups
588 .iter()
589 .map(|&[first, len]| {
590 let ca: NoNull<IdxCa> = (first..first + len).collect_trusted();
591 ca.into_inner().into_series()
592 })
593 .collect_trusted(),
594 }
595 }
596
597 pub fn into_sliceable(self) -> GroupPositions {
598 let len = self.len();
599 slice_groups(Arc::new(self), 0, len)
600 }
601
602 pub fn num_elements(&self) -> usize {
603 match self {
604 GroupsType::Idx(i) => i.all().iter().map(|v| v.len()).sum(),
605 GroupsType::Slice {
606 groups,
607 overlapping: _,
608 monotonic: _,
609 } => groups.iter().map(|[_, l]| *l as usize).sum(),
610 }
611 }
612}
613
614impl From<GroupsIdx> for GroupsType {
615 fn from(groups: GroupsIdx) -> Self {
616 GroupsType::Idx(groups)
617 }
618}
619
620pub enum GroupsIndicator<'a> {
621 Idx(BorrowIdxItem<'a>),
622 Slice([IdxSize; 2]),
623}
624
625impl GroupsIndicator<'_> {
626 pub fn len(&self) -> usize {
627 match self {
628 GroupsIndicator::Idx(g) => g.1.len(),
629 GroupsIndicator::Slice([_, len]) => *len as usize,
630 }
631 }
632 pub fn first(&self) -> IdxSize {
633 match self {
634 GroupsIndicator::Idx(g) => g.0,
635 GroupsIndicator::Slice([first, _]) => *first,
636 }
637 }
638 pub fn is_empty(&self) -> bool {
639 self.len() == 0
640 }
641}
642
643pub struct GroupsTypeIter<'a> {
644 vals: &'a GroupsType,
645 len: usize,
646 idx: usize,
647}
648
649impl<'a> GroupsTypeIter<'a> {
650 fn new(vals: &'a GroupsType) -> Self {
651 let len = vals.len();
652 let idx = 0;
653 GroupsTypeIter { vals, len, idx }
654 }
655}
656
657impl<'a> Iterator for GroupsTypeIter<'a> {
658 type Item = GroupsIndicator<'a>;
659
660 fn nth(&mut self, n: usize) -> Option<Self::Item> {
661 self.idx = self.idx.saturating_add(n);
662 self.next()
663 }
664
665 fn next(&mut self) -> Option<Self::Item> {
666 if self.idx >= self.len {
667 return None;
668 }
669
670 let out = unsafe {
671 match self.vals {
672 GroupsType::Idx(groups) => {
673 let item = groups.get_unchecked(self.idx);
674 Some(GroupsIndicator::Idx(item))
675 },
676 GroupsType::Slice { groups, .. } => {
677 Some(GroupsIndicator::Slice(*groups.get_unchecked(self.idx)))
678 },
679 }
680 };
681 self.idx += 1;
682 out
683 }
684}
685
686pub struct GroupsTypeParIter<'a> {
687 vals: &'a GroupsType,
688 len: usize,
689}
690
691impl<'a> GroupsTypeParIter<'a> {
692 fn new(vals: &'a GroupsType) -> Self {
693 let len = vals.len();
694 GroupsTypeParIter { vals, len }
695 }
696}
697
698impl<'a> ParallelIterator for GroupsTypeParIter<'a> {
699 type Item = GroupsIndicator<'a>;
700
701 fn drive_unindexed<C>(self, consumer: C) -> C::Result
702 where
703 C: UnindexedConsumer<Self::Item>,
704 {
705 (0..self.len)
706 .into_par_iter()
707 .map(|i| unsafe {
708 match self.vals {
709 GroupsType::Idx(groups) => GroupsIndicator::Idx(groups.get_unchecked(i)),
710 GroupsType::Slice { groups, .. } => {
711 GroupsIndicator::Slice(*groups.get_unchecked(i))
712 },
713 }
714 })
715 .drive_unindexed(consumer)
716 }
717}
718
719#[derive(Debug)]
720pub struct GroupPositions {
721 sliced: ManuallyDrop<GroupsType>,
725 original: Arc<GroupsType>,
727 offset: i64,
728 len: usize,
729}
730
731impl Clone for GroupPositions {
732 fn clone(&self) -> Self {
733 let sliced = slice_groups_inner(&self.original, self.offset, self.len);
734
735 Self {
736 sliced,
737 original: self.original.clone(),
738 offset: self.offset,
739 len: self.len,
740 }
741 }
742}
743
744impl AsRef<GroupsType> for GroupPositions {
745 fn as_ref(&self) -> &GroupsType {
746 self.sliced.deref()
747 }
748}
749
750impl Deref for GroupPositions {
751 type Target = GroupsType;
752
753 fn deref(&self) -> &Self::Target {
754 self.sliced.deref()
755 }
756}
757
758impl Default for GroupPositions {
759 fn default() -> Self {
760 GroupsType::default().into_sliceable()
761 }
762}
763
764impl GroupPositions {
765 pub fn slice(&self, offset: i64, len: usize) -> Self {
766 let offset = self.offset + offset;
767 slice_groups(self.original.clone(), offset, len)
768 }
769
770 pub fn sort_by_first_idx(&mut self) {
771 if !self.as_ref().is_sorted_by_first_idx() {
772 let original = Arc::make_mut(&mut self.original);
773 original.sort_by_first_idx();
774
775 self.sliced = slice_groups_inner(original, self.offset, self.len);
776 }
777 }
778
779 pub fn unroll(mut self) -> GroupPositions {
780 match self.sliced.deref_mut() {
781 GroupsType::Idx(_) => self,
782 GroupsType::Slice {
783 overlapping: false, ..
784 } => self,
785 GroupsType::Slice { groups, .. } => {
786 let mut cum_offset = 0 as IdxSize;
789 let groups: Vec<_> = groups
790 .iter()
791 .map(|[_, len]| {
792 let new = [cum_offset, *len];
793 cum_offset += *len;
794 new
795 })
796 .collect();
797
798 GroupsType::new_slice(groups, false, true).into_sliceable()
799 },
800 }
801 }
802
803 pub fn as_unrolled_slice(&self) -> Option<&GroupsSlice> {
804 match &*self.sliced {
805 GroupsType::Idx(_) => None,
806 GroupsType::Slice {
807 groups: _,
808 overlapping: true,
809 monotonic: _,
810 } => None,
811 GroupsType::Slice {
812 groups,
813 overlapping: false,
814 monotonic: _,
815 } => Some(groups),
816 }
817 }
818
819 pub fn is_same(&self, other: &Self) -> bool {
821 Arc::ptr_eq(&self.original, &other.original)
822 && self.offset == other.offset
823 && self.len == other.len
824 }
825}
826
827fn slice_groups_inner(g: &GroupsType, offset: i64, len: usize) -> ManuallyDrop<GroupsType> {
828 match g {
834 GroupsType::Idx(groups) => {
835 let first = unsafe {
836 let first = slice_slice(groups.first(), offset, len);
837 let ptr = first.as_ptr() as *mut _;
838 Vec::from_raw_parts(ptr, first.len(), first.len())
839 };
840
841 let all = unsafe {
842 let all = slice_slice(groups.all(), offset, len);
843 let ptr = all.as_ptr() as *mut _;
844 Vec::from_raw_parts(ptr, all.len(), all.len())
845 };
846 ManuallyDrop::new(GroupsType::Idx(GroupsIdx::new(
847 first,
848 all,
849 groups.is_sorted_by_first_idx(),
850 )))
851 },
852 GroupsType::Slice {
853 groups,
854 overlapping,
855 monotonic,
856 } => {
857 let groups = unsafe {
858 let groups = slice_slice(groups, offset, len);
859 let ptr = groups.as_ptr() as *mut _;
860 Vec::from_raw_parts(ptr, groups.len(), groups.len())
861 };
862
863 ManuallyDrop::new(GroupsType::new_slice(groups, *overlapping, *monotonic))
864 },
865 }
866}
867
868fn slice_groups(g: Arc<GroupsType>, offset: i64, len: usize) -> GroupPositions {
869 let sliced = slice_groups_inner(g.as_ref(), offset, len);
870
871 GroupPositions {
872 sliced,
873 original: g,
874 offset,
875 len,
876 }
877}