Skip to main content

whichtime_sys/refiners/
overlap_removal.rs

1//! Overlap removal refiner - removes overlapping results, keeping longer matches
2
3use crate::context::ParsingContext;
4use crate::refiners::Refiner;
5use crate::results::ParsedResult;
6
7/// Refiner that removes overlapping matches and prefers the longest span.
8pub struct OverlapRemovalRefiner;
9
10impl Refiner for OverlapRemovalRefiner {
11    fn refine(
12        &self,
13        _context: &ParsingContext,
14        mut results: Vec<ParsedResult>,
15    ) -> Vec<ParsedResult> {
16        if results.len() < 2 {
17            return results;
18        }
19
20        // Sort by start index, then by end index (longer first)
21        results.sort_by(|a, b| {
22            a.index
23                .cmp(&b.index)
24                .then_with(|| b.end_index.cmp(&a.end_index))
25        });
26
27        let mut filtered = Vec::with_capacity(results.len());
28        let mut last_end = 0;
29
30        for result in results {
31            // If this result starts after (or at) the end of the previous, keep it
32            if result.index >= last_end {
33                last_end = result.end_index;
34                filtered.push(result);
35            } else if result.end_index > last_end {
36                // This result overlaps but extends further - check if we should replace
37                let last = filtered.last();
38                if let Some(prev) = last {
39                    let prev_len = prev.end_index - prev.index;
40                    let curr_len = result.end_index - result.index;
41                    if curr_len > prev_len {
42                        filtered.pop();
43                        last_end = result.end_index;
44                        filtered.push(result);
45                    }
46                }
47            }
48            // Otherwise, skip this result (it's fully contained in the previous)
49        }
50
51        filtered
52    }
53}