1// Copyright 2018 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package tsdb
15
16import (
17	"encoding/binary"
18	"hash"
19	"hash/crc32"
20	"unsafe"
21
22	"github.com/pkg/errors"
23)
24
25var errInvalidSize = errors.New("invalid size")
26
27// encbuf is a helper type to populate a byte slice with various types.
28type encbuf struct {
29	b []byte
30	c [binary.MaxVarintLen64]byte
31}
32
33func (e *encbuf) reset()      { e.b = e.b[:0] }
34func (e *encbuf) get() []byte { return e.b }
35func (e *encbuf) len() int    { return len(e.b) }
36
37func (e *encbuf) putString(s string) { e.b = append(e.b, s...) }
38func (e *encbuf) putBytes(b []byte)  { e.b = append(e.b, b...) }
39func (e *encbuf) putByte(c byte)     { e.b = append(e.b, c) }
40
41func (e *encbuf) putBE32int(x int)      { e.putBE32(uint32(x)) }
42func (e *encbuf) putBE64int(x int)      { e.putBE64(uint64(x)) }
43func (e *encbuf) putBE64int64(x int64)  { e.putBE64(uint64(x)) }
44func (e *encbuf) putUvarint32(x uint32) { e.putUvarint64(uint64(x)) }
45func (e *encbuf) putUvarint(x int)      { e.putUvarint64(uint64(x)) }
46
47func (e *encbuf) putBE32(x uint32) {
48	binary.BigEndian.PutUint32(e.c[:], x)
49	e.b = append(e.b, e.c[:4]...)
50}
51
52func (e *encbuf) putBE64(x uint64) {
53	binary.BigEndian.PutUint64(e.c[:], x)
54	e.b = append(e.b, e.c[:8]...)
55}
56
57func (e *encbuf) putUvarint64(x uint64) {
58	n := binary.PutUvarint(e.c[:], x)
59	e.b = append(e.b, e.c[:n]...)
60}
61
62func (e *encbuf) putVarint64(x int64) {
63	n := binary.PutVarint(e.c[:], x)
64	e.b = append(e.b, e.c[:n]...)
65}
66
67// putVarintStr writes a string to the buffer prefixed by its varint length (in bytes!).
68func (e *encbuf) putUvarintStr(s string) {
69	b := *(*[]byte)(unsafe.Pointer(&s))
70	e.putUvarint(len(b))
71	e.putString(s)
72}
73
74// putHash appends a hash over the buffers current contents to the buffer.
75func (e *encbuf) putHash(h hash.Hash) {
76	h.Reset()
77	_, err := h.Write(e.b)
78	if err != nil {
79		panic(err) // The CRC32 implementation does not error
80	}
81	e.b = h.Sum(e.b)
82}
83
84// decbuf provides safe methods to extract data from a byte slice. It does all
85// necessary bounds checking and advancing of the byte slice.
86// Several datums can be extracted without checking for errors. However, before using
87// any datum, the err() method must be checked.
88type decbuf struct {
89	b []byte
90	e error
91}
92
93func (d *decbuf) uvarint() int      { return int(d.uvarint64()) }
94func (d *decbuf) uvarint32() uint32 { return uint32(d.uvarint64()) }
95func (d *decbuf) be32int() int      { return int(d.be32()) }
96func (d *decbuf) be64int64() int64  { return int64(d.be64()) }
97
98// crc32 returns a CRC32 checksum over the remaining bytes.
99func (d *decbuf) crc32() uint32 {
100	return crc32.Checksum(d.b, castagnoliTable)
101}
102
103func (d *decbuf) uvarintStr() string {
104	l := d.uvarint64()
105	if d.e != nil {
106		return ""
107	}
108	if len(d.b) < int(l) {
109		d.e = errInvalidSize
110		return ""
111	}
112	s := string(d.b[:l])
113	d.b = d.b[l:]
114	return s
115}
116
117func (d *decbuf) varint64() int64 {
118	if d.e != nil {
119		return 0
120	}
121	x, n := binary.Varint(d.b)
122	if n < 1 {
123		d.e = errInvalidSize
124		return 0
125	}
126	d.b = d.b[n:]
127	return x
128}
129
130func (d *decbuf) uvarint64() uint64 {
131	if d.e != nil {
132		return 0
133	}
134	x, n := binary.Uvarint(d.b)
135	if n < 1 {
136		d.e = errInvalidSize
137		return 0
138	}
139	d.b = d.b[n:]
140	return x
141}
142
143func (d *decbuf) be64() uint64 {
144	if d.e != nil {
145		return 0
146	}
147	if len(d.b) < 4 {
148		d.e = errInvalidSize
149		return 0
150	}
151	x := binary.BigEndian.Uint64(d.b)
152	d.b = d.b[8:]
153	return x
154}
155
156func (d *decbuf) be32() uint32 {
157	if d.e != nil {
158		return 0
159	}
160	if len(d.b) < 4 {
161		d.e = errInvalidSize
162		return 0
163	}
164	x := binary.BigEndian.Uint32(d.b)
165	d.b = d.b[4:]
166	return x
167}
168
169func (d *decbuf) byte() byte {
170	if d.e != nil {
171		return 0
172	}
173	if len(d.b) < 1 {
174		d.e = errInvalidSize
175		return 0
176	}
177	x := d.b[0]
178	d.b = d.b[1:]
179	return x
180}
181
182func (d *decbuf) decbuf(l int) decbuf {
183	if d.e != nil {
184		return decbuf{e: d.e}
185	}
186	if l > len(d.b) {
187		return decbuf{e: errInvalidSize}
188	}
189	r := decbuf{b: d.b[:l]}
190	d.b = d.b[l:]
191	return r
192}
193
194func (d *decbuf) err() error  { return d.e }
195func (d *decbuf) len() int    { return len(d.b) }
196func (d *decbuf) get() []byte { return d.b }
197