github.com/sandwich-go/boost@v1.3.29/xhash/hash14v/converter.go (about)

     1  package hash14v
     2  
     3  import (
     4  	"bytes"
     5  	"github.com/sandwich-go/boost/xcrypto/algorithm/vigenere"
     6  	"github.com/sandwich-go/boost/z"
     7  	"math"
     8  )
     9  
    10  const (
    11  	base          = 26
    12  	maxLength     = 14
    13  	minHashOffset = "A"
    14  )
    15  
    16  type converter struct {
    17  	reservedBuff [16]byte
    18  	idOffset     uint64
    19  	hashOffset   []byte
    20  	hashKey      []byte
    21  	minLength    int
    22  	maxLength    int
    23  	spec         *Options
    24  }
    25  
    26  // New return new hash14v operator
    27  func New(opts ...Option) Converter {
    28  	spec := NewOptions(opts...)
    29  	oo := &converter{spec: spec}
    30  	oo.hashKey = vigenere.Sanitize(spec.GetHashKey())
    31  	oo.hashOffset = spec.GetHashOffset()
    32  	if len(oo.hashOffset) == 0 {
    33  		oo.hashOffset = z.StringToBytes(minHashOffset)
    34  	}
    35  	oo.minLength = len(oo.hashOffset)
    36  	oo.maxLength = maxLength
    37  	oo.idOffset = oo.decode(oo.hashOffset)
    38  	return oo
    39  }
    40  
    41  // ToV 对 Id 进行转换,转换为 V
    42  func (o *converter) ToV(id Id) V {
    43  	if math.MaxUint64-id < o.idOffset {
    44  		return nil
    45  	}
    46  	ret := o.encode(id + o.idOffset)
    47  	if o.hashKey != nil {
    48  		vigenere.EncryptAndInplace(ret, o.hashKey)
    49  	}
    50  	return ret
    51  }
    52  
    53  // ToId 对 Id 进行转换,转换为 V
    54  func (o *converter) ToId(v V) Id {
    55  	if len(v) < o.minLength || len(v) > o.maxLength {
    56  		return 0
    57  	}
    58  	if o.hashKey == nil {
    59  		return o.decode(v) - o.idOffset
    60  	}
    61  	return o.decode(vigenere.Decrypt(v, o.hashKey)) - o.idOffset
    62  }
    63  
    64  // Offset 获取 Id 的 offset
    65  func (o *converter) Offset() Id { return o.idOffset }
    66  
    67  func (o *converter) encode(num uint64) V {
    68  	if o.spec.GetUsingReservedBuff() {
    69  		var i int
    70  		for i = len(o.reservedBuff) - 1; num != 0; i-- {
    71  			o.reservedBuff[i] = 'A' + byte(num%base) - 1
    72  			num /= 26
    73  		}
    74  		return o.reservedBuff[i+1:]
    75  	} else {
    76  		var rb [16]byte
    77  		var i int
    78  		for i = len(rb) - 1; num != 0; i-- {
    79  			rb[i] = 'A' + byte(num%base) - 1
    80  			num /= 26
    81  		}
    82  		return rb[i+1:]
    83  	}
    84  }
    85  
    86  func (o *converter) decode(hi V) (ret uint64) {
    87  	hi = bytes.ToUpper(hi)
    88  	lenID := len(hi)
    89  	for index, c := range hi {
    90  		ret += uint64(math.Pow(base, float64(lenID-1-index))) * uint64(c-'A'+1)
    91  	}
    92  	return ret
    93  }