1use crate::storage::timeindex::{AsTime, TimeIndexEntry, TimeIndexOps, TimeIndexWindow};
2use either::Either;
3use iter_enum::{DoubleEndedIterator, ExactSizeIterator, Extend, FusedIterator, Iterator};
4use raphtory_api::core::storage::{sorted_vec_map::SVM, timeindex::TimeIndexLike};
5use serde::{Deserialize, Serialize};
6use std::{collections::BTreeMap, fmt::Debug, ops::Range};
7
8#[derive(Debug, PartialEq, Default, Clone, Serialize, Deserialize)]
9pub enum TCell<A> {
11 #[default]
12 Empty,
13 TCell1(TimeIndexEntry, A),
14 TCellCap(SVM<TimeIndexEntry, A>),
15 TCellN(BTreeMap<TimeIndexEntry, A>),
16}
17
18#[derive(Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, Extend)]
19enum TCellVariants<Empty, TCell1, TCellCap, TCellN> {
20 Empty(Empty),
21 TCell1(TCell1),
22 TCellCap(TCellCap),
23 TCellN(TCellN),
24}
25
26const BTREE_CUTOFF: usize = 128;
27
28impl<A: PartialEq> TCell<A> {
29 pub fn new(t: TimeIndexEntry, value: A) -> Self {
30 TCell::TCell1(t, value)
31 }
32
33 #[inline]
34 pub fn set(&mut self, t: TimeIndexEntry, value: A) {
35 match self {
36 TCell::Empty => {
37 *self = TCell::TCell1(t, value);
38 }
39 TCell::TCell1(t0, v) => {
40 if &t != t0 {
41 if let TCell::TCell1(t0, value0) = std::mem::take(self) {
42 let mut svm = SVM::new();
43 svm.insert(t, value);
44 svm.insert(t0, value0);
45 *self = TCell::TCellCap(svm)
46 }
47 } else {
48 *v = value
49 }
50 }
51 TCell::TCellCap(svm) => {
52 if svm.len() < BTREE_CUTOFF {
53 svm.insert(t, value);
54 } else {
55 let svm = std::mem::take(svm);
56 let mut btm: BTreeMap<TimeIndexEntry, A> = BTreeMap::new();
57 for (k, v) in svm.into_iter() {
58 btm.insert(k, v);
59 }
60 btm.insert(t, value);
61 *self = TCell::TCellN(btm)
62 }
63 }
64 TCell::TCellN(btm) => {
65 btm.insert(t, value);
66 }
67 }
68 }
69
70 pub fn at(&self, ti: &TimeIndexEntry) -> Option<&A> {
71 match self {
72 TCell::Empty => None,
73 TCell::TCell1(t, v) => (t == ti).then_some(v),
74 TCell::TCellCap(svm) => svm.get(ti),
75 TCell::TCellN(btm) => btm.get(ti),
76 }
77 }
78}
79impl<A: Sync + Send> TCell<A> {
80 pub fn iter(&self) -> impl DoubleEndedIterator<Item = (&TimeIndexEntry, &A)> + Send + Sync {
81 match self {
82 TCell::Empty => TCellVariants::Empty(std::iter::empty()),
83 TCell::TCell1(t, value) => TCellVariants::TCell1(std::iter::once((t, value))),
84 TCell::TCellCap(svm) => TCellVariants::TCellCap(svm.iter()),
85 TCell::TCellN(btm) => TCellVariants::TCellN(btm.iter()),
86 }
87 }
88
89 pub fn iter_t(&self) -> impl DoubleEndedIterator<Item = (i64, &A)> + Send + Sync {
90 self.iter().map(|(t, a)| (t.t(), a))
91 }
92
93 pub fn iter_window(
94 &self,
95 r: Range<TimeIndexEntry>,
96 ) -> impl DoubleEndedIterator<Item = (&TimeIndexEntry, &A)> + Send + Sync {
97 match self {
98 TCell::Empty => TCellVariants::Empty(std::iter::empty()),
99 TCell::TCell1(t, value) => TCellVariants::TCell1(if r.contains(t) {
100 Either::Left(std::iter::once((t, value)))
101 } else {
102 Either::Right(std::iter::empty())
103 }),
104 TCell::TCellCap(svm) => TCellVariants::TCellCap(svm.range(r)),
105 TCell::TCellN(btm) => TCellVariants::TCellN(btm.range(r)),
106 }
107 }
108
109 pub fn iter_window_t(
110 &self,
111 r: Range<i64>,
112 ) -> impl DoubleEndedIterator<Item = (i64, &A)> + Send + Sync + '_ {
113 self.iter_window(TimeIndexEntry::range(r))
114 .map(|(t, a)| (t.t(), a))
115 }
116
117 pub fn last_before(&self, t: TimeIndexEntry) -> Option<(TimeIndexEntry, &A)> {
118 match self {
119 TCell::Empty => None,
120 TCell::TCell1(t2, v) => (*t2 < t).then_some((*t2, v)),
121 TCell::TCellCap(map) => map
122 .range(TimeIndexEntry::MIN..t)
123 .last()
124 .map(|(ti, v)| (*ti, v)),
125 TCell::TCellN(map) => map
126 .range(TimeIndexEntry::MIN..t)
127 .last()
128 .map(|(ti, v)| (*ti, v)),
129 }
130 }
131
132 pub fn len(&self) -> usize {
133 match self {
134 TCell::Empty => 0,
135 TCell::TCell1(_, _) => 1,
136 TCell::TCellCap(v) => v.len(),
137 TCell::TCellN(v) => v.len(),
138 }
139 }
140
141 pub fn is_empty(&self) -> bool {
142 self.len() == 0
143 }
144}
145
146impl<'a, A: Send + Sync> TimeIndexOps<'a> for &'a TCell<A> {
147 type IndexType = TimeIndexEntry;
148 type RangeType = TimeIndexWindow<'a, Self::IndexType, TCell<A>>;
149
150 #[inline]
151 fn active(&self, w: Range<Self::IndexType>) -> bool {
152 match self {
153 TCell::Empty => false,
154 TCell::TCell1(time_index_entry, _) => w.contains(time_index_entry),
155 TCell::TCellCap(svm) => svm.range(w).next().is_some(),
156 TCell::TCellN(btree_map) => btree_map.range(w).next().is_some(),
157 }
158 }
159
160 fn range(&self, w: Range<Self::IndexType>) -> Self::RangeType {
161 let range = match self {
162 TCell::Empty => TimeIndexWindow::Empty,
163 TCell::TCell1(t, _) => {
164 if w.contains(t) {
165 TimeIndexWindow::All(*self)
166 } else {
167 TimeIndexWindow::Empty
168 }
169 }
170 _ => {
171 if let Some(min_val) = self.first() {
172 if let Some(max_val) = self.last() {
173 if min_val >= w.start && max_val < w.end {
174 TimeIndexWindow::All(*self)
175 } else {
176 TimeIndexWindow::Range {
177 timeindex: *self,
178 range: w,
179 }
180 }
181 } else {
182 TimeIndexWindow::Empty
183 }
184 } else {
185 TimeIndexWindow::Empty
186 }
187 }
188 };
189 range
190 }
191
192 fn first(&self) -> Option<Self::IndexType> {
193 match self {
194 TCell::Empty => None,
195 TCell::TCell1(t, _) => Some(*t),
196 TCell::TCellCap(svm) => svm.first_key_value().map(|(ti, _)| *ti),
197 TCell::TCellN(btm) => btm.first_key_value().map(|(ti, _)| *ti),
198 }
199 }
200
201 fn last(&self) -> Option<Self::IndexType> {
202 match self {
203 TCell::Empty => None,
204 TCell::TCell1(t, _) => Some(*t),
205 TCell::TCellCap(svm) => svm.last_key_value().map(|(ti, _)| *ti),
206 TCell::TCellN(btm) => btm.last_key_value().map(|(ti, _)| *ti),
207 }
208 }
209
210 #[allow(refining_impl_trait)]
211 fn iter(self) -> impl DoubleEndedIterator<Item = Self::IndexType> + Send + Sync + 'a {
212 match self {
213 TCell::Empty => TCellVariants::Empty(std::iter::empty()),
214 TCell::TCell1(t, _) => TCellVariants::TCell1(std::iter::once(*t)),
215 TCell::TCellCap(svm) => TCellVariants::TCellCap(svm.iter().map(|(ti, _)| *ti)),
216 TCell::TCellN(btm) => TCellVariants::TCellN(btm.keys().copied()),
217 }
218 }
219
220 fn iter_rev(self) -> impl Iterator<Item = Self::IndexType> + Send + Sync + 'a {
221 TimeIndexOps::iter(self).rev()
222 }
223
224 fn len(&self) -> usize {
225 match self {
226 TCell::Empty => 0,
227 TCell::TCell1(_, _) => 1,
228 TCell::TCellCap(svm) => svm.len(),
229 TCell::TCellN(btm) => btm.len(),
230 }
231 }
232}
233
234impl<'a, A: Send + Sync> TimeIndexLike<'a> for &'a TCell<A> {
235 #[allow(refining_impl_trait)]
236 fn range_iter(
237 self,
238 w: Range<Self::IndexType>,
239 ) -> impl DoubleEndedIterator<Item = Self::IndexType> + Send + Sync + 'a {
240 self.iter_window(w).map(|(ti, _)| *ti)
241 }
242
243 fn range_iter_rev(
244 self,
245 w: Range<Self::IndexType>,
246 ) -> impl Iterator<Item = Self::IndexType> + Send + Sync + 'a {
247 self.range_iter(w).rev()
248 }
249
250 fn range_count(&self, w: Range<Self::IndexType>) -> usize {
251 match self {
252 TCell::Empty => 0,
253 TCell::TCell1(t, _) => {
254 if w.contains(t) {
255 1
256 } else {
257 0
258 }
259 }
260 TCell::TCellCap(ts) => ts.range(w).count(),
261 TCell::TCellN(ts) => ts.range(w).count(),
262 }
263 }
264
265 fn last_range(&self, w: Range<Self::IndexType>) -> Option<Self::IndexType> {
266 self.iter_window(w).next_back().map(|(ti, _)| *ti)
267 }
268}
269
270#[cfg(test)]
271mod tcell_tests {
272 use super::TCell;
273 use crate::storage::timeindex::{AsTime, TimeIndexEntry};
274
275 #[test]
276 fn set_new_value_for_tcell_initialized_as_empty() {
277 let mut tcell = TCell::default();
278 tcell.set(TimeIndexEntry::start(16), String::from("lobster"));
279
280 assert_eq!(
281 tcell.iter().map(|(_, v)| v).collect::<Vec<_>>(),
282 vec!["lobster"]
283 );
284 }
285
286 #[test]
287 fn every_new_update_to_the_same_prop_is_recorded_as_history() {
288 let mut tcell = TCell::new(TimeIndexEntry::start(1), "Pometry");
289 tcell.set(TimeIndexEntry::start(2), "Pometry Inc.");
290
291 assert_eq!(
292 tcell.iter_t().collect::<Vec<_>>(),
293 vec![(1, &"Pometry"), (2, &"Pometry Inc."),]
294 );
295 }
296
297 #[test]
298 fn new_update_with_the_same_time_to_a_prop_is_ignored() {
299 let mut tcell = TCell::new(TimeIndexEntry::start(1), "Pometry");
300 tcell.set(TimeIndexEntry::start(1), "Pometry Inc.");
301
302 assert_eq!(
303 tcell.iter_t().collect::<Vec<_>>(),
304 vec![(1, &"Pometry Inc.")]
305 );
306 }
307
308 #[test]
309 fn updates_to_prop_can_be_iterated() {
310 let tcell: TCell<String> = TCell::default();
311
312 let actual = tcell.iter().collect::<Vec<_>>();
313 let expected = vec![];
314 assert_eq!(actual, expected);
315
316 assert_eq!(tcell.iter_t().collect::<Vec<_>>(), vec![]);
317
318 let tcell = TCell::new(TimeIndexEntry::start(3), "Pometry");
319
320 assert_eq!(
321 tcell.iter().collect::<Vec<_>>(),
322 vec![(&TimeIndexEntry::start(3), &"Pometry")]
323 );
324
325 assert_eq!(tcell.iter_t().collect::<Vec<_>>(), vec![(3, &"Pometry")]);
326
327 let mut tcell = TCell::new(TimeIndexEntry::start(2), "Pometry");
328 tcell.set(TimeIndexEntry::start(1), "Inc. Pometry");
329
330 assert_eq!(
331 tcell.iter_t().collect::<Vec<_>>(),
333 vec![(1, &"Inc. Pometry"), (2, &"Pometry"),]
334 );
335
336 assert_eq!(
337 tcell.iter().collect::<Vec<_>>(),
339 vec![
340 (&TimeIndexEntry::start(1), &"Inc. Pometry"),
341 (&TimeIndexEntry::start(2), &"Pometry")
342 ]
343 );
344
345 let mut tcell: TCell<i64> = TCell::default();
346 for n in 1..130 {
347 tcell.set(TimeIndexEntry::start(n), n)
348 }
349
350 assert_eq!(tcell.iter_t().count(), 129);
351
352 assert_eq!(tcell.iter().count(), 129)
353 }
354
355 #[test]
356 fn updates_to_prop_can_be_window_iterated() {
357 let tcell: TCell<String> = TCell::default();
358
359 let actual = tcell
360 .iter_window(TimeIndexEntry::MIN..TimeIndexEntry::MAX)
361 .collect::<Vec<_>>();
362 let expected = vec![];
363 assert_eq!(actual, expected);
364
365 assert_eq!(
366 tcell.iter_window_t(i64::MIN..i64::MAX).collect::<Vec<_>>(),
367 vec![]
368 );
369
370 let tcell = TCell::new(TimeIndexEntry::start(3), "Pometry");
371
372 assert_eq!(
373 tcell
374 .iter_window(TimeIndexEntry::range(3..4))
375 .collect::<Vec<_>>(),
376 vec![(&TimeIndexEntry(3, 0), &"Pometry")]
377 );
378
379 assert_eq!(
380 tcell.iter_window_t(3..4).collect::<Vec<_>>(),
381 vec![(3, &"Pometry")]
382 );
383
384 let mut tcell = TCell::new(TimeIndexEntry::start(3), "Pometry");
385 tcell.set(TimeIndexEntry::start(1), "Pometry Inc.");
386 tcell.set(TimeIndexEntry::start(2), "Raphtory");
387
388 let one = TimeIndexEntry::start(1);
389 let two = TimeIndexEntry::start(2);
390 let three = TimeIndexEntry::start(3);
391
392 assert_eq!(
393 tcell.iter_window_t(2..3).collect::<Vec<_>>(),
394 vec![(2, &"Raphtory")]
395 );
396
397 let expected = vec![];
398 assert_eq!(
399 tcell
400 .iter_window(TimeIndexEntry::range(4..5))
401 .collect::<Vec<_>>(),
402 expected
403 );
404
405 assert_eq!(
406 tcell
407 .iter_window(TimeIndexEntry::range(1..i64::MAX))
408 .collect::<Vec<_>>(),
409 vec![
410 (&one, &"Pometry Inc."),
411 (&two, &"Raphtory"),
412 (&three, &"Pometry")
413 ]
414 );
415
416 assert_eq!(
417 tcell
418 .iter_window(TimeIndexEntry::range(3..i64::MAX))
419 .collect::<Vec<_>>(),
420 vec![(&three, &"Pometry")]
421 );
422
423 assert_eq!(
424 tcell
425 .iter_window(TimeIndexEntry::range(2..i64::MAX))
426 .collect::<Vec<_>>(),
427 vec![(&two, &"Raphtory"), (&three, &"Pometry")]
428 );
429
430 let expected = vec![];
431 assert_eq!(
432 tcell
433 .iter_window(TimeIndexEntry::range(5..i64::MAX))
434 .collect::<Vec<_>>(),
435 expected
436 );
437
438 assert_eq!(
439 tcell
440 .iter_window(TimeIndexEntry::range(i64::MIN..4))
441 .collect::<Vec<_>>(),
442 vec![
443 (&one, &"Pometry Inc."),
444 (&two, &"Raphtory"),
445 (&three, &"Pometry")
446 ]
447 );
448
449 let expected = vec![];
450 assert_eq!(
451 tcell
452 .iter_window(TimeIndexEntry::range(i64::MIN..1))
453 .collect::<Vec<_>>(),
454 expected
455 );
456
457 let mut tcell: TCell<i64> = TCell::default();
458 for n in 1..130 {
459 tcell.set(TimeIndexEntry::start(n), n)
460 }
461
462 assert_eq!(tcell.iter_window_t(i64::MIN..i64::MAX).count(), 129);
463
464 assert_eq!(
465 tcell
466 .iter_window(TimeIndexEntry::range(i64::MIN..i64::MAX))
467 .count(),
468 129
469 )
470 }
471}