1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package pprof
6
7// A protobuf is a simple protocol buffer encoder.
8type protobuf struct {
9	data []byte
10	tmp  [16]byte
11	nest int
12}
13
14func (b *protobuf) varint(x uint64) {
15	for x >= 128 {
16		b.data = append(b.data, byte(x)|0x80)
17		x >>= 7
18	}
19	b.data = append(b.data, byte(x))
20}
21
22func (b *protobuf) length(tag int, len int) {
23	b.varint(uint64(tag)<<3 | 2)
24	b.varint(uint64(len))
25}
26
27func (b *protobuf) uint64(tag int, x uint64) {
28	// append varint to b.data
29	b.varint(uint64(tag)<<3 | 0)
30	b.varint(x)
31}
32
33func (b *protobuf) uint64s(tag int, x []uint64) {
34	if len(x) > 2 {
35		// Use packed encoding
36		n1 := len(b.data)
37		for _, u := range x {
38			b.varint(u)
39		}
40		n2 := len(b.data)
41		b.length(tag, n2-n1)
42		n3 := len(b.data)
43		copy(b.tmp[:], b.data[n2:n3])
44		copy(b.data[n1+(n3-n2):], b.data[n1:n2])
45		copy(b.data[n1:], b.tmp[:n3-n2])
46		return
47	}
48	for _, u := range x {
49		b.uint64(tag, u)
50	}
51}
52
53func (b *protobuf) uint64Opt(tag int, x uint64) {
54	if x == 0 {
55		return
56	}
57	b.uint64(tag, x)
58}
59
60func (b *protobuf) int64(tag int, x int64) {
61	u := uint64(x)
62	b.uint64(tag, u)
63}
64
65func (b *protobuf) int64Opt(tag int, x int64) {
66	if x == 0 {
67		return
68	}
69	b.int64(tag, x)
70}
71
72func (b *protobuf) int64s(tag int, x []int64) {
73	if len(x) > 2 {
74		// Use packed encoding
75		n1 := len(b.data)
76		for _, u := range x {
77			b.varint(uint64(u))
78		}
79		n2 := len(b.data)
80		b.length(tag, n2-n1)
81		n3 := len(b.data)
82		copy(b.tmp[:], b.data[n2:n3])
83		copy(b.data[n1+(n3-n2):], b.data[n1:n2])
84		copy(b.data[n1:], b.tmp[:n3-n2])
85		return
86	}
87	for _, u := range x {
88		b.int64(tag, u)
89	}
90}
91
92func (b *protobuf) string(tag int, x string) {
93	b.length(tag, len(x))
94	b.data = append(b.data, x...)
95}
96
97func (b *protobuf) strings(tag int, x []string) {
98	for _, s := range x {
99		b.string(tag, s)
100	}
101}
102
103func (b *protobuf) stringOpt(tag int, x string) {
104	if x == "" {
105		return
106	}
107	b.string(tag, x)
108}
109
110func (b *protobuf) bool(tag int, x bool) {
111	if x {
112		b.uint64(tag, 1)
113	} else {
114		b.uint64(tag, 0)
115	}
116}
117
118func (b *protobuf) boolOpt(tag int, x bool) {
119	if !x {
120		return
121	}
122	b.bool(tag, x)
123}
124
125type msgOffset int
126
127func (b *protobuf) startMessage() msgOffset {
128	b.nest++
129	return msgOffset(len(b.data))
130}
131
132func (b *protobuf) endMessage(tag int, start msgOffset) {
133	n1 := int(start)
134	n2 := len(b.data)
135	b.length(tag, n2-n1)
136	n3 := len(b.data)
137	copy(b.tmp[:], b.data[n2:n3])
138	copy(b.data[n1+(n3-n2):], b.data[n1:n2])
139	copy(b.data[n1:], b.tmp[:n3-n2])
140	b.nest--
141}
142