use crate::Match;
#[derive(Debug, Clone, Default)]
pub struct MatchSet {
matches: Vec<Match>,
}
impl MatchSet {
#[must_use]
pub fn new() -> Self {
Self {
matches: Vec::new(),
}
}
pub fn try_with_capacity(cap: usize) -> crate::error::Result<Self> {
let mut vec = Vec::new();
vec.try_reserve(cap).map_err(|e| {
crate::error::Error::Backend(Box::new(std::io::Error::new(
std::io::ErrorKind::OutOfMemory,
e,
)))
})?;
Ok(Self { matches: vec })
}
#[must_use]
pub fn with_capacity(cap: usize) -> Self {
Self {
matches: Vec::with_capacity(cap),
}
}
pub fn try_insert(&mut self, m: Match) -> crate::error::Result<()> {
if let Err(pos) = self.matches.binary_search(&m) {
self.matches.try_reserve(1).map_err(|e| {
crate::error::Error::Backend(Box::new(std::io::Error::new(
std::io::ErrorKind::OutOfMemory,
e,
)))
})?;
self.matches.insert(pos, m);
}
Ok(())
}
pub fn insert(&mut self, m: Match) {
match self.matches.binary_search(&m) {
Ok(_) => {} Err(pos) => self.matches.insert(pos, m),
}
}
pub fn try_extend(
&mut self,
iter: impl IntoIterator<Item = Match>,
) -> crate::error::Result<()> {
let iter = iter.into_iter();
let (lower, _) = iter.size_hint();
if lower > 0 {
self.matches.try_reserve(lower).map_err(|e| {
crate::error::Error::Backend(Box::new(std::io::Error::new(
std::io::ErrorKind::OutOfMemory,
e,
)))
})?;
}
for m in iter {
self.matches.push(m);
}
self.matches.sort_unstable();
self.matches.dedup();
Ok(())
}
pub fn extend(&mut self, iter: impl IntoIterator<Item = Match>) {
self.matches.extend(iter);
self.matches.sort_unstable();
self.matches.dedup();
}
pub fn try_merge_overlapping(&mut self) -> crate::error::Result<()> {
if self.matches.len() < 2 {
return Ok(());
}
let mut merged = Vec::new();
merged.try_reserve(self.matches.len()).map_err(|e| {
crate::error::Error::Backend(Box::new(std::io::Error::new(
std::io::ErrorKind::OutOfMemory,
e,
)))
})?;
let mut current = self.matches[0];
for m in &self.matches[1..] {
if current.overlaps(m) {
current.end = current.end.max(m.end);
} else {
merged.push(current);
current = *m;
}
}
merged.push(current);
self.matches = merged;
Ok(())
}
pub fn merge_overlapping(&mut self) {
if self.matches.len() < 2 {
return;
}
let mut merged: Vec<Match> = Vec::with_capacity(self.matches.len());
let mut current = self.matches[0];
for m in &self.matches[1..] {
if current.overlaps(m) {
current.end = current.end.max(m.end);
} else {
merged.push(current);
current = *m;
}
}
merged.push(current);
self.matches = merged;
}
#[must_use]
pub fn len(&self) -> usize {
self.matches.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.matches.is_empty()
}
#[must_use]
pub fn as_slice(&self) -> &[Match] {
&self.matches
}
pub fn iter(&self) -> std::slice::Iter<'_, Match> {
self.matches.iter()
}
#[must_use]
pub fn into_vec(self) -> Vec<Match> {
self.matches
}
#[must_use]
pub fn filter_by_pattern(&self, pattern_id: u32) -> Self {
Self {
matches: self
.matches
.iter()
.copied()
.filter(|m| m.pattern_id == pattern_id)
.collect(),
}
}
#[must_use]
pub fn pattern_counts(&self) -> std::collections::HashMap<u32, usize> {
let mut counts = std::collections::HashMap::new();
for m in &self.matches {
*counts.entry(m.pattern_id).or_insert(0) += 1;
}
counts
}
#[must_use]
pub fn pattern_ids(&self) -> Vec<u32> {
let mut ids: Vec<u32> = self.matches.iter().map(|m| m.pattern_id).collect();
ids.sort_unstable();
ids.dedup();
ids
}
}
impl IntoIterator for MatchSet {
type Item = Match;
type IntoIter = std::vec::IntoIter<Match>;
fn into_iter(self) -> Self::IntoIter {
self.matches.into_iter()
}
}
impl<'a> IntoIterator for &'a MatchSet {
type Item = &'a Match;
type IntoIter = std::slice::Iter<'a, Match>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}