Home | History | Annotate | Download | only in pprof
      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 }
    142