github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/atomickit/uint.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package atomickit 7 8 import ( 9 "math/bits" 10 "strconv" 11 "sync/atomic" 12 "unsafe" 13 ) 14 15 func NewUint(v uint) Uint { 16 return Uint{v} 17 } 18 19 type Uint struct { 20 v uint 21 } 22 23 func (p *Uint) ptr32() *uint32 { 24 return (*uint32)(unsafe.Pointer(&p.v)) 25 } 26 27 func (p *Uint) ptr64() *uint64 { 28 return (*uint64)(unsafe.Pointer(&p.v)) 29 } 30 31 func (p *Uint) Load() uint { 32 if bits.UintSize == 32 { 33 return uint(atomic.LoadUint32(p.ptr32())) 34 } 35 return uint(atomic.LoadUint64(p.ptr64())) 36 } 37 38 func (p *Uint) Store(v uint) { 39 if bits.UintSize == 32 { 40 atomic.StoreUint32(p.ptr32(), uint32(v)) 41 return 42 } 43 atomic.StoreUint64(p.ptr64(), uint64(v)) 44 } 45 46 func (p *Uint) Swap(v uint) uint { 47 if bits.UintSize == 32 { 48 return uint(atomic.SwapUint32(p.ptr32(), uint32(v))) 49 } 50 return uint(atomic.SwapUint64(p.ptr64(), uint64(v))) 51 } 52 53 func (p *Uint) CompareAndSwap(old, new uint) bool { 54 if bits.UintSize == 32 { 55 return atomic.CompareAndSwapUint32(p.ptr32(), uint32(old), uint32(new)) 56 } 57 return atomic.CompareAndSwapUint64(p.ptr64(), uint64(old), uint64(new)) 58 } 59 60 func (p *Uint) Add(v uint) uint { 61 if bits.UintSize == 32 { 62 return uint(atomic.AddUint32(p.ptr32(), uint32(v))) 63 } 64 return uint(atomic.AddUint64(p.ptr64(), uint64(v))) 65 } 66 67 func (p *Uint) Sub(v uint) uint { 68 return p.Add(^(v - 1)) 69 } 70 71 func (p *Uint) String() string { 72 return strconv.FormatUint(uint64(p.Load()), 10) 73 } 74 75 func (p *Uint) SetBits(v uint) uint { 76 for { 77 switch x := p.Load(); { 78 case x & v == v: 79 return x 80 case p.CompareAndSwap(x, x|v): 81 return x|v 82 } 83 } 84 } 85 86 func (p *Uint) TrySetBits(v uint, all bool) bool { 87 for { 88 x := p.Load() 89 switch { 90 case x & v == 0: 91 case all: 92 return false 93 case x & v == v: 94 return false 95 } 96 if p.CompareAndSwap(x, x|v) { 97 return true 98 } 99 } 100 } 101 102 func (p *Uint) UnsetBits(v uint) uint { 103 for { 104 switch x := p.Load(); { 105 case x & v == 0: 106 return x 107 case p.CompareAndSwap(x, x&^v): 108 return x&^v 109 } 110 } 111 } 112 113 func (p *Uint) TryUnsetBits(v uint, all bool) bool { 114 for { 115 x := p.Load() 116 switch { 117 case x & v == 0: 118 return false 119 case x & v == v: 120 case all: 121 return false 122 } 123 if p.CompareAndSwap(x, x&^v) { 124 return true 125 } 126 } 127 } 128 129 func (p *Uint) CompareAndSub(v uint) bool { 130 for { 131 switch x := p.Load(); { 132 case x < v: 133 return false 134 case p.CompareAndSwap(x, x-v): 135 return true 136 } 137 } 138 } 139 140 func (p *Uint) SetLesser(v uint) uint { 141 for { 142 switch x := p.Load(); { 143 case x <= v: 144 return x 145 case p.CompareAndSwap(x, v): 146 return v 147 } 148 } 149 } 150 151 func (p *Uint) SetGreater(v uint) uint { 152 for { 153 switch x := p.Load(); { 154 case x >= v: 155 return x 156 case p.CompareAndSwap(x, v): 157 return v 158 } 159 } 160 } 161 162 func (p *Uint) CompareAndSetBits(maskOut, deny, v uint) bool { 163 for { 164 x := p.Load() 165 x2 := x &^ maskOut 166 switch { 167 case x2 & deny != 0: 168 return false 169 case x2 & v != 0: 170 return false 171 } 172 if p.CompareAndSwap(x, x|v) { 173 return true 174 } 175 } 176 }