| // Copyright 2016 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 stringset provides a way to represent a collection of strings | |
| // compactly. | |
| package stringset | |
| import "sort" | |
| // A Set holds a collection of strings that can be looked up by an index number. | |
| type Set struct { | |
| // These fields are exported to allow for code generation. | |
| Data string | |
| Index []uint16 | |
| } | |
| // Elem returns the string with index i. It panics if i is out of range. | |
| func (s *Set) Elem(i int) string { | |
| return s.Data[s.Index[i]:s.Index[i+1]] | |
| } | |
| // Len returns the number of strings in the set. | |
| func (s *Set) Len() int { | |
| return len(s.Index) - 1 | |
| } | |
| // Search returns the index of the given string or -1 if it is not in the set. | |
| // The Set must have been created with strings in sorted order. | |
| func Search(s *Set, str string) int { | |
| // TODO: optimize this if it gets used a lot. | |
| n := len(s.Index) - 1 | |
| p := sort.Search(n, func(i int) bool { | |
| return s.Elem(i) >= str | |
| }) | |
| if p == n || str != s.Elem(p) { | |
| return -1 | |
| } | |
| return p | |
| } | |
| // A Builder constructs Sets. | |
| type Builder struct { | |
| set Set | |
| index map[string]int | |
| } | |
| // NewBuilder returns a new and initialized Builder. | |
| func NewBuilder() *Builder { | |
| return &Builder{ | |
| set: Set{ | |
| Index: []uint16{0}, | |
| }, | |
| index: map[string]int{}, | |
| } | |
| } | |
| // Set creates the set created so far. | |
| func (b *Builder) Set() Set { | |
| return b.set | |
| } | |
| // Index returns the index for the given string, which must have been added | |
| // before. | |
| func (b *Builder) Index(s string) int { | |
| return b.index[s] | |
| } | |
| // Add adds a string to the index. Strings that are added by a single Add will | |
| // be stored together, unless they match an existing string. | |
| func (b *Builder) Add(ss ...string) { | |
| // First check if the string already exists. | |
| for _, s := range ss { | |
| if _, ok := b.index[s]; ok { | |
| continue | |
| } | |
| b.index[s] = len(b.set.Index) - 1 | |
| b.set.Data += s | |
| x := len(b.set.Data) | |
| if x > 0xFFFF { | |
| panic("Index too > 0xFFFF") | |
| } | |
| b.set.Index = append(b.set.Index, uint16(x)) | |
| } | |
| } |