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 }