Source file src/internal/coverage/stringtab/stringtab.go

     1  // Copyright 2022 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 stringtab
     6  
     7  import (
     8  	"fmt"
     9  	"internal/coverage/slicereader"
    10  	"internal/coverage/uleb128"
    11  	"io"
    12  )
    13  
    14  // This package implements string table writer and reader utilities,
    15  // for use in emitting and reading/decoding coverage meta-data and
    16  // counter-data files.
    17  
    18  // Writer implements a string table writing utility.
    19  type Writer struct {
    20  	stab   map[string]uint32
    21  	strs   []string
    22  	tmp    []byte
    23  	frozen bool
    24  }
    25  
    26  // InitWriter initializes a stringtab.Writer.
    27  func (stw *Writer) InitWriter() {
    28  	stw.stab = make(map[string]uint32)
    29  	stw.tmp = make([]byte, 64)
    30  }
    31  
    32  // Nentries returns the number of strings interned so far.
    33  func (stw *Writer) Nentries() uint32 {
    34  	return uint32(len(stw.strs))
    35  }
    36  
    37  // Lookup looks up string 's' in the writer's table, adding
    38  // a new entry if need be, and returning an index into the table.
    39  func (stw *Writer) Lookup(s string) uint32 {
    40  	if idx, ok := stw.stab[s]; ok {
    41  		return idx
    42  	}
    43  	if stw.frozen {
    44  		panic("internal error: string table previously frozen")
    45  	}
    46  	idx := uint32(len(stw.strs))
    47  	stw.stab[s] = idx
    48  	stw.strs = append(stw.strs, s)
    49  	return idx
    50  }
    51  
    52  // Size computes the memory in bytes needed for the serialized
    53  // version of a stringtab.Writer.
    54  func (stw *Writer) Size() uint32 {
    55  	rval := uint32(0)
    56  	stw.tmp = stw.tmp[:0]
    57  	stw.tmp = uleb128.AppendUleb128(stw.tmp, uint(len(stw.strs)))
    58  	rval += uint32(len(stw.tmp))
    59  	for _, s := range stw.strs {
    60  		stw.tmp = stw.tmp[:0]
    61  		slen := uint(len(s))
    62  		stw.tmp = uleb128.AppendUleb128(stw.tmp, slen)
    63  		rval += uint32(len(stw.tmp)) + uint32(slen)
    64  	}
    65  	return rval
    66  }
    67  
    68  // Write writes the string table in serialized form to the specified
    69  // io.Writer.
    70  func (stw *Writer) Write(w io.Writer) error {
    71  	wr128 := func(v uint) error {
    72  		stw.tmp = stw.tmp[:0]
    73  		stw.tmp = uleb128.AppendUleb128(stw.tmp, v)
    74  		if nw, err := w.Write(stw.tmp); err != nil {
    75  			return fmt.Errorf("writing string table: %v", err)
    76  		} else if nw != len(stw.tmp) {
    77  			return fmt.Errorf("short write emitting stringtab uleb")
    78  		}
    79  		return nil
    80  	}
    81  	if err := wr128(uint(len(stw.strs))); err != nil {
    82  		return err
    83  	}
    84  	for _, s := range stw.strs {
    85  		if err := wr128(uint(len(s))); err != nil {
    86  			return err
    87  		}
    88  		if nw, err := w.Write([]byte(s)); err != nil {
    89  			return fmt.Errorf("writing string table: %v", err)
    90  		} else if nw != len([]byte(s)) {
    91  			return fmt.Errorf("short write emitting stringtab")
    92  		}
    93  	}
    94  	return nil
    95  }
    96  
    97  // Freeze sends a signal to the writer that no more additions are
    98  // allowed, only lookups of existing strings (if a lookup triggers
    99  // addition, a panic will result). Useful as a mechanism for
   100  // "finalizing" a string table prior to writing it out.
   101  func (stw *Writer) Freeze() {
   102  	stw.frozen = true
   103  }
   104  
   105  // Reader is a helper for reading a string table previously
   106  // serialized by a Writer.Write call.
   107  type Reader struct {
   108  	r    *slicereader.Reader
   109  	strs []string
   110  }
   111  
   112  // NewReader creates a stringtab.Reader to read the contents
   113  // of a string table from 'r'.
   114  func NewReader(r *slicereader.Reader) *Reader {
   115  	str := &Reader{
   116  		r: r,
   117  	}
   118  	return str
   119  }
   120  
   121  // Read reads/decodes a string table using the reader provided.
   122  func (str *Reader) Read() {
   123  	numEntries := int(str.r.ReadULEB128())
   124  	str.strs = make([]string, 0, numEntries)
   125  	for idx := 0; idx < numEntries; idx++ {
   126  		slen := str.r.ReadULEB128()
   127  		str.strs = append(str.strs, str.r.ReadString(int64(slen)))
   128  	}
   129  }
   130  
   131  // Entries returns the number of decoded entries in a string table.
   132  func (str *Reader) Entries() int {
   133  	return len(str.strs)
   134  }
   135  
   136  // Get returns string 'idx' within the string table.
   137  func (str *Reader) Get(idx uint32) string {
   138  	return str.strs[idx]
   139  }
   140  

View as plain text