1
2
3
4
5 package ssa
6
7 import (
8 "fmt"
9 "os"
10 "slices"
11 )
12
13
14 var debugPoset = false
15
16 const uintSize = 32 << (^uint(0) >> 63)
17
18
19 type bitset []uint
20
21 func newBitset(n int) bitset {
22 return make(bitset, (n+uintSize-1)/uintSize)
23 }
24
25 func (bs bitset) Reset() {
26 for i := range bs {
27 bs[i] = 0
28 }
29 }
30
31 func (bs bitset) Set(idx uint32) {
32 bs[idx/uintSize] |= 1 << (idx % uintSize)
33 }
34
35 func (bs bitset) Clear(idx uint32) {
36 bs[idx/uintSize] &^= 1 << (idx % uintSize)
37 }
38
39 func (bs bitset) Test(idx uint32) bool {
40 return bs[idx/uintSize]&(1<<(idx%uintSize)) != 0
41 }
42
43 type undoType uint8
44
45 const (
46 undoInvalid undoType = iota
47 undoCheckpoint
48 undoSetChl
49 undoSetChr
50 undoNonEqual
51 undoNewNode
52 undoAliasNode
53 undoNewRoot
54 undoChangeRoot
55 undoMergeRoot
56 )
57
58
59
60
61
62 type posetUndo struct {
63 typ undoType
64 idx uint32
65 ID ID
66 edge posetEdge
67 }
68
69 const (
70
71
72 posetFlagUnsigned = 1 << iota
73 )
74
75
76
77 type posetEdge uint32
78
79 func newedge(t uint32, strict bool) posetEdge {
80 s := uint32(0)
81 if strict {
82 s = 1
83 }
84 return posetEdge(t<<1 | s)
85 }
86 func (e posetEdge) Target() uint32 { return uint32(e) >> 1 }
87 func (e posetEdge) Strict() bool { return uint32(e)&1 != 0 }
88 func (e posetEdge) String() string {
89 s := fmt.Sprint(e.Target())
90 if e.Strict() {
91 s += "*"
92 }
93 return s
94 }
95
96
97 type posetNode struct {
98 l, r posetEdge
99 }
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 type poset struct {
142 lastidx uint32
143 flags uint8
144 values map[ID]uint32
145 nodes []posetNode
146 roots []uint32
147 noneq map[uint32]bitset
148 undo []posetUndo
149 }
150
151 func newPoset() *poset {
152 return &poset{
153 values: make(map[ID]uint32),
154 nodes: make([]posetNode, 1, 16),
155 roots: make([]uint32, 0, 4),
156 noneq: make(map[uint32]bitset),
157 undo: make([]posetUndo, 0, 4),
158 }
159 }
160
161 func (po *poset) SetUnsigned(uns bool) {
162 if uns {
163 po.flags |= posetFlagUnsigned
164 } else {
165 po.flags &^= posetFlagUnsigned
166 }
167 }
168
169
170 func (po *poset) setchl(i uint32, l posetEdge) { po.nodes[i].l = l }
171 func (po *poset) setchr(i uint32, r posetEdge) { po.nodes[i].r = r }
172 func (po *poset) chl(i uint32) uint32 { return po.nodes[i].l.Target() }
173 func (po *poset) chr(i uint32) uint32 { return po.nodes[i].r.Target() }
174 func (po *poset) children(i uint32) (posetEdge, posetEdge) {
175 return po.nodes[i].l, po.nodes[i].r
176 }
177
178
179
180 func (po *poset) upush(typ undoType, p uint32, e posetEdge) {
181 po.undo = append(po.undo, posetUndo{typ: typ, idx: p, edge: e})
182 }
183
184
185 func (po *poset) upushnew(id ID, idx uint32) {
186 po.undo = append(po.undo, posetUndo{typ: undoNewNode, ID: id, idx: idx})
187 }
188
189
190 func (po *poset) upushneq(idx1 uint32, idx2 uint32) {
191 po.undo = append(po.undo, posetUndo{typ: undoNonEqual, ID: ID(idx1), idx: idx2})
192 }
193
194
195 func (po *poset) upushalias(id ID, i2 uint32) {
196 po.undo = append(po.undo, posetUndo{typ: undoAliasNode, ID: id, idx: i2})
197 }
198
199
200 func (po *poset) addchild(i1, i2 uint32, strict bool) {
201 i1l, i1r := po.children(i1)
202 e2 := newedge(i2, strict)
203
204 if i1l == 0 {
205 po.setchl(i1, e2)
206 po.upush(undoSetChl, i1, 0)
207 } else if i1r == 0 {
208 po.setchr(i1, e2)
209 po.upush(undoSetChr, i1, 0)
210 } else {
211
212
213
214
215
216
217
218
219
220
221
222
223 extra := po.newnode(nil)
224 if (i1^i2)&1 != 0 {
225 po.setchl(extra, i1r)
226 po.setchr(extra, e2)
227 po.setchr(i1, newedge(extra, false))
228 po.upush(undoSetChr, i1, i1r)
229 } else {
230 po.setchl(extra, i1l)
231 po.setchr(extra, e2)
232 po.setchl(i1, newedge(extra, false))
233 po.upush(undoSetChl, i1, i1l)
234 }
235 }
236 }
237
238
239
240 func (po *poset) newnode(n *Value) uint32 {
241 i := po.lastidx + 1
242 po.lastidx++
243 po.nodes = append(po.nodes, posetNode{})
244 if n != nil {
245 if po.values[n.ID] != 0 {
246 panic("newnode for Value already inserted")
247 }
248 po.values[n.ID] = i
249 po.upushnew(n.ID, i)
250 } else {
251 po.upushnew(0, i)
252 }
253 return i
254 }
255
256
257 func (po *poset) lookup(n *Value) (uint32, bool) {
258 i, f := po.values[n.ID]
259 return i, f
260 }
261
262
263
264 func (po *poset) aliasnewnode(n1, n2 *Value) {
265 i1, i2 := po.values[n1.ID], po.values[n2.ID]
266 if i1 == 0 || i2 != 0 {
267 panic("aliasnewnode invalid arguments")
268 }
269
270 po.values[n2.ID] = i1
271 po.upushalias(n2.ID, 0)
272 }
273
274
275
276
277
278
279 func (po *poset) aliasnodes(n1 *Value, i2s bitset) {
280 i1 := po.values[n1.ID]
281 if i1 == 0 {
282 panic("aliasnode for non-existing node")
283 }
284 if i2s.Test(i1) {
285 panic("aliasnode i2s contains n1 node")
286 }
287
288
289 for idx, n := range po.nodes {
290
291 if uint32(idx) == i1 {
292 continue
293 }
294 l, r := n.l, n.r
295
296
297 if i2s.Test(l.Target()) {
298 po.setchl(uint32(idx), newedge(i1, l.Strict()))
299 po.upush(undoSetChl, uint32(idx), l)
300 }
301 if i2s.Test(r.Target()) {
302 po.setchr(uint32(idx), newedge(i1, r.Strict()))
303 po.upush(undoSetChr, uint32(idx), r)
304 }
305
306
307
308 if i2s.Test(uint32(idx)) {
309 if l != 0 && !i2s.Test(l.Target()) {
310 po.addchild(i1, l.Target(), l.Strict())
311 }
312 if r != 0 && !i2s.Test(r.Target()) {
313 po.addchild(i1, r.Target(), r.Strict())
314 }
315 po.setchl(uint32(idx), 0)
316 po.setchr(uint32(idx), 0)
317 po.upush(undoSetChl, uint32(idx), l)
318 po.upush(undoSetChr, uint32(idx), r)
319 }
320 }
321
322
323
324 for k, v := range po.values {
325 if i2s.Test(v) {
326 po.values[k] = i1
327 po.upushalias(k, v)
328 }
329 }
330 }
331
332 func (po *poset) isroot(r uint32) bool {
333 for i := range po.roots {
334 if po.roots[i] == r {
335 return true
336 }
337 }
338 return false
339 }
340
341 func (po *poset) changeroot(oldr, newr uint32) {
342 for i := range po.roots {
343 if po.roots[i] == oldr {
344 po.roots[i] = newr
345 return
346 }
347 }
348 panic("changeroot on non-root")
349 }
350
351 func (po *poset) removeroot(r uint32) {
352 for i := range po.roots {
353 if po.roots[i] == r {
354 po.roots = slices.Delete(po.roots, i, i+1)
355 return
356 }
357 }
358 panic("removeroot on non-root")
359 }
360
361
362
363
364
365
366
367
368
369 func (po *poset) dfs(r uint32, strict bool, f func(i uint32) bool) bool {
370 closed := newBitset(int(po.lastidx + 1))
371 open := make([]uint32, 1, 64)
372 open[0] = r
373
374 if strict {
375
376
377
378 next := make([]uint32, 0, 64)
379
380 for len(open) > 0 {
381 i := open[len(open)-1]
382 open = open[:len(open)-1]
383
384
385
386
387
388 if !closed.Test(i) {
389 closed.Set(i)
390
391 l, r := po.children(i)
392 if l != 0 {
393 if l.Strict() {
394 next = append(next, l.Target())
395 } else {
396 open = append(open, l.Target())
397 }
398 }
399 if r != 0 {
400 if r.Strict() {
401 next = append(next, r.Target())
402 } else {
403 open = append(open, r.Target())
404 }
405 }
406 }
407 }
408 open = next
409 closed.Reset()
410 }
411
412 for len(open) > 0 {
413 i := open[len(open)-1]
414 open = open[:len(open)-1]
415
416 if !closed.Test(i) {
417 if f(i) {
418 return true
419 }
420 closed.Set(i)
421 l, r := po.children(i)
422 if l != 0 {
423 open = append(open, l.Target())
424 }
425 if r != 0 {
426 open = append(open, r.Target())
427 }
428 }
429 }
430 return false
431 }
432
433
434
435
436
437 func (po *poset) reaches(i1, i2 uint32, strict bool) bool {
438 return po.dfs(i1, strict, func(n uint32) bool {
439 return n == i2
440 })
441 }
442
443
444
445
446 func (po *poset) findroot(i uint32) uint32 {
447
448
449
450 for _, r := range po.roots {
451 if po.reaches(r, i, false) {
452 return r
453 }
454 }
455 panic("findroot didn't find any root")
456 }
457
458
459 func (po *poset) mergeroot(r1, r2 uint32) uint32 {
460 r := po.newnode(nil)
461 po.setchl(r, newedge(r1, false))
462 po.setchr(r, newedge(r2, false))
463 po.changeroot(r1, r)
464 po.removeroot(r2)
465 po.upush(undoMergeRoot, r, 0)
466 return r
467 }
468
469
470
471
472
473 func (po *poset) collapsepath(n1, n2 *Value) bool {
474 i1, i2 := po.values[n1.ID], po.values[n2.ID]
475 if po.reaches(i1, i2, true) {
476 return false
477 }
478
479
480 paths := po.findpaths(i1, i2)
481
482
483 paths.Clear(i1)
484 po.aliasnodes(n1, paths)
485 return true
486 }
487
488
489
490
491
492
493
494 func (po *poset) findpaths(cur, dst uint32) bitset {
495 seen := newBitset(int(po.lastidx + 1))
496 path := newBitset(int(po.lastidx + 1))
497 path.Set(dst)
498 po.findpaths1(cur, dst, seen, path)
499 return path
500 }
501
502 func (po *poset) findpaths1(cur, dst uint32, seen bitset, path bitset) {
503 if cur == dst {
504 return
505 }
506 seen.Set(cur)
507 l, r := po.chl(cur), po.chr(cur)
508 if !seen.Test(l) {
509 po.findpaths1(l, dst, seen, path)
510 }
511 if !seen.Test(r) {
512 po.findpaths1(r, dst, seen, path)
513 }
514 if path.Test(l) || path.Test(r) {
515 path.Set(cur)
516 }
517 }
518
519
520 func (po *poset) isnoneq(i1, i2 uint32) bool {
521 if i1 == i2 {
522 return false
523 }
524 if i1 < i2 {
525 i1, i2 = i2, i1
526 }
527
528
529 if bs, ok := po.noneq[i1]; ok && bs.Test(i2) {
530 return true
531 }
532 return false
533 }
534
535
536 func (po *poset) setnoneq(n1, n2 *Value) {
537 i1, f1 := po.lookup(n1)
538 i2, f2 := po.lookup(n2)
539
540
541
542
543 if !f1 {
544 i1 = po.newnode(n1)
545 po.roots = append(po.roots, i1)
546 po.upush(undoNewRoot, i1, 0)
547 }
548 if !f2 {
549 i2 = po.newnode(n2)
550 po.roots = append(po.roots, i2)
551 po.upush(undoNewRoot, i2, 0)
552 }
553
554 if i1 == i2 {
555 panic("setnoneq on same node")
556 }
557 if i1 < i2 {
558 i1, i2 = i2, i1
559 }
560 bs := po.noneq[i1]
561 if bs == nil {
562
563
564
565
566 bs = newBitset(int(i1))
567 po.noneq[i1] = bs
568 } else if bs.Test(i2) {
569
570 return
571 }
572 bs.Set(i2)
573 po.upushneq(i1, i2)
574 }
575
576
577
578 func (po *poset) CheckIntegrity() {
579
580 seen := newBitset(int(po.lastidx + 1))
581 for _, r := range po.roots {
582 if r == 0 {
583 panic("empty root")
584 }
585
586 po.dfs(r, false, func(i uint32) bool {
587 if seen.Test(i) {
588 panic("duplicate node")
589 }
590 seen.Set(i)
591 return false
592 })
593 }
594
595
596 for id, idx := range po.values {
597 if !seen.Test(idx) {
598 panic(fmt.Errorf("spurious value [%d]=%d", id, idx))
599 }
600 }
601
602
603 for i, n := range po.nodes {
604 if n.l|n.r != 0 {
605 if !seen.Test(uint32(i)) {
606 panic(fmt.Errorf("children of unknown node %d->%v", i, n))
607 }
608 if n.l.Target() == uint32(i) || n.r.Target() == uint32(i) {
609 panic(fmt.Errorf("self-loop on node %d", i))
610 }
611 }
612 }
613 }
614
615
616
617
618 func (po *poset) CheckEmpty() error {
619 if len(po.nodes) != 1 {
620 return fmt.Errorf("non-empty nodes list: %v", po.nodes)
621 }
622 if len(po.values) != 0 {
623 return fmt.Errorf("non-empty value map: %v", po.values)
624 }
625 if len(po.roots) != 0 {
626 return fmt.Errorf("non-empty root list: %v", po.roots)
627 }
628 if len(po.undo) != 0 {
629 return fmt.Errorf("non-empty undo list: %v", po.undo)
630 }
631 if po.lastidx != 0 {
632 return fmt.Errorf("lastidx index is not zero: %v", po.lastidx)
633 }
634 for _, bs := range po.noneq {
635 for _, x := range bs {
636 if x != 0 {
637 return fmt.Errorf("non-empty noneq map")
638 }
639 }
640 }
641 return nil
642 }
643
644
645 func (po *poset) DotDump(fn string, title string) error {
646 f, err := os.Create(fn)
647 if err != nil {
648 return err
649 }
650 defer f.Close()
651
652
653 names := make(map[uint32]string)
654 for id, i := range po.values {
655 s := names[i]
656 if s == "" {
657 s = fmt.Sprintf("v%d", id)
658 } else {
659 s += fmt.Sprintf(", v%d", id)
660 }
661 names[i] = s
662 }
663
664 fmt.Fprintf(f, "digraph poset {\n")
665 fmt.Fprintf(f, "\tedge [ fontsize=10 ]\n")
666 for ridx, r := range po.roots {
667 fmt.Fprintf(f, "\tsubgraph root%d {\n", ridx)
668 po.dfs(r, false, func(i uint32) bool {
669 fmt.Fprintf(f, "\t\tnode%d [label=<%s <font point-size=\"6\">[%d]</font>>]\n", i, names[i], i)
670 chl, chr := po.children(i)
671 for _, ch := range []posetEdge{chl, chr} {
672 if ch != 0 {
673 if ch.Strict() {
674 fmt.Fprintf(f, "\t\tnode%d -> node%d [label=\" <\" color=\"red\"]\n", i, ch.Target())
675 } else {
676 fmt.Fprintf(f, "\t\tnode%d -> node%d [label=\" <=\" color=\"green\"]\n", i, ch.Target())
677 }
678 }
679 }
680 return false
681 })
682 fmt.Fprintf(f, "\t}\n")
683 }
684 fmt.Fprintf(f, "\tlabelloc=\"t\"\n")
685 fmt.Fprintf(f, "\tlabeldistance=\"3.0\"\n")
686 fmt.Fprintf(f, "\tlabel=%q\n", title)
687 fmt.Fprintf(f, "}\n")
688 return nil
689 }
690
691
692
693
694
695 func (po *poset) Ordered(n1, n2 *Value) bool {
696 if debugPoset {
697 defer po.CheckIntegrity()
698 }
699 if n1.ID == n2.ID {
700 panic("should not call Ordered with n1==n2")
701 }
702
703 i1, f1 := po.lookup(n1)
704 i2, f2 := po.lookup(n2)
705 if !f1 || !f2 {
706 return false
707 }
708
709 return i1 != i2 && po.reaches(i1, i2, true)
710 }
711
712
713
714
715
716 func (po *poset) OrderedOrEqual(n1, n2 *Value) bool {
717 if debugPoset {
718 defer po.CheckIntegrity()
719 }
720 if n1.ID == n2.ID {
721 panic("should not call Ordered with n1==n2")
722 }
723
724 i1, f1 := po.lookup(n1)
725 i2, f2 := po.lookup(n2)
726 if !f1 || !f2 {
727 return false
728 }
729
730 return i1 == i2 || po.reaches(i1, i2, false)
731 }
732
733
734
735
736
737 func (po *poset) Equal(n1, n2 *Value) bool {
738 if debugPoset {
739 defer po.CheckIntegrity()
740 }
741 if n1.ID == n2.ID {
742 panic("should not call Equal with n1==n2")
743 }
744
745 i1, f1 := po.lookup(n1)
746 i2, f2 := po.lookup(n2)
747 return f1 && f2 && i1 == i2
748 }
749
750
751
752
753
754
755 func (po *poset) NonEqual(n1, n2 *Value) bool {
756 if debugPoset {
757 defer po.CheckIntegrity()
758 }
759 if n1.ID == n2.ID {
760 panic("should not call NonEqual with n1==n2")
761 }
762
763
764
765 i1, f1 := po.lookup(n1)
766 i2, f2 := po.lookup(n2)
767 if !f1 || !f2 {
768 return false
769 }
770
771
772 if po.isnoneq(i1, i2) {
773 return true
774 }
775
776
777 if po.Ordered(n1, n2) || po.Ordered(n2, n1) {
778 return true
779 }
780
781 return false
782 }
783
784
785
786
787 func (po *poset) setOrder(n1, n2 *Value, strict bool) bool {
788 i1, f1 := po.lookup(n1)
789 i2, f2 := po.lookup(n2)
790
791 switch {
792 case !f1 && !f2:
793
794
795
796 i1, i2 = po.newnode(n1), po.newnode(n2)
797 po.roots = append(po.roots, i1)
798 po.upush(undoNewRoot, i1, 0)
799 po.addchild(i1, i2, strict)
800
801 case f1 && !f2:
802
803
804 i2 = po.newnode(n2)
805 po.addchild(i1, i2, strict)
806
807 case !f1 && f2:
808
809
810
811 i1 = po.newnode(n1)
812
813 if po.isroot(i2) {
814 po.changeroot(i2, i1)
815 po.upush(undoChangeRoot, i1, newedge(i2, strict))
816 po.addchild(i1, i2, strict)
817 return true
818 }
819
820
821
822 r := po.findroot(i2)
823
824
825
826
827
828
829
830
831
832 extra := po.newnode(nil)
833 po.changeroot(r, extra)
834 po.upush(undoChangeRoot, extra, newedge(r, false))
835 po.addchild(extra, r, false)
836 po.addchild(extra, i1, false)
837 po.addchild(i1, i2, strict)
838
839 case f1 && f2:
840
841
842 if i1 == i2 {
843 return !strict
844 }
845
846
847
848 if !strict && po.isnoneq(i1, i2) {
849 strict = true
850 }
851
852
853
854
855
856 if po.reaches(i1, i2, false) {
857
858
859
860
861
862
863
864
865
866
867 if strict && !po.reaches(i1, i2, true) {
868 po.addchild(i1, i2, true)
869 return true
870 }
871
872
873 return true
874 }
875
876
877 if po.reaches(i2, i1, false) {
878
879
880
881
882
883
884
885
886
887 if strict {
888
889 return false
890 }
891
892
893
894 return po.collapsepath(n2, n1)
895 }
896
897
898
899
900 r1, r2 := po.findroot(i1), po.findroot(i2)
901 if r1 != r2 {
902
903 po.mergeroot(r1, r2)
904 }
905
906
907 po.addchild(i1, i2, strict)
908 }
909
910 return true
911 }
912
913
914
915 func (po *poset) SetOrder(n1, n2 *Value) bool {
916 if debugPoset {
917 defer po.CheckIntegrity()
918 }
919 if n1.ID == n2.ID {
920 panic("should not call SetOrder with n1==n2")
921 }
922 return po.setOrder(n1, n2, true)
923 }
924
925
926
927 func (po *poset) SetOrderOrEqual(n1, n2 *Value) bool {
928 if debugPoset {
929 defer po.CheckIntegrity()
930 }
931 if n1.ID == n2.ID {
932 panic("should not call SetOrder with n1==n2")
933 }
934 return po.setOrder(n1, n2, false)
935 }
936
937
938
939
940 func (po *poset) SetEqual(n1, n2 *Value) bool {
941 if debugPoset {
942 defer po.CheckIntegrity()
943 }
944 if n1.ID == n2.ID {
945 panic("should not call Add with n1==n2")
946 }
947
948 i1, f1 := po.lookup(n1)
949 i2, f2 := po.lookup(n2)
950
951 switch {
952 case !f1 && !f2:
953 i1 = po.newnode(n1)
954 po.roots = append(po.roots, i1)
955 po.upush(undoNewRoot, i1, 0)
956 po.aliasnewnode(n1, n2)
957 case f1 && !f2:
958 po.aliasnewnode(n1, n2)
959 case !f1 && f2:
960 po.aliasnewnode(n2, n1)
961 case f1 && f2:
962 if i1 == i2 {
963
964 return true
965 }
966
967
968 if po.isnoneq(i1, i2) {
969 return false
970 }
971
972
973
974 if po.reaches(i1, i2, false) {
975 return po.collapsepath(n1, n2)
976 }
977 if po.reaches(i2, i1, false) {
978 return po.collapsepath(n2, n1)
979 }
980
981 r1 := po.findroot(i1)
982 r2 := po.findroot(i2)
983 if r1 != r2 {
984
985 po.mergeroot(r1, r2)
986 }
987
988
989
990 i2s := newBitset(int(po.lastidx) + 1)
991 i2s.Set(i2)
992 po.aliasnodes(n1, i2s)
993 }
994 return true
995 }
996
997
998
999
1000 func (po *poset) SetNonEqual(n1, n2 *Value) bool {
1001 if debugPoset {
1002 defer po.CheckIntegrity()
1003 }
1004 if n1.ID == n2.ID {
1005 panic("should not call SetNonEqual with n1==n2")
1006 }
1007
1008
1009 i1, f1 := po.lookup(n1)
1010 i2, f2 := po.lookup(n2)
1011
1012
1013
1014 if !f1 || !f2 {
1015 po.setnoneq(n1, n2)
1016 return true
1017 }
1018
1019
1020 if po.isnoneq(i1, i2) {
1021 return true
1022 }
1023
1024
1025 if po.Equal(n1, n2) {
1026 return false
1027 }
1028
1029
1030 po.setnoneq(n1, n2)
1031
1032
1033
1034
1035
1036 if po.reaches(i1, i2, false) && !po.reaches(i1, i2, true) {
1037 po.addchild(i1, i2, true)
1038 }
1039 if po.reaches(i2, i1, false) && !po.reaches(i2, i1, true) {
1040 po.addchild(i2, i1, true)
1041 }
1042
1043 return true
1044 }
1045
1046
1047
1048
1049 func (po *poset) Checkpoint() {
1050 po.undo = append(po.undo, posetUndo{typ: undoCheckpoint})
1051 }
1052
1053
1054
1055
1056
1057 func (po *poset) Undo() {
1058 if len(po.undo) == 0 {
1059 panic("empty undo stack")
1060 }
1061 if debugPoset {
1062 defer po.CheckIntegrity()
1063 }
1064
1065 for len(po.undo) > 0 {
1066 pass := po.undo[len(po.undo)-1]
1067 po.undo = po.undo[:len(po.undo)-1]
1068
1069 switch pass.typ {
1070 case undoCheckpoint:
1071 return
1072
1073 case undoSetChl:
1074 po.setchl(pass.idx, pass.edge)
1075
1076 case undoSetChr:
1077 po.setchr(pass.idx, pass.edge)
1078
1079 case undoNonEqual:
1080 po.noneq[uint32(pass.ID)].Clear(pass.idx)
1081
1082 case undoNewNode:
1083 if pass.idx != po.lastidx {
1084 panic("invalid newnode index")
1085 }
1086 if pass.ID != 0 {
1087 if po.values[pass.ID] != pass.idx {
1088 panic("invalid newnode undo pass")
1089 }
1090 delete(po.values, pass.ID)
1091 }
1092 po.setchl(pass.idx, 0)
1093 po.setchr(pass.idx, 0)
1094 po.nodes = po.nodes[:pass.idx]
1095 po.lastidx--
1096
1097 case undoAliasNode:
1098 ID, prev := pass.ID, pass.idx
1099 cur := po.values[ID]
1100 if prev == 0 {
1101
1102 delete(po.values, ID)
1103 } else {
1104 if cur == prev {
1105 panic("invalid aliasnode undo pass")
1106 }
1107
1108 po.values[ID] = prev
1109 }
1110
1111 case undoNewRoot:
1112 i := pass.idx
1113 l, r := po.children(i)
1114 if l|r != 0 {
1115 panic("non-empty root in undo newroot")
1116 }
1117 po.removeroot(i)
1118
1119 case undoChangeRoot:
1120 i := pass.idx
1121 l, r := po.children(i)
1122 if l|r != 0 {
1123 panic("non-empty root in undo changeroot")
1124 }
1125 po.changeroot(i, pass.edge.Target())
1126
1127 case undoMergeRoot:
1128 i := pass.idx
1129 l, r := po.children(i)
1130 po.changeroot(i, l.Target())
1131 po.roots = append(po.roots, r.Target())
1132
1133 default:
1134 panic(pass.typ)
1135 }
1136 }
1137
1138 if debugPoset && po.CheckEmpty() != nil {
1139 panic("poset not empty at the end of undo")
1140 }
1141 }
1142
View as plain text