mirror of
https://github.com/metabarcoding/obitools4.git
synced 2025-06-29 16:20:46 +00:00
239 lines
4.9 KiB
Go
239 lines
4.9 KiB
Go
package obifp
|
|
|
|
import (
|
|
"math"
|
|
"math/bits"
|
|
|
|
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obilog"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type Uint64 struct {
|
|
w0 uint64
|
|
}
|
|
|
|
// Zero returns a zero value of type Uint64.
|
|
//
|
|
// No parameters.
|
|
// Returns a Uint64 value of 0.
|
|
func (u Uint64) Zero() Uint64 {
|
|
return Uint64{0}
|
|
}
|
|
|
|
// MaxValue returns the maximum possible value of type Uint64.
|
|
//
|
|
// No parameters.
|
|
// Returns the maximum value of type Uint64.
|
|
func (u Uint64) MaxValue() Uint64 {
|
|
return Uint64{math.MaxUint64}
|
|
}
|
|
|
|
// IsZero checks if the Uint64 value is zero.
|
|
//
|
|
// No parameters.
|
|
// Returns a boolean indicating if the value is zero.
|
|
func (u Uint64) IsZero() bool {
|
|
return u.w0 == 0
|
|
}
|
|
|
|
// Cast a Uint64 to a Uint64.
|
|
//
|
|
// Which is a no-op.
|
|
//
|
|
// No parameters.
|
|
// Returns the Uint64 value itself.
|
|
func (u Uint64) Uint64() Uint64 {
|
|
return u
|
|
}
|
|
|
|
// Cast a Uint64 to a Uint128.
|
|
//
|
|
// No parameters.
|
|
// Returns a Uint128 value with the high field set to 0 and the low field set to the value of the Uint64.
|
|
func (u Uint64) Uint128() Uint128 {
|
|
return Uint128{w1: 0, w0: u.w0}
|
|
}
|
|
|
|
// Cast a Uint64 to a Uint256.
|
|
//
|
|
// No parameters.
|
|
// Returns a Uint256 value with the high fields set to 0 and the low fields set to the value of the Uint64.
|
|
func (u Uint64) Uint256() Uint256 {
|
|
return Uint256{w3: 0, w2: 0, w1: 0, w0: u.w0}
|
|
}
|
|
|
|
func (u Uint64) Set64(v uint64) Uint64 {
|
|
|
|
return Uint64{
|
|
w0: v,
|
|
}
|
|
}
|
|
|
|
// LeftShift64 performs a left shift operation on the Uint64 value by n bits, with carry-in from carryIn.
|
|
//
|
|
// The carry-in value is used as the first bit of the shifted value.
|
|
//
|
|
// The function returns u << n | (carryIn & ((1 << n) - 1)).
|
|
//
|
|
// This is a shift left operation, lowest bits are set with the lowest bits of
|
|
// the carry-in value instead of 0 as they would be in classical a left shift operation.
|
|
//
|
|
// Parameters:
|
|
// - n: the number of bits to shift by.
|
|
// - carryIn: the carry-in value.
|
|
//
|
|
// Returns:
|
|
// - value: the result of the left shift operation.
|
|
// - carry: the carry-out value.
|
|
func (u Uint64) LeftShift64(n uint, carryIn uint64) (value, carry uint64) {
|
|
switch {
|
|
case n == 0:
|
|
return u.w0, 0
|
|
|
|
case n < 64:
|
|
return u.w0<<n | (carryIn & ((1 << n) - 1)), u.w0 >> (64 - n)
|
|
|
|
case n == 64:
|
|
return carryIn, u.w0
|
|
|
|
case n < 128:
|
|
return carryIn, u.w0 << (n - 64)
|
|
|
|
}
|
|
|
|
obilog.Warnf("Uint64 overflow at LeftShift64(%v, %v)", u, n)
|
|
return 0, 0
|
|
}
|
|
|
|
// RightShift64 performs a right shift operation on the Uint64 value by n bits, with carry-out to carry.
|
|
//
|
|
// The function returns the result of the right shift operation and the carry-out value.
|
|
//
|
|
// Parameters:
|
|
// - n: the number of bits to shift by.
|
|
//
|
|
// Returns:
|
|
// - value: the result of the right shift operation.
|
|
// - carry: the carry-out value.
|
|
func (u Uint64) RightShift64(n uint, carryIn uint64) (value, carry uint64) {
|
|
switch {
|
|
case n == 0:
|
|
return u.w0, 0
|
|
|
|
case n < 64:
|
|
return u.w0>>n | (carryIn & ^((1 << (64 - n)) - 1)), u.w0 << (64 - n)
|
|
|
|
case n == 64:
|
|
return carryIn, u.w0
|
|
|
|
case n < 128:
|
|
return carryIn, u.w0 >> (n - 64)
|
|
}
|
|
|
|
obilog.Warnf("Uint64 overflow at RightShift64(%v, %v)", u, n)
|
|
return 0, 0
|
|
}
|
|
|
|
func (u Uint64) Add64(v Uint64, carryIn uint64) (value, carry uint64) {
|
|
return bits.Add64(u.w0, v.w0, uint64(carryIn))
|
|
}
|
|
|
|
func (u Uint64) Sub64(v Uint64, carryIn uint64) (value, carry uint64) {
|
|
return bits.Sub64(u.w0, v.w0, uint64(carryIn))
|
|
}
|
|
|
|
func (u Uint64) Mul64(v Uint64) (value, carry uint64) {
|
|
return bits.Mul64(u.w0, v.w0)
|
|
}
|
|
|
|
func (u Uint64) LeftShift(n uint) Uint64 {
|
|
sl, _ := u.LeftShift64(n, 0)
|
|
return Uint64{w0: sl}
|
|
}
|
|
|
|
func (u Uint64) RightShift(n uint) Uint64 {
|
|
sr, _ := u.RightShift64(n, 0)
|
|
return Uint64{w0: sr}
|
|
}
|
|
|
|
func (u Uint64) Add(v Uint64) Uint64 {
|
|
value, carry := u.Add64(v, 0)
|
|
|
|
if carry != 0 {
|
|
log.Panicf("Uint64 overflow at Add(%v, %v)", u, v)
|
|
}
|
|
|
|
return Uint64{w0: value}
|
|
}
|
|
|
|
func (u Uint64) Sub(v Uint64) Uint64 {
|
|
value, carry := u.Sub64(v, 0)
|
|
|
|
if carry != 0 {
|
|
log.Panicf("Uint64 overflow at Sub(%v, %v)", u, v)
|
|
}
|
|
|
|
return Uint64{w0: value}
|
|
}
|
|
|
|
func (u Uint64) Mul(v Uint64) Uint64 {
|
|
value, carry := u.Mul64(v)
|
|
|
|
if carry != 0 {
|
|
log.Panicf("Uint64 overflow at Mul(%v, %v)", u, v)
|
|
}
|
|
|
|
return Uint64{w0: value}
|
|
}
|
|
|
|
func (u Uint64) Cmp(v Uint64) int {
|
|
switch {
|
|
case u.w0 < v.w0:
|
|
return -1
|
|
case u.w0 > v.w0:
|
|
return 1
|
|
default:
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func (u Uint64) Equals(v Uint64) bool {
|
|
return u.Cmp(v) == 0
|
|
}
|
|
|
|
func (u Uint64) LessThan(v Uint64) bool {
|
|
return u.Cmp(v) < 0
|
|
}
|
|
|
|
func (u Uint64) GreaterThan(v Uint64) bool {
|
|
return u.Cmp(v) > 0
|
|
}
|
|
|
|
func (u Uint64) LessThanOrEqual(v Uint64) bool {
|
|
return !u.GreaterThan(v)
|
|
}
|
|
|
|
func (u Uint64) GreaterThanOrEqual(v Uint64) bool {
|
|
return !u.LessThan(v)
|
|
}
|
|
|
|
func (u Uint64) And(v Uint64) Uint64 {
|
|
return Uint64{w0: u.w0 & v.w0}
|
|
}
|
|
|
|
func (u Uint64) Or(v Uint64) Uint64 {
|
|
return Uint64{w0: u.w0 | v.w0}
|
|
}
|
|
|
|
func (u Uint64) Xor(v Uint64) Uint64 {
|
|
return Uint64{w0: u.w0 ^ v.w0}
|
|
}
|
|
|
|
func (u Uint64) Not() Uint64 {
|
|
return Uint64{w0: ^u.w0}
|
|
}
|
|
|
|
func (u Uint64) AsUint64() uint64 {
|
|
return u.w0
|
|
}
|