range_set_blaze/
union_iter_map.rs

1use crate::map::ValueRef;
2use crate::merge_map::KMergeMap;
3use crate::sorted_disjoint_map::{Priority, PrioritySortedStartsMap};
4use crate::{AssumeSortedStarts, MergeMap, SortedDisjointMap, UnionKMergeMap, UnionMergeMap};
5use alloc::{collections::BinaryHeap, vec};
6use core::cmp::min;
7use core::iter::FusedIterator;
8use core::ops::RangeInclusive;
9use itertools::Itertools;
10
11use crate::Integer;
12use crate::unsorted_priority_map::AssumePrioritySortedStartsMap;
13use crate::unsorted_priority_map::UnsortedPriorityMap;
14
15type SortedStartsInVecMap<T, VR> =
16    AssumePrioritySortedStartsMap<T, VR, vec::IntoIter<Priority<T, VR>>>;
17#[allow(clippy::redundant_pub_crate)]
18pub(crate) type SortedStartsInVec<T> = AssumeSortedStarts<T, vec::IntoIter<RangeInclusive<T>>>;
19
20/// This `struct` is created by the [`union`] method. See [`union`]'s
21/// documentation for more.
22///
23/// [`union`]: crate::SortedDisjointMap::union
24#[derive(Clone, Debug)]
25#[must_use = "iterators are lazy and do nothing unless consumed"]
26pub struct UnionIterMap<T, VR, SS>
27where
28    T: Integer,
29    VR: ValueRef,
30    SS: PrioritySortedStartsMap<T, VR>,
31{
32    iter: SS,
33    next_item: Option<Priority<T, VR>>,
34    workspace: BinaryHeap<Priority<T, VR>>,
35    gather: Option<(RangeInclusive<T>, VR)>,
36    ready_to_go: Option<(RangeInclusive<T>, VR)>,
37}
38
39impl<T, VR, I> Iterator for UnionIterMap<T, VR, I>
40where
41    T: Integer,
42    VR: ValueRef,
43    I: PrioritySortedStartsMap<T, VR>,
44{
45    type Item = (RangeInclusive<T>, VR);
46
47    fn next(&mut self) -> Option<(RangeInclusive<T>, VR)> {
48        // Keep doing this until we have something to return.
49        loop {
50            if let Some(value) = self.ready_to_go.take() {
51                // If ready_to_go is Some, return the value immediately.
52                return Some(value);
53            }
54
55            // if self.next_item should go into the workspace, then put it there, get the next, next_item, and loop
56            if let Some(next_item) = self.next_item.take() {
57                let (next_start, next_end) = next_item.start_and_end();
58
59                // If workspace is empty, just push the next item
60                let Some(best) = self.workspace.peek() else {
61                    self.workspace.push(next_item);
62                    self.next_item = self.iter.next();
63                    continue; // return to top of the main processing loop
64                };
65                // LATER: Could add this special case: If next value is the same as best value and the ending is later, and the start overlaps/touches, then just extend the best value.
66                if next_start == best.start() {
67                    // Only push if the priority is better or the end is greater
68                    if &next_item > best || next_end > best.end() {
69                        self.workspace.push(next_item);
70                    }
71                    self.next_item = self.iter.next();
72                    continue; // return to top of the main processing loop
73                }
74
75                // It does not go into the workspace, so just hold it and keep processing.
76                self.next_item = Some(next_item);
77            }
78
79            // If the workspace is empty, we are done.
80            let Some(best) = self.workspace.peek() else {
81                debug_assert!(self.next_item.is_none());
82                debug_assert!(self.ready_to_go.is_none());
83                return self.gather.take();
84            };
85
86            // We buffer for output the best item up to the start of the next item (if any).
87
88            // Find the start of the next item, if any.
89            let next_end = self.next_item.as_ref().map_or_else(
90                || best.end(),
91                |next_item| min(next_item.start().sub_one(), best.end()),
92            );
93
94            // Add the front of best to the gather buffer.
95            if let Some(mut gather) = self.gather.take() {
96                if gather.1.borrow() == best.value().borrow()
97                    && (*gather.0.end()).add_one() == best.start()
98                {
99                    // if the gather is contiguous with the best, then merge them
100                    gather.0 = *gather.0.start()..=next_end;
101                    self.gather = Some(gather);
102                } else {
103                    // if the gather is not contiguous with the best, then output the gather and set the gather to the best
104                    self.ready_to_go = Some(gather);
105                    self.gather = Some((best.start()..=next_end, best.value().clone()));
106                }
107            } else {
108                // if there is no gather, then set the gather to the best
109                self.gather = Some((best.start()..=next_end, best.value().clone()));
110            }
111
112            // We also update the workspace to removing any items that are completely covered by the new_start.
113            // We also don't need to keep any items that have a lower priority and are shorter than the new best.
114            let mut new_workspace = BinaryHeap::new();
115            while let Some(item) = self.workspace.pop() {
116                let mut item = item;
117                if item.end() <= next_end {
118                    // too short, don't keep
119                    continue; // while loop
120                }
121                item.set_range(next_end.add_one()..=item.end());
122                let Some(new_best) = new_workspace.peek() else {
123                    // new_workspace is empty, so keep
124                    new_workspace.push(item);
125                    continue; // while loop
126                };
127                if &item < new_best && item.end() <= new_best.end() {
128                    // item.priority, item.0, new_best.priority, new_best.0);
129                    // not as good as new_best, and shorter, so don't keep
130                    continue; // while loop
131                }
132
133                // higher priority or longer, so keep
134                // item.priority, item.0, new_best.priority, new_best.0);
135                new_workspace.push(item);
136            }
137            self.workspace = new_workspace;
138        } // end of main loop
139    }
140}
141
142impl<T, VR, I> UnionIterMap<T, VR, I>
143where
144    T: Integer,
145    VR: ValueRef,
146    I: PrioritySortedStartsMap<T, VR>,
147{
148    #[inline]
149    pub(crate) fn new(mut iter: I) -> Self {
150        let item = iter.next();
151        Self {
152            iter,
153            next_item: item,
154            workspace: BinaryHeap::new(),
155            gather: None,
156            ready_to_go: None,
157        }
158    }
159}
160
161impl<T, VR, L, R> UnionMergeMap<T, VR, L, R>
162where
163    T: Integer,
164    VR: ValueRef,
165    L: SortedDisjointMap<T, VR>,
166    R: SortedDisjointMap<T, VR>,
167{
168    #[inline]
169    pub(crate) fn new2(left: L, right: R) -> Self {
170        let iter = MergeMap::new(left, right);
171        Self::new(iter)
172    }
173}
174
175impl<T, VR, J> UnionKMergeMap<T, VR, J>
176where
177    T: Integer,
178    VR: ValueRef,
179    J: SortedDisjointMap<T, VR>,
180{
181    #[inline]
182    pub(crate) fn new_k<K>(k: K) -> Self
183    where
184        K: IntoIterator<Item = J>,
185    {
186        let iter = KMergeMap::new(k);
187        Self::new(iter)
188    }
189}
190
191// UnionIterMap from iter (T, VR)
192impl<T, VR> FromIterator<(RangeInclusive<T>, VR)>
193    for UnionIterMap<T, VR, SortedStartsInVecMap<T, VR>>
194where
195    T: Integer,
196    VR: ValueRef,
197{
198    fn from_iter<I>(iter: I) -> Self
199    where
200        I: IntoIterator<Item = (RangeInclusive<T>, VR)>,
201    {
202        let iter = iter.into_iter();
203        let iter = UnsortedPriorityMap::new(iter);
204        // We sort only by start -- priority is not used until later.
205        let iter = iter.sorted_by(|a, b| a.start().cmp(&b.start()));
206        let iter = AssumePrioritySortedStartsMap::new(iter);
207        Self::new(iter)
208    }
209}
210
211impl<T, VR, I> FusedIterator for UnionIterMap<T, VR, I>
212where
213    T: Integer,
214    VR: ValueRef,
215    I: PrioritySortedStartsMap<T, VR> + FusedIterator,
216{
217}