File size: 3,734 Bytes
e36aeda | 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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | // Copyright 2022 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 stringtab
import (
"fmt"
"internal/coverage/slicereader"
"internal/coverage/uleb128"
"io"
)
// This package implements string table writer and reader utilities,
// for use in emitting and reading/decoding coverage meta-data and
// counter-data files.
// Writer implements a string table writing utility.
type Writer struct {
stab map[string]uint32
strs []string
tmp []byte
frozen bool
}
// InitWriter initializes a stringtab.Writer.
func (stw *Writer) InitWriter() {
stw.stab = make(map[string]uint32)
stw.tmp = make([]byte, 64)
}
// Nentries returns the number of strings interned so far.
func (stw *Writer) Nentries() uint32 {
return uint32(len(stw.strs))
}
// Lookup looks up string 's' in the writer's table, adding
// a new entry if need be, and returning an index into the table.
func (stw *Writer) Lookup(s string) uint32 {
if idx, ok := stw.stab[s]; ok {
return idx
}
if stw.frozen {
panic("internal error: string table previously frozen")
}
idx := uint32(len(stw.strs))
stw.stab[s] = idx
stw.strs = append(stw.strs, s)
return idx
}
// Size computes the memory in bytes needed for the serialized
// version of a stringtab.Writer.
func (stw *Writer) Size() uint32 {
rval := uint32(0)
stw.tmp = stw.tmp[:0]
stw.tmp = uleb128.AppendUleb128(stw.tmp, uint(len(stw.strs)))
rval += uint32(len(stw.tmp))
for _, s := range stw.strs {
stw.tmp = stw.tmp[:0]
slen := uint(len(s))
stw.tmp = uleb128.AppendUleb128(stw.tmp, slen)
rval += uint32(len(stw.tmp)) + uint32(slen)
}
return rval
}
// Write writes the string table in serialized form to the specified
// io.Writer.
func (stw *Writer) Write(w io.Writer) error {
wr128 := func(v uint) error {
stw.tmp = stw.tmp[:0]
stw.tmp = uleb128.AppendUleb128(stw.tmp, v)
if nw, err := w.Write(stw.tmp); err != nil {
return fmt.Errorf("writing string table: %v", err)
} else if nw != len(stw.tmp) {
return fmt.Errorf("short write emitting stringtab uleb")
}
return nil
}
if err := wr128(uint(len(stw.strs))); err != nil {
return err
}
for _, s := range stw.strs {
if err := wr128(uint(len(s))); err != nil {
return err
}
if nw, err := w.Write([]byte(s)); err != nil {
return fmt.Errorf("writing string table: %v", err)
} else if nw != len([]byte(s)) {
return fmt.Errorf("short write emitting stringtab")
}
}
return nil
}
// Freeze sends a signal to the writer that no more additions are
// allowed, only lookups of existing strings (if a lookup triggers
// addition, a panic will result). Useful as a mechanism for
// "finalizing" a string table prior to writing it out.
func (stw *Writer) Freeze() {
stw.frozen = true
}
// Reader is a helper for reading a string table previously
// serialized by a Writer.Write call.
type Reader struct {
r *slicereader.Reader
strs []string
}
// NewReader creates a stringtab.Reader to read the contents
// of a string table from 'r'.
func NewReader(r *slicereader.Reader) *Reader {
str := &Reader{
r: r,
}
return str
}
// Read reads/decodes a string table using the reader provided.
func (str *Reader) Read() {
numEntries := int(str.r.ReadULEB128())
str.strs = make([]string, 0, numEntries)
for idx := 0; idx < numEntries; idx++ {
slen := str.r.ReadULEB128()
str.strs = append(str.strs, str.r.ReadString(int64(slen)))
}
}
// Entries returns the number of decoded entries in a string table.
func (str *Reader) Entries() int {
return len(str.strs)
}
// Get returns string 'idx' within the string table.
func (str *Reader) Get(idx uint32) string {
return str.strs[idx]
}
|