1// Copyright 2014 The Cockroach Authors. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12// implied. See the License for the specific language governing 13// permissions and limitations under the License. 14 15// This code originated from: 16// https://github.com/cockroachdb/cockroach/blob/2dd65dde5d90c157f4b93f92502ca1063b904e1d/pkg/util/encoding/encoding.go 17 18// Modified to not use pkg/errors 19 20package scorch 21 22import "fmt" 23 24const ( 25 // intMin is chosen such that the range of int tags does not overlap the 26 // ascii character set that is frequently used in testing. 27 intMin = 0x80 // 128 28 intMaxWidth = 8 29 intZero = intMin + intMaxWidth // 136 30 intSmall = intMax - intZero - intMaxWidth // 109 31 // intMax is the maximum int tag value. 32 intMax = 0xfd // 253 33) 34 35// encodeUvarintAscending encodes the uint64 value using a variable length 36// (length-prefixed) representation. The length is encoded as a single 37// byte indicating the number of encoded bytes (-8) to follow. See 38// EncodeVarintAscending for rationale. The encoded bytes are appended to the 39// supplied buffer and the final buffer is returned. 40func encodeUvarintAscending(b []byte, v uint64) []byte { 41 switch { 42 case v <= intSmall: 43 return append(b, intZero+byte(v)) 44 case v <= 0xff: 45 return append(b, intMax-7, byte(v)) 46 case v <= 0xffff: 47 return append(b, intMax-6, byte(v>>8), byte(v)) 48 case v <= 0xffffff: 49 return append(b, intMax-5, byte(v>>16), byte(v>>8), byte(v)) 50 case v <= 0xffffffff: 51 return append(b, intMax-4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 52 case v <= 0xffffffffff: 53 return append(b, intMax-3, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), 54 byte(v)) 55 case v <= 0xffffffffffff: 56 return append(b, intMax-2, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), 57 byte(v>>8), byte(v)) 58 case v <= 0xffffffffffffff: 59 return append(b, intMax-1, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), 60 byte(v>>16), byte(v>>8), byte(v)) 61 default: 62 return append(b, intMax, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), 63 byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) 64 } 65} 66 67// decodeUvarintAscending decodes a varint encoded uint64 from the input 68// buffer. The remainder of the input buffer and the decoded uint64 69// are returned. 70func decodeUvarintAscending(b []byte) ([]byte, uint64, error) { 71 if len(b) == 0 { 72 return nil, 0, fmt.Errorf("insufficient bytes to decode uvarint value") 73 } 74 length := int(b[0]) - intZero 75 b = b[1:] // skip length byte 76 if length <= intSmall { 77 return b, uint64(length), nil 78 } 79 length -= intSmall 80 if length < 0 || length > 8 { 81 return nil, 0, fmt.Errorf("invalid uvarint length of %d", length) 82 } else if len(b) < length { 83 return nil, 0, fmt.Errorf("insufficient bytes to decode uvarint value: %q", b) 84 } 85 var v uint64 86 // It is faster to range over the elements in a slice than to index 87 // into the slice on each loop iteration. 88 for _, t := range b[:length] { 89 v = (v << 8) | uint64(t) 90 } 91 return b[length:], v, nil 92} 93