summaryrefslogtreecommitdiffstats
path: root/src/internal/coverage/slicereader/slicereader.go
blob: 3d117bae374ebab43780ae97d1da3edceee5b520 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Copyright 2021 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 slicereader

import (
	"encoding/binary"
	"unsafe"
)

// This file contains the helper "SliceReader", a utility for
// reading values from a byte slice that may or may not be backed
// by a read-only mmap'd region.

type Reader struct {
	b        []byte
	readonly bool
	off      int64
}

func NewReader(b []byte, readonly bool) *Reader {
	r := Reader{
		b:        b,
		readonly: readonly,
	}
	return &r
}

func (r *Reader) Read(b []byte) (int, error) {
	amt := len(b)
	toread := r.b[r.off:]
	if len(toread) < amt {
		amt = len(toread)
	}
	copy(b, toread)
	r.off += int64(amt)
	return amt, nil
}

func (r *Reader) SeekTo(off int64) {
	r.off = off
}

func (r *Reader) Offset() int64 {
	return r.off
}

func (r *Reader) ReadUint8() uint8 {
	rv := uint8(r.b[int(r.off)])
	r.off += 1
	return rv
}

func (r *Reader) ReadUint32() uint32 {
	end := int(r.off) + 4
	rv := binary.LittleEndian.Uint32(r.b[int(r.off):end:end])
	r.off += 4
	return rv
}

func (r *Reader) ReadUint64() uint64 {
	end := int(r.off) + 8
	rv := binary.LittleEndian.Uint64(r.b[int(r.off):end:end])
	r.off += 8
	return rv
}

func (r *Reader) ReadULEB128() (value uint64) {
	var shift uint

	for {
		b := r.b[r.off]
		r.off++
		value |= (uint64(b&0x7F) << shift)
		if b&0x80 == 0 {
			break
		}
		shift += 7
	}
	return
}

func (r *Reader) ReadString(len int64) string {
	b := r.b[r.off : r.off+len]
	r.off += len
	if r.readonly {
		return toString(b) // backed by RO memory, ok to make unsafe string
	}
	return string(b)
}

func toString(b []byte) string {
	if len(b) == 0 {
		return ""
	}
	return unsafe.String(&b[0], len(b))
}