1use std::collections::hash_map;
6use rustc_hash::FxHashMap;
7use crate::abst::{Ring, RingOps};
8
9use super::lc_key::LcKey;
10
11#[derive(PartialEq, Eq, Clone, Default, Debug)]
18#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
19pub(super) enum LcData<X, R>
20where
21 X: LcKey,
22 R: Ring, for<'x> &'x R: RingOps<R>
23{
24 #[default]
25 Zero,
26 Single(X, R),
27 Many(FxHashMap<X, R>),
28}
29
30impl<X, R> LcData<X, R>
31where
32 X: LcKey,
33 R: Ring, for<'x> &'x R: RingOps<R>
34{
35 fn new_many() -> FxHashMap<X, R> {
36 FxHashMap::default()
37 }
38
39 pub(super) fn len(&self) -> usize {
40 match self {
41 Self::Zero => 0,
42 Self::Single(_, _) => 1,
43 Self::Many(m) => m.len(),
44 }
45 }
46
47 pub(super) fn is_empty(&self) -> bool {
48 matches!(self, Self::Zero)
49 }
50
51 pub(super) fn get(&self, x: &X) -> Option<&R> {
52 match self {
53 Self::Zero => None,
54 Self::Single(k, v) => (k == x).then_some(v),
55 Self::Many(m) => m.get(x),
56 }
57 }
58
59 pub(super) fn iter(&self) -> LcDataIter<'_, X, R> {
60 match self {
61 Self::Zero => LcDataIter::Zero,
62 Self::Single(x, r) => LcDataIter::Single(Some((x, r))),
63 Self::Many(m) => LcDataIter::Many(m.iter()),
64 }
65 }
66
67 pub(super) fn add_pair_unreduced(&mut self, x: X, r: R) {
71 if r.is_zero() { return; }
72 match self {
73 Self::Zero => {
74 *self = Self::Single(x, r);
75 }
76 Self::Single(x0, r0) if x0 == &x => {
77 r0.add_assign(r);
78 }
79 Self::Single(_, _) => {
80 let Self::Single(x0, r0) = std::mem::take(self) else { unreachable!() };
81 let mut m = Self::new_many();
82 m.insert(x0, r0);
83 m.insert(x, r);
84 *self = Self::Many(m);
85 }
86 Self::Many(m) => {
87 if let Some(v) = m.get_mut(&x) {
88 v.add_assign(r);
89 } else {
90 m.insert(x, r);
91 }
92 }
93 }
94 }
95
96 pub(super) fn add_pair_ref_unreduced(&mut self, x: &X, r: R) {
98 if r.is_zero() { return; }
99 match self {
100 Self::Single(x0, r0) if x0 == x => {
101 r0.add_assign(r);
102 return;
103 }
104 Self::Many(m) => {
105 if let Some(r0) = m.get_mut(x) {
106 r0.add_assign(r);
107 return;
108 }
109 }
110 _ => {}
111 }
112 self.add_pair_unreduced(x.clone(), r);
113 }
114
115 pub(super) fn reduce(&mut self) {
117 match self {
118 Self::Zero => {}
119 Self::Single(_, r) => {
120 if r.is_zero() {
121 *self = Self::Zero;
122 }
123 }
124 Self::Many(m) => {
125 m.retain(|_, r| !r.is_zero());
126 match m.len() {
127 0 => *self = Self::Zero,
128 1 => {
129 let (x, r) = std::mem::take(m).drain().next().unwrap();
130 *self = Self::Single(x, r);
131 }
132 _ => {}
133 }
134 }
135 }
136 }
137
138 pub(super) fn map_coeffs_in_place<F>(&mut self, f: F)
140 where F: Fn(R) -> R {
141 match self {
142 Self::Zero => {}
143 Self::Single(_, _) => {
144 let Self::Single(x, r) = std::mem::take(self) else { unreachable!() };
145 let r = f(r);
146 if !r.is_zero() {
147 *self = Self::Single(x, r);
148 }
149 }
150 Self::Many(m) => {
151 let taken = std::mem::take(m);
152 for (k, v) in taken {
153 let v = f(v);
154 if !v.is_zero() {
155 m.insert(k, v);
156 }
157 }
158 self.reduce();
159 }
160 }
161 }
162}
163
164impl<X, R> IntoIterator for LcData<X, R>
165where
166 X: LcKey,
167 R: Ring, for<'x> &'x R: RingOps<R>
168{
169 type Item = (X, R);
170 type IntoIter = LcDataIntoIter<X, R>;
171 fn into_iter(self) -> Self::IntoIter {
172 match self {
173 Self::Zero => LcDataIntoIter::Zero,
174 Self::Single(x, r) => LcDataIntoIter::Single(Some((x, r))),
175 Self::Many(m) => LcDataIntoIter::Many(m.into_iter()),
176 }
177 }
178}
179
180pub enum LcDataIter<'a, X, R> {
182 Zero,
183 Single(Option<(&'a X, &'a R)>),
184 Many(hash_map::Iter<'a, X, R>),
185}
186
187impl<'a, X, R> Iterator for LcDataIter<'a, X, R> {
188 type Item = (&'a X, &'a R);
189 fn next(&mut self) -> Option<Self::Item> {
190 match self {
191 Self::Zero => None,
192 Self::Single(opt) => opt.take(),
193 Self::Many(it) => it.next(),
194 }
195 }
196}
197
198pub enum LcDataIntoIter<X, R> {
200 Zero,
201 Single(Option<(X, R)>),
202 Many(hash_map::IntoIter<X, R>),
203}
204
205impl<X, R> Iterator for LcDataIntoIter<X, R> {
206 type Item = (X, R);
207 fn next(&mut self) -> Option<Self::Item> {
208 match self {
209 Self::Zero => None,
210 Self::Single(opt) => opt.take(),
211 Self::Many(it) => it.next(),
212 }
213 }
214}