github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/int256/bitwise.gno (about)

     1  package int256
     2  
     3  import (
     4  	"gno.land/p/demo/uint256"
     5  )
     6  
     7  // Or sets z = x | y and returns z.
     8  func (z *Int) Or(x, y *Int) *Int {
     9  	if x.neg == y.neg {
    10  		if x.neg {
    11  			// (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
    12  			x1 := new(uint256.Uint).Sub(x.abs, one)
    13  			y1 := new(uint256.Uint).Sub(y.abs, one)
    14  			z.abs = z.abs.Add(z.abs.And(x1, y1), one)
    15  			z.neg = true // z cannot be zero if x and y are negative
    16  			return z
    17  		}
    18  
    19  		// x | y == x | y
    20  		z.abs = z.abs.Or(x.abs, y.abs)
    21  		z.neg = false
    22  		return z
    23  	}
    24  
    25  	// x.neg != y.neg
    26  	if x.neg {
    27  		x, y = y, x // | is symmetric
    28  	}
    29  
    30  	// x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
    31  	y1 := new(uint256.Uint).Sub(y.abs, one)
    32  	z.abs = z.abs.Add(z.abs.AndNot(y1, x.abs), one)
    33  	z.neg = true // z cannot be zero if one of x or y is negative
    34  
    35  	return z
    36  }
    37  
    38  // And sets z = x & y and returns z.
    39  func (z *Int) And(x, y *Int) *Int {
    40  	if x.neg == y.neg {
    41  		if x.neg {
    42  			// (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
    43  			x1 := new(uint256.Uint).Sub(x.abs, one)
    44  			y1 := new(uint256.Uint).Sub(y.abs, one)
    45  			z.abs = z.abs.Add(z.abs.Or(x1, y1), one)
    46  			z.neg = true // z cannot be zero if x and y are negative
    47  			return z
    48  		}
    49  
    50  		// x & y == x & y
    51  		z.abs = z.abs.And(x.abs, y.abs)
    52  		z.neg = false
    53  		return z
    54  	}
    55  
    56  	// x.neg != y.neg
    57  	// REF: https://cs.opensource.google/go/go/+/refs/tags/go1.22.1:src/math/big/int.go;l=1192-1202;drc=d57303e65f00b84b528ee682747dbe1fd3316d30
    58  	if x.neg {
    59  		x, y = y, x // & is symmetric
    60  	}
    61  
    62  	// x & (-y) == x & ^(y-1) == x &^ (y-1)
    63  	y1 := new(uint256.Uint).Sub(y.abs, uint256.One())
    64  	z.abs = z.abs.AndNot(x.abs, y1)
    65  	z.neg = false
    66  	return z
    67  }
    68  
    69  // Rsh sets z = x >> n and returns z.
    70  // OBS: Different from original implementation it was using math.Big
    71  func (z *Int) Rsh(x *Int, n uint) *Int {
    72  	if !x.neg {
    73  		z.abs.Rsh(x.abs, n)
    74  		z.neg = x.neg
    75  		return z
    76  	}
    77  
    78  	// REF: https://cs.opensource.google/go/go/+/refs/tags/go1.22.1:src/math/big/int.go;l=1118-1126;drc=d57303e65f00b84b528ee682747dbe1fd3316d30
    79  	t := NewInt(0).Sub(FromUint256(x.abs), NewInt(1))
    80  	t = t.Rsh(t, n)
    81  
    82  	_tmp := t.Add(t, NewInt(1))
    83  	z.abs = _tmp.Abs()
    84  	z.neg = true
    85  
    86  	return z
    87  }
    88  
    89  // Lsh sets z = x << n and returns z.
    90  func (z *Int) Lsh(x *Int, n uint) *Int {
    91  	z.abs.Lsh(x.abs, n)
    92  	z.neg = x.neg
    93  	return z
    94  }