github.com/pyroscope-io/godeltaprof@v0.1.3-0.20230906152420-0d7eeca7b8c1/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  }