// Copyright 2014 The Cockroach Authors. // // 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. // This code originated from: // https://github.com/cockroachdb/cockroach/blob/2dd65dde5d90c157f4b93f92502ca1063b904e1d/pkg/util/encoding/encoding.go // Modified to not use pkg/errors package segment import "fmt" const ( MaxVarintSize = 9 // IntMin is chosen such that the range of int tags does not overlap the // ascii character set that is frequently used in testing. IntMin = 0x80 // 128 intMaxWidth = 8 intZero = IntMin + intMaxWidth // 136 intSmall = IntMax - intZero - intMaxWidth // 109 // IntMax is the maximum int tag value. IntMax = 0xfd // 253 ) // EncodeUvarintAscending encodes the uint64 value using a variable length // (length-prefixed) representation. The length is encoded as a single // byte indicating the number of encoded bytes (-8) to follow. See // EncodeVarintAscending for rationale. The encoded bytes are appended to the // supplied buffer and the final buffer is returned. func EncodeUvarintAscending(b []byte, v uint64) []byte { switch { case v <= intSmall: return append(b, intZero+byte(v)) case v <= 0xff: return append(b, IntMax-7, byte(v)) case v <= 0xffff: return append(b, IntMax-6, byte(v>>8), byte(v)) case v <= 0xffffff: return append(b, IntMax-5, byte(v>>16), byte(v>>8), byte(v)) case v <= 0xffffffff: return append(b, IntMax-4, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) case v <= 0xffffffffff: return append(b, IntMax-3, byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) case v <= 0xffffffffffff: return append(b, IntMax-2, byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) case v <= 0xffffffffffffff: return append(b, IntMax-1, byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) default: return append(b, IntMax, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) } } // DecodeUvarintAscending decodes a varint encoded uint64 from the input // buffer. The remainder of the input buffer and the decoded uint64 // are returned. func DecodeUvarintAscending(b []byte) ([]byte, uint64, error) { if len(b) == 0 { return nil, 0, fmt.Errorf("insufficient bytes to decode uvarint value") } length := int(b[0]) - intZero b = b[1:] // skip length byte if length <= intSmall { return b, uint64(length), nil } length -= intSmall if length < 0 || length > 8 { return nil, 0, fmt.Errorf("invalid uvarint length of %d", length) } else if len(b) < length { return nil, 0, fmt.Errorf("insufficient bytes to decode uvarint value: %q", b) } var v uint64 // It is faster to range over the elements in a slice than to index // into the slice on each loop iteration. for _, t := range b[:length] { v = (v << 8) | uint64(t) } return b[length:], v, nil }