github.com/andy2046/gopie@v0.7.0/pkg/dll/amr.go (about) 1 package dll 2 3 import ( 4 "sync/atomic" 5 "unsafe" 6 ) 7 8 type ( 9 atomicMarkableReference struct { 10 pair *pair 11 } 12 13 pair struct { 14 reference *Element 15 mark bool 16 } 17 ) 18 19 func newAtomicMarkableReference(initialRef *Element, initialMark bool) *atomicMarkableReference { 20 return &atomicMarkableReference{ 21 &pair{ 22 reference: initialRef, 23 mark: initialMark, 24 }, 25 } 26 } 27 28 func (amr *atomicMarkableReference) getPair() *pair { 29 return (*pair)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&amr.pair)))) 30 } 31 32 func (amr *atomicMarkableReference) getReference() *Element { 33 p := amr.getPair() 34 return p.reference 35 } 36 37 func (amr *atomicMarkableReference) isMarked() bool { 38 p := amr.getPair() 39 return p.mark 40 } 41 42 func (amr *atomicMarkableReference) get() (bool, *Element) { 43 p := amr.getPair() 44 return p.mark, p.reference 45 } 46 47 func (amr *atomicMarkableReference) compareAndSet(expectedReference *Element, 48 newReference *Element, 49 expectedMark bool, 50 newMark bool) bool { 51 current := amr.getPair() 52 val := &pair{newReference, newMark} 53 54 return expectedReference == current.reference && 55 expectedMark == current.mark && 56 ((newReference == current.reference && 57 newMark == current.mark) || 58 amr.casPair(current, val)) 59 } 60 61 func (amr *atomicMarkableReference) tryMark(expectedReference *Element, newMark bool) bool { 62 current := amr.getPair() 63 val := &pair{expectedReference, newMark} 64 return expectedReference == current.reference && 65 (newMark == current.mark || 66 amr.casPair(current, val)) 67 } 68 69 func (amr *atomicMarkableReference) casPair(cmp *pair, val *pair) bool { 70 return atomic.CompareAndSwapPointer( 71 (*unsafe.Pointer)(unsafe.Pointer(&amr.pair)), 72 unsafe.Pointer(cmp), 73 unsafe.Pointer(val)) 74 }