mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 11:35:03 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			112 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			112 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| //  Copyright (c) 2014 Couchbase, Inc.
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| // 		http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| package numeric
 | |
| 
 | |
| import "fmt"
 | |
| 
 | |
| const ShiftStartInt64 byte = 0x20
 | |
| 
 | |
| // PrefixCoded is a byte array encoding of
 | |
| // 64-bit numeric values shifted by 0-63 bits
 | |
| type PrefixCoded []byte
 | |
| 
 | |
| func NewPrefixCodedInt64(in int64, shift uint) (PrefixCoded, error) {
 | |
| 	rv, _, err := NewPrefixCodedInt64Prealloc(in, shift, nil)
 | |
| 	return rv, err
 | |
| }
 | |
| 
 | |
| func NewPrefixCodedInt64Prealloc(in int64, shift uint, prealloc []byte) (
 | |
| 	rv PrefixCoded, preallocRest []byte, err error) {
 | |
| 	if shift > 63 {
 | |
| 		return nil, prealloc, fmt.Errorf("cannot shift %d, must be between 0 and 63", shift)
 | |
| 	}
 | |
| 
 | |
| 	nChars := ((63 - shift) / 7) + 1
 | |
| 
 | |
| 	size := int(nChars + 1)
 | |
| 	if len(prealloc) >= size {
 | |
| 		rv = PrefixCoded(prealloc[0:size])
 | |
| 		preallocRest = prealloc[size:]
 | |
| 	} else {
 | |
| 		rv = make(PrefixCoded, size)
 | |
| 	}
 | |
| 
 | |
| 	rv[0] = ShiftStartInt64 + byte(shift)
 | |
| 
 | |
| 	sortableBits := int64(uint64(in) ^ 0x8000000000000000)
 | |
| 	sortableBits = int64(uint64(sortableBits) >> shift)
 | |
| 	for nChars > 0 {
 | |
| 		// Store 7 bits per byte for compatibility
 | |
| 		// with UTF-8 encoding of terms
 | |
| 		rv[nChars] = byte(sortableBits & 0x7f)
 | |
| 		nChars--
 | |
| 		sortableBits = int64(uint64(sortableBits) >> 7)
 | |
| 	}
 | |
| 
 | |
| 	return rv, preallocRest, nil
 | |
| }
 | |
| 
 | |
| func MustNewPrefixCodedInt64(in int64, shift uint) PrefixCoded {
 | |
| 	rv, err := NewPrefixCodedInt64(in, shift)
 | |
| 	if err != nil {
 | |
| 		panic(err)
 | |
| 	}
 | |
| 	return rv
 | |
| }
 | |
| 
 | |
| // Shift returns the number of bits shifted
 | |
| // returns 0 if in uninitialized state
 | |
| func (p PrefixCoded) Shift() (uint, error) {
 | |
| 	if len(p) > 0 {
 | |
| 		shift := p[0] - ShiftStartInt64
 | |
| 		if shift < 0 || shift < 63 {
 | |
| 			return uint(shift), nil
 | |
| 		}
 | |
| 	}
 | |
| 	return 0, fmt.Errorf("invalid prefix coded value")
 | |
| }
 | |
| 
 | |
| func (p PrefixCoded) Int64() (int64, error) {
 | |
| 	shift, err := p.Shift()
 | |
| 	if err != nil {
 | |
| 		return 0, err
 | |
| 	}
 | |
| 	var sortableBits int64
 | |
| 	for _, inbyte := range p[1:] {
 | |
| 		sortableBits <<= 7
 | |
| 		sortableBits |= int64(inbyte)
 | |
| 	}
 | |
| 	return int64(uint64((sortableBits << shift)) ^ 0x8000000000000000), nil
 | |
| }
 | |
| 
 | |
| func ValidPrefixCodedTerm(p string) (bool, int) {
 | |
| 	return ValidPrefixCodedTermBytes([]byte(p))
 | |
| }
 | |
| 
 | |
| func ValidPrefixCodedTermBytes(p []byte) (bool, int) {
 | |
| 	if len(p) > 0 {
 | |
| 		if p[0] < ShiftStartInt64 || p[0] > ShiftStartInt64+63 {
 | |
| 			return false, 0
 | |
| 		}
 | |
| 		shift := p[0] - ShiftStartInt64
 | |
| 		nChars := ((63 - int(shift)) / 7) + 1
 | |
| 		if len(p) != nChars+1 {
 | |
| 			return false, 0
 | |
| 		}
 | |
| 		return true, int(shift)
 | |
| 	}
 | |
| 	return false, 0
 | |
| }
 |