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