Skip to main content

molframe_core/selection/query/
operations.rs

1//! Public set algebra over adaptive selection shapes.
2
3use super::merge::{copy_selection, merge_positions, visit_positions};
4use super::representation::AtomSelection;
5use super::runs::{
6    RunCursor, complement_within, difference_runs, intersect_runs, retain_after, union_runs,
7};
8use std::ops::Range;
9
10impl AtomSelection {
11    /// The atoms in both selections.
12    #[must_use]
13    pub fn intersect(&self, other: &Self) -> Self {
14        match (self, other) {
15            (Self::Empty, _) | (_, Self::Empty) => return Self::Empty,
16            (Self::All(_), _) => return copy_selection(other),
17            (_, Self::All(_)) => return copy_selection(self),
18            _ => {}
19        }
20        if let (Some(left), Some(right)) = (RunCursor::new(self), RunCursor::new(other)) {
21            return intersect_runs(left, right);
22        }
23        let (smaller, larger) = if self.len() <= other.len() {
24            (self, other)
25        } else {
26            (other, self)
27        };
28        let mut kept = Vec::new();
29        visit_positions(smaller, |position| {
30            if larger.contains(position) {
31                kept.push(position);
32            }
33        });
34        Self::from_sorted(kept)
35    }
36
37    /// The atoms in either selection.
38    #[must_use]
39    pub fn union(&self, other: &Self) -> Self {
40        match (self, other) {
41            (Self::Empty, _) => return copy_selection(other),
42            (_, Self::Empty) => return copy_selection(self),
43            (Self::All(count), _) | (_, Self::All(count)) => return Self::All(*count),
44            _ => {}
45        }
46        if let (Some(left), Some(right)) = (RunCursor::new(self), RunCursor::new(other)) {
47            return union_runs(left, right);
48        }
49        merge_positions(self, other)
50    }
51
52    /// The atoms in this selection but not the other.
53    #[must_use]
54    pub fn difference(&self, other: &Self) -> Self {
55        if self.is_empty() {
56            return Self::Empty;
57        }
58        if other.is_empty() {
59            return copy_selection(self);
60        }
61        if let Self::All(count) = self {
62            return complement_within(other, *count);
63        }
64        if let Self::All(count) = other {
65            return retain_after(self, *count);
66        }
67        if let (Some(left), Some(right)) = (RunCursor::new(self), RunCursor::new(other)) {
68            return difference_runs(left, right);
69        }
70        let mut kept = Vec::new();
71        visit_positions(self, |position| {
72            if !other.contains(position) {
73                kept.push(position);
74            }
75        });
76        Self::from_sorted(kept)
77    }
78
79    /// Every atom of a structure of `count` atoms that this selection excludes.
80    #[must_use]
81    pub fn complement(&self, count: u32) -> Self {
82        if self.is_empty() {
83            return Self::All(count);
84        }
85        if count == 0 {
86            return Self::Empty;
87        }
88        complement_within(self, count)
89    }
90
91    /// The bytes this selection occupies beyond its own header.
92    #[must_use]
93    pub fn heap_bytes(&self) -> usize {
94        match self {
95            Self::Empty | Self::All(_) | Self::Range(_) => 0,
96            Self::Ranges(runs) => runs.len() * size_of::<Range<u32>>(),
97            Self::Sparse(positions) => positions.len() * size_of::<u32>(),
98            Self::Dense(mask) => (mask.len() as usize).div_ceil(8),
99        }
100    }
101}