Source file src/cmd/vendor/github.com/google/pprof/profile/encode.go

     1  // Copyright 2014 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package profile
    16  
    17  import (
    18  	"errors"
    19  	"sort"
    20  	"strings"
    21  )
    22  
    23  func (p *Profile) decoder() []decoder {
    24  	return profileDecoder
    25  }
    26  
    27  // preEncode populates the unexported fields to be used by encode
    28  // (with suffix X) from the corresponding exported fields. The
    29  // exported fields are cleared up to facilitate testing.
    30  func (p *Profile) preEncode() {
    31  	strings := make(map[string]int)
    32  	addString(strings, "")
    33  
    34  	for _, st := range p.SampleType {
    35  		st.typeX = addString(strings, st.Type)
    36  		st.unitX = addString(strings, st.Unit)
    37  	}
    38  
    39  	for _, s := range p.Sample {
    40  		s.labelX = nil
    41  		var keys []string
    42  		for k := range s.Label {
    43  			keys = append(keys, k)
    44  		}
    45  		sort.Strings(keys)
    46  		for _, k := range keys {
    47  			vs := s.Label[k]
    48  			for _, v := range vs {
    49  				s.labelX = append(s.labelX,
    50  					label{
    51  						keyX: addString(strings, k),
    52  						strX: addString(strings, v),
    53  					},
    54  				)
    55  			}
    56  		}
    57  		var numKeys []string
    58  		for k := range s.NumLabel {
    59  			numKeys = append(numKeys, k)
    60  		}
    61  		sort.Strings(numKeys)
    62  		for _, k := range numKeys {
    63  			keyX := addString(strings, k)
    64  			vs := s.NumLabel[k]
    65  			units := s.NumUnit[k]
    66  			for i, v := range vs {
    67  				var unitX int64
    68  				if len(units) != 0 {
    69  					unitX = addString(strings, units[i])
    70  				}
    71  				s.labelX = append(s.labelX,
    72  					label{
    73  						keyX:  keyX,
    74  						numX:  v,
    75  						unitX: unitX,
    76  					},
    77  				)
    78  			}
    79  		}
    80  		s.locationIDX = make([]uint64, len(s.Location))
    81  		for i, loc := range s.Location {
    82  			s.locationIDX[i] = loc.ID
    83  		}
    84  	}
    85  
    86  	for _, m := range p.Mapping {
    87  		m.fileX = addString(strings, m.File)
    88  		m.buildIDX = addString(strings, m.BuildID)
    89  	}
    90  
    91  	for _, l := range p.Location {
    92  		for i, ln := range l.Line {
    93  			if ln.Function != nil {
    94  				l.Line[i].functionIDX = ln.Function.ID
    95  			} else {
    96  				l.Line[i].functionIDX = 0
    97  			}
    98  		}
    99  		if l.Mapping != nil {
   100  			l.mappingIDX = l.Mapping.ID
   101  		} else {
   102  			l.mappingIDX = 0
   103  		}
   104  	}
   105  	for _, f := range p.Function {
   106  		f.nameX = addString(strings, f.Name)
   107  		f.systemNameX = addString(strings, f.SystemName)
   108  		f.filenameX = addString(strings, f.Filename)
   109  	}
   110  
   111  	p.dropFramesX = addString(strings, p.DropFrames)
   112  	p.keepFramesX = addString(strings, p.KeepFrames)
   113  
   114  	if pt := p.PeriodType; pt != nil {
   115  		pt.typeX = addString(strings, pt.Type)
   116  		pt.unitX = addString(strings, pt.Unit)
   117  	}
   118  
   119  	p.commentX = nil
   120  	for _, c := range p.Comments {
   121  		p.commentX = append(p.commentX, addString(strings, c))
   122  	}
   123  
   124  	p.defaultSampleTypeX = addString(strings, p.DefaultSampleType)
   125  	p.docURLX = addString(strings, p.DocURL)
   126  
   127  	p.stringTable = make([]string, len(strings))
   128  	for s, i := range strings {
   129  		p.stringTable[i] = s
   130  	}
   131  }
   132  
   133  func (p *Profile) encode(b *buffer) {
   134  	for _, x := range p.SampleType {
   135  		encodeMessage(b, 1, x)
   136  	}
   137  	for _, x := range p.Sample {
   138  		encodeMessage(b, 2, x)
   139  	}
   140  	for _, x := range p.Mapping {
   141  		encodeMessage(b, 3, x)
   142  	}
   143  	for _, x := range p.Location {
   144  		encodeMessage(b, 4, x)
   145  	}
   146  	for _, x := range p.Function {
   147  		encodeMessage(b, 5, x)
   148  	}
   149  	encodeStrings(b, 6, p.stringTable)
   150  	encodeInt64Opt(b, 7, p.dropFramesX)
   151  	encodeInt64Opt(b, 8, p.keepFramesX)
   152  	encodeInt64Opt(b, 9, p.TimeNanos)
   153  	encodeInt64Opt(b, 10, p.DurationNanos)
   154  	if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) {
   155  		encodeMessage(b, 11, p.PeriodType)
   156  	}
   157  	encodeInt64Opt(b, 12, p.Period)
   158  	encodeInt64s(b, 13, p.commentX)
   159  	encodeInt64(b, 14, p.defaultSampleTypeX)
   160  	encodeInt64Opt(b, 15, p.docURLX)
   161  }
   162  
   163  var profileDecoder = []decoder{
   164  	nil, // 0
   165  	// repeated ValueType sample_type = 1
   166  	func(b *buffer, m message) error {
   167  		x := new(ValueType)
   168  		pp := m.(*Profile)
   169  		pp.SampleType = append(pp.SampleType, x)
   170  		return decodeMessage(b, x)
   171  	},
   172  	// repeated Sample sample = 2
   173  	func(b *buffer, m message) error {
   174  		x := new(Sample)
   175  		pp := m.(*Profile)
   176  		pp.Sample = append(pp.Sample, x)
   177  		return decodeMessage(b, x)
   178  	},
   179  	// repeated Mapping mapping = 3
   180  	func(b *buffer, m message) error {
   181  		x := new(Mapping)
   182  		pp := m.(*Profile)
   183  		pp.Mapping = append(pp.Mapping, x)
   184  		return decodeMessage(b, x)
   185  	},
   186  	// repeated Location location = 4
   187  	func(b *buffer, m message) error {
   188  		x := new(Location)
   189  		x.Line = b.tmpLines[:0] // Use shared space temporarily
   190  		pp := m.(*Profile)
   191  		pp.Location = append(pp.Location, x)
   192  		err := decodeMessage(b, x)
   193  		b.tmpLines = x.Line[:0]
   194  		// Copy to shrink size and detach from shared space.
   195  		x.Line = append([]Line(nil), x.Line...)
   196  		return err
   197  	},
   198  	// repeated Function function = 5
   199  	func(b *buffer, m message) error {
   200  		x := new(Function)
   201  		pp := m.(*Profile)
   202  		pp.Function = append(pp.Function, x)
   203  		return decodeMessage(b, x)
   204  	},
   205  	// repeated string string_table = 6
   206  	func(b *buffer, m message) error {
   207  		err := decodeStrings(b, &m.(*Profile).stringTable)
   208  		if err != nil {
   209  			return err
   210  		}
   211  		if m.(*Profile).stringTable[0] != "" {
   212  			return errors.New("string_table[0] must be ''")
   213  		}
   214  		return nil
   215  	},
   216  	// int64 drop_frames = 7
   217  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
   218  	// int64 keep_frames = 8
   219  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
   220  	// int64 time_nanos = 9
   221  	func(b *buffer, m message) error {
   222  		if m.(*Profile).TimeNanos != 0 {
   223  			return errConcatProfile
   224  		}
   225  		return decodeInt64(b, &m.(*Profile).TimeNanos)
   226  	},
   227  	// int64 duration_nanos = 10
   228  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
   229  	// ValueType period_type = 11
   230  	func(b *buffer, m message) error {
   231  		x := new(ValueType)
   232  		pp := m.(*Profile)
   233  		pp.PeriodType = x
   234  		return decodeMessage(b, x)
   235  	},
   236  	// int64 period = 12
   237  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
   238  	// repeated int64 comment = 13
   239  	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) },
   240  	// int64 defaultSampleType = 14
   241  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) },
   242  	// string doc_link = 15;
   243  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).docURLX) },
   244  }
   245  
   246  // postDecode takes the unexported fields populated by decode (with
   247  // suffix X) and populates the corresponding exported fields.
   248  // The unexported fields are cleared up to facilitate testing.
   249  func (p *Profile) postDecode() error {
   250  	var err error
   251  	mappings := make(map[uint64]*Mapping, len(p.Mapping))
   252  	mappingIds := make([]*Mapping, len(p.Mapping)+1)
   253  	for _, m := range p.Mapping {
   254  		m.File, err = getString(p.stringTable, &m.fileX, err)
   255  		m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
   256  		if m.ID < uint64(len(mappingIds)) {
   257  			mappingIds[m.ID] = m
   258  		} else {
   259  			mappings[m.ID] = m
   260  		}
   261  
   262  		// If this a main linux kernel mapping with a relocation symbol suffix
   263  		// ("[kernel.kallsyms]_text"), extract said suffix.
   264  		// It is fairly hacky to handle at this level, but the alternatives appear even worse.
   265  		const prefix = "[kernel.kallsyms]"
   266  		if strings.HasPrefix(m.File, prefix) {
   267  			m.KernelRelocationSymbol = m.File[len(prefix):]
   268  		}
   269  	}
   270  
   271  	functions := make(map[uint64]*Function, len(p.Function))
   272  	functionIds := make([]*Function, len(p.Function)+1)
   273  	for _, f := range p.Function {
   274  		f.Name, err = getString(p.stringTable, &f.nameX, err)
   275  		f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
   276  		f.Filename, err = getString(p.stringTable, &f.filenameX, err)
   277  		if f.ID < uint64(len(functionIds)) {
   278  			functionIds[f.ID] = f
   279  		} else {
   280  			functions[f.ID] = f
   281  		}
   282  	}
   283  
   284  	locations := make(map[uint64]*Location, len(p.Location))
   285  	locationIds := make([]*Location, len(p.Location)+1)
   286  	for _, l := range p.Location {
   287  		if id := l.mappingIDX; id < uint64(len(mappingIds)) {
   288  			l.Mapping = mappingIds[id]
   289  		} else {
   290  			l.Mapping = mappings[id]
   291  		}
   292  		l.mappingIDX = 0
   293  		for i, ln := range l.Line {
   294  			if id := ln.functionIDX; id != 0 {
   295  				l.Line[i].functionIDX = 0
   296  				if id < uint64(len(functionIds)) {
   297  					l.Line[i].Function = functionIds[id]
   298  				} else {
   299  					l.Line[i].Function = functions[id]
   300  				}
   301  			}
   302  		}
   303  		if l.ID < uint64(len(locationIds)) {
   304  			locationIds[l.ID] = l
   305  		} else {
   306  			locations[l.ID] = l
   307  		}
   308  	}
   309  
   310  	for _, st := range p.SampleType {
   311  		st.Type, err = getString(p.stringTable, &st.typeX, err)
   312  		st.Unit, err = getString(p.stringTable, &st.unitX, err)
   313  	}
   314  
   315  	// Pre-allocate space for all locations.
   316  	numLocations := 0
   317  	for _, s := range p.Sample {
   318  		numLocations += len(s.locationIDX)
   319  	}
   320  	locBuffer := make([]*Location, numLocations)
   321  
   322  	for _, s := range p.Sample {
   323  		if len(s.labelX) > 0 {
   324  			labels := make(map[string][]string, len(s.labelX))
   325  			numLabels := make(map[string][]int64, len(s.labelX))
   326  			numUnits := make(map[string][]string, len(s.labelX))
   327  			for _, l := range s.labelX {
   328  				var key, value string
   329  				key, err = getString(p.stringTable, &l.keyX, err)
   330  				if l.strX != 0 {
   331  					value, err = getString(p.stringTable, &l.strX, err)
   332  					labels[key] = append(labels[key], value)
   333  				} else if l.numX != 0 || l.unitX != 0 {
   334  					numValues := numLabels[key]
   335  					units := numUnits[key]
   336  					if l.unitX != 0 {
   337  						var unit string
   338  						unit, err = getString(p.stringTable, &l.unitX, err)
   339  						units = padStringArray(units, len(numValues))
   340  						numUnits[key] = append(units, unit)
   341  					}
   342  					numLabels[key] = append(numLabels[key], l.numX)
   343  				}
   344  			}
   345  			if len(labels) > 0 {
   346  				s.Label = labels
   347  			}
   348  			if len(numLabels) > 0 {
   349  				s.NumLabel = numLabels
   350  				for key, units := range numUnits {
   351  					if len(units) > 0 {
   352  						numUnits[key] = padStringArray(units, len(numLabels[key]))
   353  					}
   354  				}
   355  				s.NumUnit = numUnits
   356  			}
   357  		}
   358  
   359  		s.Location = locBuffer[:len(s.locationIDX)]
   360  		locBuffer = locBuffer[len(s.locationIDX):]
   361  		for i, lid := range s.locationIDX {
   362  			if lid < uint64(len(locationIds)) {
   363  				s.Location[i] = locationIds[lid]
   364  			} else {
   365  				s.Location[i] = locations[lid]
   366  			}
   367  		}
   368  		s.locationIDX = nil
   369  	}
   370  
   371  	p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
   372  	p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
   373  
   374  	if pt := p.PeriodType; pt == nil {
   375  		p.PeriodType = &ValueType{}
   376  	}
   377  
   378  	if pt := p.PeriodType; pt != nil {
   379  		pt.Type, err = getString(p.stringTable, &pt.typeX, err)
   380  		pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
   381  	}
   382  
   383  	for _, i := range p.commentX {
   384  		var c string
   385  		c, err = getString(p.stringTable, &i, err)
   386  		p.Comments = append(p.Comments, c)
   387  	}
   388  
   389  	p.commentX = nil
   390  	p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err)
   391  	p.DocURL, err = getString(p.stringTable, &p.docURLX, err)
   392  	p.stringTable = nil
   393  	return err
   394  }
   395  
   396  // padStringArray pads arr with enough empty strings to make arr
   397  // length l when arr's length is less than l.
   398  func padStringArray(arr []string, l int) []string {
   399  	if l <= len(arr) {
   400  		return arr
   401  	}
   402  	return append(arr, make([]string, l-len(arr))...)
   403  }
   404  
   405  func (p *ValueType) decoder() []decoder {
   406  	return valueTypeDecoder
   407  }
   408  
   409  func (p *ValueType) encode(b *buffer) {
   410  	encodeInt64Opt(b, 1, p.typeX)
   411  	encodeInt64Opt(b, 2, p.unitX)
   412  }
   413  
   414  var valueTypeDecoder = []decoder{
   415  	nil, // 0
   416  	// optional int64 type = 1
   417  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
   418  	// optional int64 unit = 2
   419  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
   420  }
   421  
   422  func (p *Sample) decoder() []decoder {
   423  	return sampleDecoder
   424  }
   425  
   426  func (p *Sample) encode(b *buffer) {
   427  	encodeUint64s(b, 1, p.locationIDX)
   428  	encodeInt64s(b, 2, p.Value)
   429  	for _, x := range p.labelX {
   430  		encodeMessage(b, 3, x)
   431  	}
   432  }
   433  
   434  var sampleDecoder = []decoder{
   435  	nil, // 0
   436  	// repeated uint64 location = 1
   437  	func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
   438  	// repeated int64 value = 2
   439  	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
   440  	// repeated Label label = 3
   441  	func(b *buffer, m message) error {
   442  		s := m.(*Sample)
   443  		n := len(s.labelX)
   444  		s.labelX = append(s.labelX, label{})
   445  		return decodeMessage(b, &s.labelX[n])
   446  	},
   447  }
   448  
   449  func (p label) decoder() []decoder {
   450  	return labelDecoder
   451  }
   452  
   453  func (p label) encode(b *buffer) {
   454  	encodeInt64Opt(b, 1, p.keyX)
   455  	encodeInt64Opt(b, 2, p.strX)
   456  	encodeInt64Opt(b, 3, p.numX)
   457  	encodeInt64Opt(b, 4, p.unitX)
   458  }
   459  
   460  var labelDecoder = []decoder{
   461  	nil, // 0
   462  	// optional int64 key = 1
   463  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).keyX) },
   464  	// optional int64 str = 2
   465  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).strX) },
   466  	// optional int64 num = 3
   467  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).numX) },
   468  	// optional int64 num = 4
   469  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).unitX) },
   470  }
   471  
   472  func (p *Mapping) decoder() []decoder {
   473  	return mappingDecoder
   474  }
   475  
   476  func (p *Mapping) encode(b *buffer) {
   477  	encodeUint64Opt(b, 1, p.ID)
   478  	encodeUint64Opt(b, 2, p.Start)
   479  	encodeUint64Opt(b, 3, p.Limit)
   480  	encodeUint64Opt(b, 4, p.Offset)
   481  	encodeInt64Opt(b, 5, p.fileX)
   482  	encodeInt64Opt(b, 6, p.buildIDX)
   483  	encodeBoolOpt(b, 7, p.HasFunctions)
   484  	encodeBoolOpt(b, 8, p.HasFilenames)
   485  	encodeBoolOpt(b, 9, p.HasLineNumbers)
   486  	encodeBoolOpt(b, 10, p.HasInlineFrames)
   487  }
   488  
   489  var mappingDecoder = []decoder{
   490  	nil, // 0
   491  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) },            // optional uint64 id = 1
   492  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) },         // optional uint64 memory_offset = 2
   493  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
   494  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) },        // optional uint64 file_offset = 4
   495  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) },          // optional int64 filename = 5
   496  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) },       // optional int64 build_id = 6
   497  	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
   498  	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
   499  	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
   500  	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
   501  }
   502  
   503  func (p *Location) decoder() []decoder {
   504  	return locationDecoder
   505  }
   506  
   507  func (p *Location) encode(b *buffer) {
   508  	encodeUint64Opt(b, 1, p.ID)
   509  	encodeUint64Opt(b, 2, p.mappingIDX)
   510  	encodeUint64Opt(b, 3, p.Address)
   511  	for i := range p.Line {
   512  		encodeMessage(b, 4, &p.Line[i])
   513  	}
   514  	encodeBoolOpt(b, 5, p.IsFolded)
   515  }
   516  
   517  var locationDecoder = []decoder{
   518  	nil, // 0
   519  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) },         // optional uint64 id = 1;
   520  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
   521  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) },    // optional uint64 address = 3;
   522  	func(b *buffer, m message) error { // repeated Line line = 4
   523  		pp := m.(*Location)
   524  		n := len(pp.Line)
   525  		pp.Line = append(pp.Line, Line{})
   526  		return decodeMessage(b, &pp.Line[n])
   527  	},
   528  	func(b *buffer, m message) error { return decodeBool(b, &m.(*Location).IsFolded) }, // optional bool is_folded = 5;
   529  }
   530  
   531  func (p *Line) decoder() []decoder {
   532  	return lineDecoder
   533  }
   534  
   535  func (p *Line) encode(b *buffer) {
   536  	encodeUint64Opt(b, 1, p.functionIDX)
   537  	encodeInt64Opt(b, 2, p.Line)
   538  	encodeInt64Opt(b, 3, p.Column)
   539  }
   540  
   541  var lineDecoder = []decoder{
   542  	nil, // 0
   543  	// optional uint64 function_id = 1
   544  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
   545  	// optional int64 line = 2
   546  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
   547  	// optional int64 column = 3
   548  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Column) },
   549  }
   550  
   551  func (p *Function) decoder() []decoder {
   552  	return functionDecoder
   553  }
   554  
   555  func (p *Function) encode(b *buffer) {
   556  	encodeUint64Opt(b, 1, p.ID)
   557  	encodeInt64Opt(b, 2, p.nameX)
   558  	encodeInt64Opt(b, 3, p.systemNameX)
   559  	encodeInt64Opt(b, 4, p.filenameX)
   560  	encodeInt64Opt(b, 5, p.StartLine)
   561  }
   562  
   563  var functionDecoder = []decoder{
   564  	nil, // 0
   565  	// optional uint64 id = 1
   566  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
   567  	// optional int64 function_name = 2
   568  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
   569  	// optional int64 function_system_name = 3
   570  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
   571  	// repeated int64 filename = 4
   572  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
   573  	// optional int64 start_line = 5
   574  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
   575  }
   576  
   577  func addString(strings map[string]int, s string) int64 {
   578  	i, ok := strings[s]
   579  	if !ok {
   580  		i = len(strings)
   581  		strings[s] = i
   582  	}
   583  	return int64(i)
   584  }
   585  
   586  func getString(strings []string, strng *int64, err error) (string, error) {
   587  	if err != nil {
   588  		return "", err
   589  	}
   590  	s := int(*strng)
   591  	if s < 0 || s >= len(strings) {
   592  		return "", errMalformed
   593  	}
   594  	*strng = 0
   595  	return strings[s], nil
   596  }
   597  

View as plain text