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