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  }