1use std::any::Any;
9use std::borrow::Cow;
10use std::cmp;
11use std::fmt;
12use std::sync::atomic::Ordering;
13use std::sync::Arc;
14
15use nonblocking::non_blocking_result;
16
17use super::hints::Flags;
18use super::AsyncSetQuery;
19use super::BoxVertexStream;
20use super::Hints;
21use crate::idset::IdList;
22use crate::idset::OrderedSpan;
23use crate::ops::DagAlgorithm;
24use crate::ops::IdConvert;
25use crate::protocol::disable_remote_protocol;
26use crate::Group;
27use crate::Id;
28use crate::IdSet;
29use crate::Result;
30use crate::Set;
31use crate::Vertex;
32
33#[derive(Clone)]
36pub struct IdStaticSet {
37 spans: IdSet,
38 pub(crate) map: Arc<dyn IdConvert + Send + Sync>,
39 pub(crate) dag: Arc<dyn DagAlgorithm + Send + Sync>,
40 hints: Hints,
41 iteration_order: IterationOrder,
43}
44
45#[derive(Clone, Debug)]
47enum IterationOrder {
48 Asc,
50 Desc,
52 Custom(IdList),
54 CustomReversed(IdList),
56}
57
58#[derive(Copy, Clone, Debug)]
60pub enum BasicIterationOrder {
61 Asc,
63 Desc,
65}
66
67struct Iter {
68 iter: Box<dyn DoubleEndedIterator<Item = Id> + Send + Sync + 'static>,
69 map: Arc<dyn IdConvert + Send + Sync>,
70 reversed: bool,
71 buf: Vec<Result<Vertex>>,
72}
73
74impl Iter {
75 fn into_box_stream(self) -> BoxVertexStream {
76 Box::pin(futures::stream::unfold(self, |this| this.next()))
77 }
78
79 async fn next(mut self) -> Option<(Result<Vertex>, Self)> {
80 if let Some(name) = self.buf.pop() {
81 return Some((name, self));
82 }
83 let map = &self.map;
84 let opt_id = if self.reversed {
85 self.iter.next_back()
86 } else {
87 self.iter.next()
88 };
89 match opt_id {
90 None => None,
91 Some(id) => {
92 let contains = map
93 .contains_vertex_id_locally(&[id])
94 .await
95 .unwrap_or_default();
96 if contains == &[true] {
97 Some((map.vertex_name(id).await, self))
98 } else {
99 let batch_size = crate::config::BATCH_SIZE.load(Ordering::Acquire);
101 let mut ids = Vec::with_capacity(batch_size);
102 ids.push(id);
103 for _ in ids.len()..batch_size {
104 if let Some(id) = if self.reversed {
105 self.iter.next_back()
106 } else {
107 self.iter.next()
108 } {
109 ids.push(id);
110 } else {
111 break;
112 }
113 }
114 ids.reverse();
115 self.buf = match self.map.vertex_name_batch(&ids).await {
116 Err(e) => return Some((Err(e), self)),
117 Ok(names) => names,
118 };
119 if self.buf.len() != ids.len() {
120 let result =
121 crate::errors::bug("vertex_name_batch does not return enough items");
122 return Some((result, self));
123 }
124 let name = self.buf.pop().expect("buf is not empty");
125 Some((name, self))
126 }
127 }
128 }
129 }
130}
131
132struct DebugSpan {
133 span: OrderedSpan,
135 end_name: Option<Vertex>,
136 start_name: Option<Vertex>,
137}
138
139impl fmt::Debug for DebugSpan {
140 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141 match (
142 self.span.start == self.span.end,
143 &self.start_name,
144 &self.end_name,
145 ) {
146 (true, Some(name), _) => {
147 fmt::Debug::fmt(&name, f)?;
148 write!(f, "+{:?}", self.span.start)?;
149 }
150 (true, None, _) => {
151 write!(f, "{:?}", self.span.start)?;
152 }
153 (false, Some(start), Some(end)) => {
154 fmt::Debug::fmt(&start, f)?;
155 write!(f, ":")?;
156 fmt::Debug::fmt(&end, f)?;
157 write!(f, "+{:?}:{:?}", self.span.start, self.span.end)?;
158 }
159 (false, _, _) => {
160 write!(f, "{:?}:{:?}", self.span.start, self.span.end)?;
161 }
162 }
163 Ok(())
164 }
165}
166
167impl fmt::Debug for IdStaticSet {
168 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169 write!(f, "<spans ")?;
170 let spans_iter: Box<dyn Iterator<Item = OrderedSpan>> = match self.iteration_order {
171 IterationOrder::Custom(ref list) | IterationOrder::CustomReversed(ref list) => {
172 Box::new(list.as_spans().iter().copied())
173 }
174 _ => Box::new(self.spans.as_spans().iter().map(|s| OrderedSpan {
175 start: s.low,
176 end: s.high,
177 })),
178 };
179
180 let len = spans_iter.size_hint().0;
181 let limit = f.width().unwrap_or(3);
182 f.debug_list()
183 .entries(spans_iter.take(limit).map(|span| DebugSpan {
184 span,
185 end_name: disable_remote_protocol(|| {
186 non_blocking_result(self.map.vertex_name(span.end)).ok()
187 }),
188 start_name: disable_remote_protocol(|| {
189 non_blocking_result(self.map.vertex_name(span.start)).ok()
190 }),
191 }))
192 .finish()?;
193 match len.saturating_sub(limit) {
194 0 => {}
195 1 => write!(f, " + 1 span")?,
196 n => write!(f, " + {} spans", n)?,
197 }
198 match &self.iteration_order {
199 IterationOrder::Asc => write!(f, " +")?,
201 IterationOrder::Desc => {}
204 IterationOrder::Custom(_) => write!(f, " ?")?,
205 IterationOrder::CustomReversed(_) => write!(f, " ¿")?,
206 }
207 write!(f, ">")?;
208 Ok(())
209 }
210}
211
212impl IdStaticSet {
213 pub(crate) fn from_id_set_idmap_dag(
214 spans: IdSet,
215 map: Arc<dyn IdConvert + Send + Sync>,
216 dag: Arc<dyn DagAlgorithm + Send + Sync>,
217 ) -> Self {
218 let hints = Hints::new_with_idmap_dag(map.clone(), dag.clone());
219 hints.add_flags(Flags::ID_DESC | Flags::TOPO_DESC);
220 if spans.is_empty() {
221 hints.add_flags(Flags::EMPTY);
222 } else {
223 hints.set_min_id(spans.min().unwrap());
224 hints.set_max_id(spans.max().unwrap());
225 }
226 Self {
227 spans,
228 map,
229 hints,
230 dag,
231 iteration_order: IterationOrder::Desc,
232 }
233 }
234
235 pub(crate) fn from_id_list_idmap_dag(
237 list: IdList,
238 map: Arc<dyn IdConvert + Send + Sync>,
239 dag: Arc<dyn DagAlgorithm + Send + Sync>,
240 ) -> Self {
241 let hints = Hints::new_with_idmap_dag(map.clone(), dag.clone());
242
243 let mut flags = Flags::ID_DESC | Flags::TOPO_DESC | Flags::ID_ASC | Flags::EMPTY;
245 let mut min_id = None;
246 let mut max_id = None;
247 let mut last_min_id = None;
248 let mut last_max_id = None;
249 for span in list.as_spans() {
250 let (this_min_id, this_max_id) = (span.min(), span.max());
251 flags -= Flags::EMPTY;
252 if span.start < span.end || last_min_id.unwrap_or(Id::MAX) < this_max_id {
253 flags -= Flags::ID_DESC | Flags::TOPO_DESC;
255 }
256 if span.start > span.end || last_max_id.unwrap_or(Id::MIN) > this_min_id {
257 flags -= Flags::ID_ASC;
259 }
260 (last_min_id, last_max_id) = (Some(this_min_id), Some(this_max_id));
261 min_id = Some(this_min_id.min(min_id.unwrap_or(Id::MAX)));
262 max_id = Some(this_max_id.max(max_id.unwrap_or(Id::MIN)));
263 }
264
265 hints.add_flags(flags);
266 if let Some(min_id) = min_id {
267 hints.set_min_id(min_id);
268 }
269 if let Some(max_id) = max_id {
270 hints.set_max_id(max_id);
271 }
272
273 let spans = list.to_set();
274
275 let iteration_order = if flags.contains(Flags::ID_DESC) {
277 IterationOrder::Desc
278 } else if flags.contains(Flags::ID_ASC) {
279 IterationOrder::Asc
280 } else {
281 IterationOrder::Custom(list)
282 };
283
284 Self {
285 spans,
286 map,
287 hints,
288 dag,
289 iteration_order,
290 }
291 }
292
293 pub(crate) fn id_set_losing_order(&self) -> &IdSet {
295 &self.spans
296 }
297
298 pub(crate) fn id_set_try_preserving_order(&self) -> Option<&IdSet> {
301 if self
302 .hints()
303 .flags()
304 .intersects(Flags::ID_DESC | Flags::ID_ASC)
305 {
306 Some(&self.spans)
307 } else {
308 None
309 }
310 }
311
312 pub(crate) fn from_edit_spans(
319 lhs: &Self,
320 rhs: &Self,
321 edit_spans: fn(&IdSet, &IdSet) -> IdSet,
322 ) -> Option<Self> {
323 let order = lhs.map.map_version().partial_cmp(rhs.map.map_version())?;
324 let spans = edit_spans(&lhs.spans, &rhs.spans);
325 let picked = match order {
326 cmp::Ordering::Less => rhs,
327 cmp::Ordering::Greater | cmp::Ordering::Equal => lhs,
328 };
329 let (map, dag) = (picked.map.clone(), picked.dag.clone());
330 let mut result = Self::from_id_set_idmap_dag(spans, map, dag);
331 if let Some(order) = lhs.iteration_order() {
332 result.set_iteration_order(order);
333 }
334 Some(result)
335 }
336
337 pub fn reversed(mut self) -> Self {
339 match self.iteration_order {
340 IterationOrder::Desc => {
341 self.hints.remove_flags(Flags::ID_DESC | Flags::TOPO_DESC);
342 self.hints.add_flags(Flags::ID_ASC);
343 self.iteration_order = IterationOrder::Asc
344 }
345 IterationOrder::Asc => {
346 self.hints.remove_flags(Flags::ID_ASC);
347 self.hints.add_flags(Flags::ID_DESC | Flags::TOPO_DESC);
348 self.iteration_order = IterationOrder::Desc
349 }
350 IterationOrder::Custom(list) => {
351 self.hints
353 .remove_flags(Flags::ID_ASC | Flags::ID_DESC | Flags::TOPO_DESC);
354 self.iteration_order = IterationOrder::CustomReversed(list);
355 }
356 IterationOrder::CustomReversed(list) => {
357 self.hints
358 .remove_flags(Flags::ID_ASC | Flags::ID_DESC | Flags::TOPO_DESC);
359 self.iteration_order = IterationOrder::Custom(list);
360 }
361 }
362 self
363 }
364
365 pub(crate) fn set_iteration_order(&mut self, order: BasicIterationOrder) {
367 match order {
369 BasicIterationOrder::Asc => {
370 self.hints.remove_flags(Flags::ID_DESC | Flags::TOPO_DESC);
371 self.hints.add_flags(Flags::ID_ASC);
372 self.iteration_order = IterationOrder::Asc;
373 }
374 BasicIterationOrder::Desc => {
375 self.hints.remove_flags(Flags::ID_ASC);
376 self.hints.add_flags(Flags::ID_DESC | Flags::TOPO_DESC);
377 self.iteration_order = IterationOrder::Desc
378 }
379 }
380 }
381
382 pub(crate) fn iteration_order(&self) -> Option<BasicIterationOrder> {
384 match self.iteration_order {
385 IterationOrder::Asc => Some(BasicIterationOrder::Asc),
386 IterationOrder::Desc => Some(BasicIterationOrder::Desc),
387 #[allow(unreachable_patterns)]
388 _ => None,
389 }
390 }
391
392 async fn max(&self) -> Result<Option<Vertex>> {
393 debug_assert_eq!(self.spans.max(), self.spans.iter_desc().nth(0));
394 self.resolve_optional_id(self.spans.max()).await
395 }
396
397 async fn min(&self) -> Result<Option<Vertex>> {
398 debug_assert_eq!(self.spans.min(), self.spans.iter_desc().rev().nth(0));
399 self.resolve_optional_id(self.spans.min()).await
400 }
401
402 async fn resolve_optional_id(&self, id: Option<Id>) -> Result<Option<Vertex>> {
403 match id {
404 Some(id) => {
405 let map = &self.map;
406 let name = map.vertex_name(id).await?;
407 Ok(Some(name))
408 }
409 None => Ok(None),
410 }
411 }
412
413 pub(crate) fn slice_spans(mut self, skip: u64, take: u64) -> Self {
414 let (skip, take) = match self.iteration_order {
415 IterationOrder::Asc | IterationOrder::CustomReversed(_) => {
416 let len = self.spans.count();
417 let take1 = len.saturating_sub(skip);
421 let take2 = take1.min(take);
422 let skip2 = take1 - take2;
423 (skip2, take2)
424 }
425 IterationOrder::Desc | IterationOrder::Custom(_) => {
426 (skip, take)
429 }
430 };
431 match self.iteration_order {
432 IterationOrder::Custom(ref mut list) | IterationOrder::CustomReversed(ref mut list) => {
433 match (skip, take) {
434 (0, u64::MAX) => {}
435 (0, _) => *list = list.take(take),
436 (_, u64::MAX) => *list = list.skip(skip),
437 _ => *list = list.skip(skip).take(take),
438 };
439 self.spans = list.to_set();
440 }
441 _ => match (skip, take) {
442 (0, u64::MAX) => {}
443 (0, _) => self.spans = self.spans.take(take),
444 (_, u64::MAX) => self.spans = self.spans.skip(skip),
445 _ => self.spans = self.spans.skip(skip).take(take),
446 },
447 }
448 self
449 }
450
451 fn get_iter_and_reversed(
453 &self,
454 ) -> (
455 Box<dyn DoubleEndedIterator<Item = Id> + Send + Sync + 'static>,
456 bool,
457 ) {
458 let iter: Box<dyn DoubleEndedIterator<Item = Id> + Send + Sync + 'static> =
459 match self.iteration_order {
460 IterationOrder::Custom(ref list) | IterationOrder::CustomReversed(ref list) => {
461 Box::new(list.into_iter())
462 }
463 _ => Box::new(self.spans.clone().into_iter()),
464 };
465 let reversed = matches!(
466 self.iteration_order,
467 IterationOrder::Asc | IterationOrder::CustomReversed(_)
468 );
469 (iter, reversed)
470 }
471}
472
473#[async_trait::async_trait]
474impl AsyncSetQuery for IdStaticSet {
475 async fn iter(&self) -> Result<BoxVertexStream> {
476 let (iter, reversed) = self.get_iter_and_reversed();
477 let iter = Iter {
478 iter,
479 map: self.map.clone(),
480 reversed,
481 buf: Default::default(),
482 };
483 Ok(iter.into_box_stream())
484 }
485
486 async fn iter_rev(&self) -> Result<BoxVertexStream> {
487 let (iter, reversed) = self.get_iter_and_reversed();
488 let iter = Iter {
489 iter,
490 map: self.map.clone(),
491 reversed: !reversed,
492 buf: Default::default(),
493 };
494 Ok(iter.into_box_stream())
495 }
496
497 async fn count(&self) -> Result<u64> {
501 Ok(self.spans.count())
502 }
503
504 async fn count_slow(&self) -> Result<u64> {
505 Ok(self.spans.count())
506 }
507
508 async fn size_hint(&self) -> (u64, Option<u64>) {
509 let size = self.spans.count();
510 (size, Some(size))
511 }
512
513 async fn first(&self) -> Result<Option<Vertex>> {
514 match self.iteration_order {
515 IterationOrder::Asc => self.min().await,
516 IterationOrder::Desc => self.max().await,
517 IterationOrder::Custom(ref list) => {
518 self.resolve_optional_id(list.into_iter().next()).await
519 }
520 IterationOrder::CustomReversed(ref list) => {
521 self.resolve_optional_id(list.into_iter().next_back()).await
522 }
523 }
524 }
525
526 async fn last(&self) -> Result<Option<Vertex>> {
527 match self.iteration_order {
528 IterationOrder::Asc => self.max().await,
529 IterationOrder::Desc => self.min().await,
530 IterationOrder::Custom(ref list) => {
531 self.resolve_optional_id(list.into_iter().next_back()).await
532 }
533 IterationOrder::CustomReversed(ref list) => {
534 self.resolve_optional_id(list.into_iter().next()).await
535 }
536 }
537 }
538
539 async fn is_empty(&self) -> Result<bool> {
540 Ok(self.spans.is_empty())
541 }
542
543 async fn contains(&self, name: &Vertex) -> Result<bool> {
544 let result = match self.map.vertex_id_with_max_group(name, Group::MAX).await? {
545 Some(id) => self.spans.contains(id),
546 None => false,
547 };
548 Ok(result)
549 }
550
551 async fn contains_fast(&self, name: &Vertex) -> Result<Option<bool>> {
552 self.contains(name).await.map(Some)
553 }
554
555 fn as_any(&self) -> &dyn Any {
556 self
557 }
558
559 fn hints(&self) -> &Hints {
560 &self.hints
561 }
562
563 fn id_convert(&self) -> Option<&dyn IdConvert> {
564 Some(self.map.as_ref() as &dyn IdConvert)
565 }
566
567 fn specialized_reverse(&self) -> Option<Set> {
568 Some(Set::from_query(self.clone().reversed()))
569 }
570
571 fn specialized_take(&self, take: u64) -> Option<Set> {
572 Some(Set::from_query(self.clone().slice_spans(0, take)))
573 }
574
575 fn specialized_skip(&self, skip: u64) -> Option<Set> {
576 Some(Set::from_query(self.clone().slice_spans(skip, u64::MAX)))
577 }
578
579 fn specialized_flatten_id(&self) -> Option<Cow<IdStaticSet>> {
581 Some(Cow::Borrowed(self))
582 }
583}
584
585#[cfg(test)]
586#[allow(clippy::redundant_clone)]
587pub(crate) mod tests {
588 use std::ops::Deref;
589 use std::sync::atomic::Ordering::Acquire;
590
591 use futures::TryStreamExt;
592 use nonblocking::non_blocking_result as r;
593
594 use super::super::tests::*;
595 use super::super::Set;
596 use super::*;
597 use crate::ops::IdMapSnapshot;
598 use crate::set::difference::DifferenceSet;
599 use crate::set::intersection::IntersectionSet;
600 use crate::set::slice::SliceSet;
601 use crate::set::union::UnionSet;
602 use crate::tests::build_segments;
603 use crate::Dag;
604 use crate::DagAlgorithm;
605
606 pub(crate) fn with_dag<R, F: Fn(&Dag) -> R>(func: F) -> R {
608 let built = build_segments(
609 r#"
610 A--B--C--D
611 \--E--F--G"#,
612 "D G",
613 2,
614 );
615 func(&built.name_dag)
618 }
619
620 #[test]
621 fn test_dag_invariants() -> Result<()> {
622 with_dag(|dag| {
623 let bef = r(dag.range("B".into(), "F".into()))?;
624 check_invariants(bef.deref())?;
625 assert_eq!(nb(bef.size_hint()), (3, Some(3)));
626
627 Ok(())
628 })
629 }
630
631 #[test]
632 fn test_dag_fast_paths() -> Result<()> {
633 with_dag(|dag| {
634 let abcd = r(dag.ancestors("D".into()))?;
635 let abefg = r(dag.ancestors("G".into()))?;
636
637 let ab = abcd.intersection(&abefg);
638 check_invariants(ab.deref())?;
639
640 assert!(nb(abcd.contains(&vec![b'A'].into()))?);
641 assert!(!nb(abcd.contains(&vec![b'E'].into()))?);
642
643 assert_eq!(dbg(&ab), "<spans [A:B+0:1]>");
645
646 let abcdefg = abcd.union(&abefg);
647 check_invariants(abcd.deref())?;
648 assert_eq!(dbg(&abcdefg), "<spans [A:G+0:6]>");
650
651 let cd = abcd.difference(&abefg);
652 check_invariants(cd.deref())?;
653 assert_eq!(dbg(&cd), "<spans [C:D+2:3]>");
655
656 Ok(())
657 })
658 }
659
660 #[test]
661 fn test_dag_fast_path_set_ops() -> Result<()> {
662 with_dag(|dag| {
663 let abcd = r(dag.ancestors("D".into()))?.reverse();
664 let unordered = abcd.take(2).union_zip(&abcd.skip(3));
665
666 assert_eq!(
669 dbg(abcd.intersection(&unordered)),
670 "<spans [D+3, A:B+0:1] +>"
671 );
672 assert_eq!(dbg(abcd.difference(&unordered)), "<spans [C+2] +>");
673
674 assert_eq!(
676 dbg(unordered.intersection(&abcd)),
677 "<and <or <spans [A:B+0:1] +> <spans [D+3] +> (order=Zip)> <spans [A:D+0:3] +>>"
678 );
679 assert_eq!(
680 dbg(unordered.difference(&abcd)),
681 "<diff <or <spans [A:B+0:1] +> <spans [D+3] +> (order=Zip)> <spans [A:D+0:3] +>>"
682 );
683
684 assert_eq!(dbg(abcd.union(&unordered)), "<spans [A:D+0:3] +>");
686
687 assert_eq!(
689 dbg(abcd.union_preserving_order(&unordered)),
690 "<or <spans [A:D+0:3] +> <or <spans [A:B+0:1] +> <spans [D+3] +> (order=Zip)>>"
691 );
692
693 Ok(())
694 })
695 }
696
697 fn dbg_flat(set: &Set) -> String {
699 let flat = set.specialized_flatten_id();
700 let flat_str = match flat {
701 Some(flat) => format!(" flat:{}", fmt_iter(&Set::from_query(flat.into_owned()))),
702 None => String::new(),
703 };
704 format!("{}{}", fmt_iter(set), flat_str)
705 }
706
707 fn set_ops(a: &Set, b: &Set) -> (Set, Set, Set) {
709 let difference = DifferenceSet::new(a.clone(), b.clone());
710 let intersection = IntersectionSet::new(a.clone(), b.clone());
711 let union = UnionSet::new(a.clone(), b.clone());
712 (
713 Set::from_query(difference),
714 Set::from_query(intersection),
715 Set::from_query(union),
716 )
717 }
718
719 #[test]
720 fn test_dag_specialized_flatten_id_fast_path_with_set_ops() -> Result<()> {
721 with_dag(|dag| {
722 let mut abcd = "A B C D"
723 .split_whitespace()
724 .map(|s: &'static str| r(dag.sort(&s.into())).unwrap())
725 .collect::<Vec<_>>();
726 let d = abcd.pop().unwrap();
727 let c = abcd.pop().unwrap();
728 let b = abcd.pop().unwrap();
729 let a = abcd.pop().unwrap();
730
731 let acb = a.union_preserving_order(&b.union_preserving_order(&c).reverse());
732 let bcd = b.union_preserving_order(&c).union_preserving_order(&d);
733
734 let diff = acb.difference(&bcd);
736 let intersect = acb.intersection(&bcd);
737 let union1 = diff.union_preserving_order(&intersect);
738 let reversed1 = union1.reverse();
739 let union2 = reversed1.union_zip(&diff);
740 let reversed2 = union2.reverse();
741
742 assert_eq!(dbg_flat(&diff), "[A] flat:[A]");
744 assert_eq!(dbg_flat(&intersect), "[C, B] flat:[C, B]");
745 assert_eq!(dbg_flat(&union1), "[A, C, B] flat:[C, B, A]");
746 assert_eq!(dbg_flat(&reversed1), "[B, C, A] flat:[A, B, C]");
747 assert_eq!(dbg_flat(&union2), "[B, C, A] flat:[A, B, C]");
748 assert_eq!(dbg_flat(&reversed2), "[A, C, B] flat:[C, B, A]");
749
750 let count1 = union2
752 .as_any()
753 .downcast_ref::<UnionSet>()
754 .unwrap()
755 .test_slow_count
756 .load(Acquire);
757 let _ = r(union2.count())?;
758 let count2 = union2
759 .as_any()
760 .downcast_ref::<UnionSet>()
761 .unwrap()
762 .test_slow_count
763 .load(Acquire);
764 assert_eq!(count1, count2, "union.count() should not use slow path");
765
766 let count1 = dag.internal_stats.sort_slow_path_count.load(Acquire);
768 let _ = r(dag.sort(&reversed2))?;
769 let count2 = dag.internal_stats.sort_slow_path_count.load(Acquire);
770 assert_eq!(count1, count2, "dag.sort() should not use slow path");
771
772 assert_eq!(
774 wrap_dbg_lines(&reversed2),
775 r#"
776 <reverse
777 <or
778 <reverse
779 <or
780 <diff
781 <or <spans [A+0]> <reverse <or <spans [B+1]> <spans [C+2]>>>>
782 <or <or <spans [B+1]> <spans [C+2]>> <spans [D+3]>>>
783 <and
784 <or <spans [A+0]> <reverse <or <spans [B+1]> <spans [C+2]>>>>
785 <or <or <spans [B+1]> <spans [C+2]>> <spans [D+3]>>>>>
786 <diff
787 <or <spans [A+0]> <reverse <or <spans [B+1]> <spans [C+2]>>>>
788 <or <or <spans [B+1]> <spans [C+2]>> <spans [D+3]>>> (order=Zip)>>"#
789 );
790
791 let flattened = reversed2.specialized_flatten_id().unwrap();
793 assert_eq!(dbg(&flattened), "<spans [A:C+0:2]>");
794
795 Ok(())
796 })
797 }
798
799 #[test]
800 fn test_dag_specialized_flatten_id_fast_path_with_slices() -> Result<()> {
801 with_dag(|dag| {
803 let abcd = r(dag.ancestors("D".into()))?.reverse();
804 let abefg = r(dag.ancestors("G".into()))?.reverse();
805
806 let slice12 =
807 |a: &Set| -> Set { Set::from_query(SliceSet::new(a.clone(), 1, Some(2))) };
808
809 let (d, i, u) = set_ops(&abcd, &abefg);
810 assert_eq!(dbg_flat(&d), "[C, D] flat:[C, D]");
811 assert_eq!(dbg_flat(&i), "[A, B] flat:[A, B]");
812 assert_eq!(
813 dbg_flat(&u),
814 "[A, B, C, D, E, F, G] flat:[A, B, C, D, E, F, G]"
815 );
816 assert_eq!(dbg_flat(&slice12(&d)), "[D] flat:[D]");
817 assert_eq!(dbg_flat(&slice12(&i)), "[B] flat:[B]");
818 assert_eq!(dbg_flat(&slice12(&u)), "[B, C]"); let (d, i, u) = set_ops(&abcd.reverse(), &abefg);
822 assert_eq!(dbg_flat(&d), "[D, C] flat:[D, C]");
823 assert_eq!(dbg_flat(&i), "[B, A] flat:[B, A]");
824 assert_eq!(
825 dbg_flat(&u),
826 "[D, C, B, A, E, F, G] flat:[G, F, E, D, C, B, A]"
827 );
828 assert_eq!(dbg_flat(&slice12(&d)), "[C] flat:[C]");
829 assert_eq!(dbg_flat(&slice12(&i)), "[A] flat:[A]");
830 assert_eq!(dbg_flat(&slice12(&u)), "[C, B]"); let unordered = abcd.skip(1).take(2).union_zip(&abefg.take(2));
834 assert!(
835 !unordered
836 .hints()
837 .flags()
838 .intersects(Flags::ID_ASC | Flags::ID_DESC)
839 );
840 assert_eq!(dbg_flat(&unordered), "[B, A, C] flat:[A, B, C]");
841
842 assert_eq!(
844 dbg_flat(&slice12(&abcd.intersection(&unordered))),
845 "[B, C] flat:[B, C]"
846 );
847 assert_eq!(
848 dbg_flat(&slice12(&abefg.difference(&unordered))),
849 "[F, G] flat:[F, G]"
850 );
851
852 assert_eq!(
854 dbg_flat(&slice12(&abcd.union_preserving_order(&unordered))),
855 "[B, C]"
856 );
857 assert_eq!(dbg_flat(&slice12(&abcd.union_zip(&unordered))), "[B, C]");
858
859 assert_eq!(
861 dbg_flat(&slice12(&abcd.union(&unordered))),
862 "[B, C] flat:[B, C]"
863 );
864
865 Ok(())
866 })
867 }
868
869 #[test]
870 fn test_dag_no_fast_paths() -> Result<()> {
871 let f = |s: Set| -> String { dbg(s) };
872 with_dag(|dag1| -> Result<()> {
873 with_dag(|dag2| -> Result<()> {
874 let abcd = r(dag1.ancestors("D".into()))?;
875 let abefg = r(dag2.ancestors("G".into()))?;
876
877 let ab = abcd.intersection(&abefg);
881 check_invariants(ab.deref())?;
882 assert_eq!(
884 dbg(&ab),
885 "<and <spans [A:D+0:3]> <spans [E:G+4:6, A:B+0:1]>>"
886 );
887
888 let abcdefg = abcd.union(&abefg);
889 check_invariants(abcd.deref())?;
890 assert_eq!(
892 dbg(&abcdefg),
893 "<or <spans [A:D+0:3]> <spans [E:G+4:6, A:B+0:1]>>"
894 );
895
896 let cd = abcd.difference(&abefg);
897 check_invariants(cd.deref())?;
898 assert_eq!(
900 dbg(&cd),
901 "<diff <spans [A:D+0:3]> <spans [E:G+4:6, A:B+0:1]>>"
902 );
903
904 let a1 = || r(dag1.all()).unwrap();
907 let a2 = || r(dag2.all()).unwrap();
908 assert_eq!(f(a1() & a2()), "<and <spans [A:G+0:6]> <spans [A:G+0:6]>>");
909 assert_eq!(f(a1() | a2()), "<or <spans [A:G+0:6]> <spans [A:G+0:6]>>");
910 assert_eq!(f(a1() - a2()), "<diff <spans [A:G+0:6]> <spans [A:G+0:6]>>");
911
912 let z = || Set::from("Z");
916 assert_eq!(f(z() & a2()), "<and <static [Z]> <spans [A:G+0:6]>>");
917 assert_eq!(f(z() | a2()), "<or <static [Z]> <spans [A:G+0:6]>>");
918 assert_eq!(f(z() - a2()), "<diff <static [Z]> <spans [A:G+0:6]>>");
919 assert_eq!(f(a1() & z()), "<and <static [Z]> <spans [A:G+0:6]>>");
920 assert_eq!(f(a1() | z()), "<or <spans [A:G+0:6]> <static [Z]>>");
921 assert_eq!(f(a1() - z()), "<diff <spans [A:G+0:6]> <static [Z]>>");
922
923 let e = Set::empty;
925 assert_eq!(f(e() & a1()), "<empty>");
926 assert_eq!(f(e() | a1()), "<spans [A:G+0:6]>");
927 assert_eq!(f(e() - a1()), "<empty>");
928 assert_eq!(f(a1() & e()), "<empty>");
929 assert_eq!(f(a1() | e()), "<spans [A:G+0:6]>");
930 assert_eq!(f(a1() - e()), "<spans [A:G+0:6]>");
931
932 let count1 = dag1.internal_stats.sort_slow_path_count.load(Acquire);
934 let _ = r(dag1.sort(&abefg))?;
935 let count2 = dag1.internal_stats.sort_slow_path_count.load(Acquire);
936 assert_eq!(
937 count1 + 1,
938 count2,
939 "dag.sort() should use slow path for incompatible set"
940 );
941
942 Ok(())
943 })
944 })
945 }
946
947 #[test]
948 fn test_dag_all() -> Result<()> {
949 with_dag(|dag| {
950 let all = r(dag.all())?;
951 assert_eq!(dbg(&all), "<spans [A:G+0:6]>");
952
953 let ac: Set = "A C".into();
954 let ac = r(dag.sort(&ac))?;
955
956 let intersection = all.intersection(&ac);
957 assert_eq!(dbg(&intersection), "<spans [C+2, A+0]>");
959 Ok(())
960 })
961 }
962
963 #[test]
964 fn test_sort() -> Result<()> {
965 with_dag(|dag| -> Result<()> {
966 let set = "G C A E".into();
967 let sorted = r(dag.sort(&set))?;
968 assert_eq!(dbg(&sorted), "<spans [G+6, E+4, C+2] + 1 span>");
969 Ok(())
970 })
971 }
972
973 #[test]
974 fn test_reversed() -> Result<()> {
975 with_dag(|dag| {
976 let desc = r(dag.all())?;
977 let asc = desc
978 .as_any()
979 .downcast_ref::<IdStaticSet>()
980 .unwrap()
981 .clone()
982 .reversed();
983 check_invariants(&asc)?;
984 assert_eq!(dbg(&asc), "<spans [A:G+0:6] +>");
985 assert_eq!(
986 dbg(r(r(asc.iter())?.try_collect::<Vec<_>>())?),
987 "[A, B, C, D, E, F, G]"
988 );
989
990 Ok(())
991 })
992 }
993
994 #[test]
995 fn test_intersect_difference_preserve_reverse_order() -> Result<()> {
996 with_dag(|dag| -> Result<()> {
997 let abc = "A B C".into();
998 let cd = "C D".into();
999 let cba = r(dag.sort(&abc))?; let dc = r(dag.sort(&cd))?;
1001 let abc = cba.reverse();
1002
1003 let ab = abc.clone() - dc.clone();
1004 check_invariants(&*ab)?;
1005 assert_eq!(fmt_iter(&ab), "[A, B]");
1006
1007 let abc2 = abc.clone() & cba.clone();
1008 check_invariants(&*abc2)?;
1009 assert_eq!(fmt_iter(&abc2), "[A, B, C]");
1010
1011 let cba2 = cba & abc;
1012 check_invariants(&*cba2)?;
1013 assert_eq!(fmt_iter(&cba2), "[C, B, A]");
1014 Ok(())
1015 })
1016 }
1017
1018 #[test]
1019 fn test_skip_take_reverse() -> Result<()> {
1020 with_dag(|dag| {
1021 let set = r(dag.sort(&Set::from("A B C")))?;
1022 check_skip_take_reverse(set)
1023 })
1024 }
1025
1026 #[test]
1027 fn test_dag_hints_ancestors() -> Result<()> {
1028 with_dag(|dag| -> Result<()> {
1029 let abc = r(dag.ancestors("B C".into()))?;
1030 let abe = r(dag.common_ancestors("E".into()))?;
1031 let f: Set = "F".into();
1032 let all = r(dag.all())?;
1033
1034 assert!(has_ancestors_flag(abc.clone()));
1035 assert!(has_ancestors_flag(abe.clone()));
1036 assert!(has_ancestors_flag(all.clone()));
1037 assert!(has_ancestors_flag(r(dag.roots(abc.clone()))?));
1038 assert!(has_ancestors_flag(r(dag.parents(all.clone()))?));
1039
1040 assert!(!has_ancestors_flag(f.clone()));
1041 assert!(!has_ancestors_flag(r(dag.roots(f.clone()))?));
1042 assert!(!has_ancestors_flag(r(dag.parents(f.clone()))?));
1043
1044 Ok(())
1045 })
1046 }
1047
1048 #[test]
1049 fn test_dag_hints_ancestors_inheritance() -> Result<()> {
1050 with_dag(|dag1| -> Result<()> {
1051 with_dag(|dag2| -> Result<()> {
1052 let abc = r(dag1.ancestors("B C".into()))?;
1053
1054 assert!(has_ancestors_flag(r(dag1.sort(&abc))?));
1057 assert!(has_ancestors_flag(r(dag1.parents(abc.clone()))?));
1058 assert!(has_ancestors_flag(r(dag1.roots(abc.clone()))?));
1059
1060 assert!(!has_ancestors_flag(r(dag2.sort(&abc))?));
1064 assert!(!has_ancestors_flag(r(dag2.parents(abc.clone()))?));
1065 assert!(!has_ancestors_flag(r(dag2.roots(abc.clone()))?));
1066
1067 Ok(())
1068 })
1069 })
1070 }
1071
1072 #[test]
1073 fn test_dag_hints_ancestors_fast_paths() -> Result<()> {
1074 with_dag(|dag| -> Result<()> {
1075 let bfg: Set = "B F G".into();
1076
1077 bfg.hints().add_flags(Flags::ANCESTORS);
1079
1080 assert_eq!(dbg(r(dag.ancestors(bfg.clone()))?), "<static [B, F, G]>");
1082 assert_eq!(dbg(r(dag.heads(bfg.clone()))?), "<spans [G+6]>");
1083
1084 let bfg = r(dag.sort(&bfg))?;
1086 bfg.hints().add_flags(Flags::ANCESTORS);
1087 assert_eq!(
1088 dbg(r(dag.ancestors(bfg.clone()))?),
1089 "<spans [F:G+5:6, B+1]>"
1090 );
1091
1092 assert_eq!(dbg(r(dag.heads(bfg.clone()))?), "<spans [G+6]>");
1095
1096 assert_eq!(
1099 dbg(r(dag.ancestors(bfg.clone()))?),
1100 "<spans [F:G+5:6, B+1]>"
1101 );
1102
1103 Ok(())
1104 })
1105 }
1106
1107 #[test]
1108 fn test_custom_order_hints() -> Result<()> {
1109 with_dag(|dag| -> Result<()> {
1110 let map = dag.id_map_snapshot()?;
1112 let dag = dag.dag_snapshot()?;
1113 let show_hints = move |ids: &[u64]| {
1114 let list = IdList::from_ids(ids.iter().map(|&id| Id(id)));
1115 let set = IdStaticSet::from_id_list_idmap_dag(list, map.clone(), dag.clone());
1116 check_invariants(&set).unwrap();
1117 let set_reversed = set.clone().reversed();
1118 check_invariants(&set_reversed).unwrap();
1119 let hints = set.hints();
1120 format!(
1121 "Order: {:?} Min: {:?} Max: {:?} {:?}",
1122 set.iteration_order(),
1123 hints.min_id(),
1124 hints.max_id(),
1125 hints.flags(),
1126 )
1127 };
1128
1129 assert_eq!(
1130 show_hints(&[]),
1131 "Order: Some(Desc) Min: None Max: None Flags(EMPTY | ID_DESC | ID_ASC | TOPO_DESC | ANCESTORS)"
1132 );
1133 assert_eq!(
1134 show_hints(&[2]),
1135 "Order: Some(Desc) Min: Some(2) Max: Some(2) Flags(ID_DESC | ID_ASC | TOPO_DESC | HAS_MIN_ID | HAS_MAX_ID)"
1136 );
1137 assert_eq!(
1138 show_hints(&[1, 2]),
1139 "Order: Some(Asc) Min: Some(1) Max: Some(2) Flags(ID_ASC | HAS_MIN_ID | HAS_MAX_ID)"
1140 );
1141 assert_eq!(
1142 show_hints(&[2, 1]),
1143 "Order: Some(Desc) Min: Some(1) Max: Some(2) Flags(ID_DESC | TOPO_DESC | HAS_MIN_ID | HAS_MAX_ID)"
1144 );
1145 assert_eq!(
1146 show_hints(&[1, 2, 4, 5]),
1147 "Order: Some(Asc) Min: Some(1) Max: Some(5) Flags(ID_ASC | HAS_MIN_ID | HAS_MAX_ID)"
1148 );
1149 assert_eq!(
1150 show_hints(&[5, 4, 2, 1]),
1151 "Order: Some(Desc) Min: Some(1) Max: Some(5) Flags(ID_DESC | TOPO_DESC | HAS_MIN_ID | HAS_MAX_ID)"
1152 );
1153 assert_eq!(
1154 show_hints(&[4, 5, 1, 2]),
1155 "Order: None Min: Some(1) Max: Some(5) Flags(HAS_MIN_ID | HAS_MAX_ID)"
1156 );
1157 assert_eq!(
1158 show_hints(&[2, 1, 5, 4]),
1159 "Order: None Min: Some(1) Max: Some(5) Flags(HAS_MIN_ID | HAS_MAX_ID)"
1160 );
1161 assert_eq!(
1162 show_hints(&[4, 5, 1]),
1163 "Order: None Min: Some(1) Max: Some(5) Flags(HAS_MIN_ID | HAS_MAX_ID)"
1164 );
1165 assert_eq!(
1166 show_hints(&[2, 1, 5]),
1167 "Order: None Min: Some(1) Max: Some(5) Flags(HAS_MIN_ID | HAS_MAX_ID)"
1168 );
1169
1170 Ok(())
1171 })
1172 }
1173
1174 #[test]
1175 fn test_custom_order_debug_fmt() -> Result<()> {
1176 with_dag(|dag| -> Result<()> {
1177 let map = dag.id_map_snapshot()?;
1178 let dag = dag.dag_snapshot()?;
1179 let list = move |ids: &[u64]| {
1180 let list = IdList::from_ids(ids.iter().map(|&id| Id(id)));
1181 IdStaticSet::from_id_list_idmap_dag(list, map.clone(), dag.clone())
1182 };
1183
1184 assert_eq!(dbg(list(&[1, 3, 2])), "<spans [B+1, D:C+3:2] ?>");
1185 assert_eq!(dbg(list(&[1, 3, 2]).reversed()), "<spans [B+1, D:C+3:2] ¿>");
1186
1187 Ok(())
1188 })
1189 }
1190
1191 fn has_ancestors_flag(set: Set) -> bool {
1192 set.hints().contains(Flags::ANCESTORS)
1193 }
1194
1195 fn wrap_dbg_lines(value: &dyn fmt::Debug) -> String {
1197 #[derive(Default, Debug)]
1198 struct Fmt<'a> {
1199 head: &'a str,
1200 tail: &'a str,
1201 body: Vec<Fmt<'a>>,
1202 len: usize,
1203 }
1204
1205 fn indent(s: &str, prefix: &str) -> String {
1206 format!(
1207 "\n{}{}",
1208 prefix,
1209 s.trim().replace('\n', &format!("\n{}", prefix))
1210 )
1211 }
1212
1213 impl<'a> Fmt<'a> {
1214 fn parse(mut s: &'a str) -> (Self, &'a str) {
1216 let mut out = Self::default();
1217 let mut seen_left = false;
1218 let mut i = 0;
1219 while i < s.len() {
1220 let ch = s.as_bytes()[i];
1221 match ch {
1222 b'<' => {
1223 if seen_left {
1224 if out.head.is_empty() {
1225 out.head = &s[..i].trim();
1226 out.len += out.head.len();
1227 }
1228 let (nested, rest) = Self::parse(&s[i..]);
1229 out.len += nested.len;
1230 out.body.push(nested);
1231 s = rest;
1232 i = 0;
1233 continue;
1234 } else {
1235 seen_left = true;
1236 i += 1;
1237 }
1238 }
1239 b'>' => {
1240 out.tail = &s[..i + 1].trim();
1241 out.len += out.tail.len();
1242 if out.head.is_empty() {
1243 (out.head, out.tail) = out.tail.split_once(' ').unwrap();
1244 }
1245 let rest = &s[i + 1..];
1246 return (out, rest);
1247 }
1248 _ => i += 1,
1249 }
1250 }
1251 panic!("unbalanced <> in fmt string");
1252 }
1253
1254 fn pretty(&self) -> String {
1255 let mut out = String::new();
1256 let need_wrap = !self.body.is_empty() && self.len > 80;
1257 out.push_str(self.head);
1258 for f in &self.body {
1259 let mut s = f.pretty();
1260 if need_wrap {
1261 s = indent(&s, " ");
1262 } else {
1263 s = format!(" {}", s);
1264 }
1265 out.push_str(&s);
1266 }
1267 if self.tail != ">" {
1268 out.push(' ');
1269 }
1270 out.push_str(self.tail);
1271 out
1272 }
1273 }
1274
1275 let s = dbg(value);
1276 let f = Fmt::parse(&s).0;
1277 indent(&f.pretty(), " ")
1278 }
1279}