|  | // Copyright 2014 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package pprof | 
|  |  | 
|  | // A protobuf is a simple protocol buffer encoder. | 
|  | type protobuf struct { | 
|  | data []byte | 
|  | tmp  [16]byte | 
|  | nest int | 
|  | } | 
|  |  | 
|  | func (b *protobuf) varint(x uint64) { | 
|  | for x >= 128 { | 
|  | b.data = append(b.data, byte(x)|0x80) | 
|  | x >>= 7 | 
|  | } | 
|  | b.data = append(b.data, byte(x)) | 
|  | } | 
|  |  | 
|  | func (b *protobuf) length(tag int, len int) { | 
|  | b.varint(uint64(tag)<<3 | 2) | 
|  | b.varint(uint64(len)) | 
|  | } | 
|  |  | 
|  | func (b *protobuf) uint64(tag int, x uint64) { | 
|  | // append varint to b.data | 
|  | b.varint(uint64(tag)<<3 | 0) | 
|  | b.varint(x) | 
|  | } | 
|  |  | 
|  | func (b *protobuf) uint64s(tag int, x []uint64) { | 
|  | if len(x) > 2 { | 
|  | // Use packed encoding | 
|  | n1 := len(b.data) | 
|  | for _, u := range x { | 
|  | b.varint(u) | 
|  | } | 
|  | n2 := len(b.data) | 
|  | b.length(tag, n2-n1) | 
|  | n3 := len(b.data) | 
|  | copy(b.tmp[:], b.data[n2:n3]) | 
|  | copy(b.data[n1+(n3-n2):], b.data[n1:n2]) | 
|  | copy(b.data[n1:], b.tmp[:n3-n2]) | 
|  | return | 
|  | } | 
|  | for _, u := range x { | 
|  | b.uint64(tag, u) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (b *protobuf) uint64Opt(tag int, x uint64) { | 
|  | if x == 0 { | 
|  | return | 
|  | } | 
|  | b.uint64(tag, x) | 
|  | } | 
|  |  | 
|  | func (b *protobuf) int64(tag int, x int64) { | 
|  | u := uint64(x) | 
|  | b.uint64(tag, u) | 
|  | } | 
|  |  | 
|  | func (b *protobuf) int64Opt(tag int, x int64) { | 
|  | if x == 0 { | 
|  | return | 
|  | } | 
|  | b.int64(tag, x) | 
|  | } | 
|  |  | 
|  | func (b *protobuf) int64s(tag int, x []int64) { | 
|  | if len(x) > 2 { | 
|  | // Use packed encoding | 
|  | n1 := len(b.data) | 
|  | for _, u := range x { | 
|  | b.varint(uint64(u)) | 
|  | } | 
|  | n2 := len(b.data) | 
|  | b.length(tag, n2-n1) | 
|  | n3 := len(b.data) | 
|  | copy(b.tmp[:], b.data[n2:n3]) | 
|  | copy(b.data[n1+(n3-n2):], b.data[n1:n2]) | 
|  | copy(b.data[n1:], b.tmp[:n3-n2]) | 
|  | return | 
|  | } | 
|  | for _, u := range x { | 
|  | b.int64(tag, u) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (b *protobuf) string(tag int, x string) { | 
|  | b.length(tag, len(x)) | 
|  | b.data = append(b.data, x...) | 
|  | } | 
|  |  | 
|  | func (b *protobuf) strings(tag int, x []string) { | 
|  | for _, s := range x { | 
|  | b.string(tag, s) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (b *protobuf) stringOpt(tag int, x string) { | 
|  | if x == "" { | 
|  | return | 
|  | } | 
|  | b.string(tag, x) | 
|  | } | 
|  |  | 
|  | func (b *protobuf) bool(tag int, x bool) { | 
|  | if x { | 
|  | b.uint64(tag, 1) | 
|  | } else { | 
|  | b.uint64(tag, 0) | 
|  | } | 
|  | } | 
|  |  | 
|  | func (b *protobuf) boolOpt(tag int, x bool) { | 
|  | if x == false { | 
|  | return | 
|  | } | 
|  | b.bool(tag, x) | 
|  | } | 
|  |  | 
|  | type msgOffset int | 
|  |  | 
|  | func (b *protobuf) startMessage() msgOffset { | 
|  | b.nest++ | 
|  | return msgOffset(len(b.data)) | 
|  | } | 
|  |  | 
|  | func (b *protobuf) endMessage(tag int, start msgOffset) { | 
|  | n1 := int(start) | 
|  | n2 := len(b.data) | 
|  | b.length(tag, n2-n1) | 
|  | n3 := len(b.data) | 
|  | copy(b.tmp[:], b.data[n2:n3]) | 
|  | copy(b.data[n1+(n3-n2):], b.data[n1:n2]) | 
|  | copy(b.data[n1:], b.tmp[:n3-n2]) | 
|  | b.nest-- | 
|  | } |