github.com/grafana/pyroscope-go/godeltaprof@v0.1.8-0.20240513050943-1b1f97373e2a/internal/pprof/protobuf.go (about) 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 5 package pprof 6 7 // A protobuf is a simple protocol buffer encoder. 8 type protobuf struct { 9 data []byte 10 tmp [16]byte 11 nest int 12 } 13 14 func (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 22 func (b *protobuf) length(tag int, len int) { 23 b.varint(uint64(tag)<<3 | 2) 24 b.varint(uint64(len)) 25 } 26 27 func (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 33 func (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 53 func (b *protobuf) uint64Opt(tag int, x uint64) { 54 if x == 0 { 55 return 56 } 57 b.uint64(tag, x) 58 } 59 60 func (b *protobuf) int64(tag int, x int64) { 61 u := uint64(x) 62 b.uint64(tag, u) 63 } 64 65 func (b *protobuf) int64Opt(tag int, x int64) { 66 if x == 0 { 67 return 68 } 69 b.int64(tag, x) 70 } 71 72 func (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 92 func (b *protobuf) string(tag int, x string) { 93 b.length(tag, len(x)) 94 b.data = append(b.data, x...) 95 } 96 97 func (b *protobuf) strings(tag int, x []string) { 98 for _, s := range x { 99 b.string(tag, s) 100 } 101 } 102 103 func (b *protobuf) stringOpt(tag int, x string) { 104 if x == "" { 105 return 106 } 107 b.string(tag, x) 108 } 109 110 func (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 118 func (b *protobuf) boolOpt(tag int, x bool) { 119 if x == false { 120 return 121 } 122 b.bool(tag, x) 123 } 124 125 type msgOffset int 126 127 func (b *protobuf) startMessage() msgOffset { 128 b.nest++ 129 return msgOffset(len(b.data)) 130 } 131 132 func (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 }