Home | History | Annotate | Download | only in suffixarray
      1 // Copyright 2010 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 suffixarray implements substring search in logarithmic time using
      6 // an in-memory suffix array.
      7 //
      8 // Example use:
      9 //
     10 //	// create index for some data
     11 //	index := suffixarray.New(data)
     12 //
     13 //	// lookup byte slice s
     14 //	offsets1 := index.Lookup(s, -1) // the list of all indices where s occurs in data
     15 //	offsets2 := index.Lookup(s, 3)  // the list of at most 3 indices where s occurs in data
     16 //
     17 package suffixarray
     18 
     19 import (
     20 	"bytes"
     21 	"encoding/binary"
     22 	"io"
     23 	"regexp"
     24 	"sort"
     25 )
     26 
     27 // Index implements a suffix array for fast substring search.
     28 type Index struct {
     29 	data []byte
     30 	sa   []int // suffix array for data; len(sa) == len(data)
     31 }
     32 
     33 // New creates a new Index for data.
     34 // Index creation time is O(N*log(N)) for N = len(data).
     35 func New(data []byte) *Index {
     36 	return &Index{data, qsufsort(data)}
     37 }
     38 
     39 // writeInt writes an int x to w using buf to buffer the write.
     40 func writeInt(w io.Writer, buf []byte, x int) error {
     41 	binary.PutVarint(buf, int64(x))
     42 	_, err := w.Write(buf[0:binary.MaxVarintLen64])
     43 	return err
     44 }
     45 
     46 // readInt reads an int x from r using buf to buffer the read and returns x.
     47 func readInt(r io.Reader, buf []byte) (int, error) {
     48 	_, err := io.ReadFull(r, buf[0:binary.MaxVarintLen64]) // ok to continue with error
     49 	x, _ := binary.Varint(buf)
     50 	return int(x), err
     51 }
     52 
     53 // writeSlice writes data[:n] to w and returns n.
     54 // It uses buf to buffer the write.
     55 func writeSlice(w io.Writer, buf []byte, data []int) (n int, err error) {
     56 	// encode as many elements as fit into buf
     57 	p := binary.MaxVarintLen64
     58 	for ; n < len(data) && p+binary.MaxVarintLen64 <= len(buf); n++ {
     59 		p += binary.PutUvarint(buf[p:], uint64(data[n]))
     60 	}
     61 
     62 	// update buffer size
     63 	binary.PutVarint(buf, int64(p))
     64 
     65 	// write buffer
     66 	_, err = w.Write(buf[0:p])
     67 	return
     68 }
     69 
     70 // readSlice reads data[:n] from r and returns n.
     71 // It uses buf to buffer the read.
     72 func readSlice(r io.Reader, buf []byte, data []int) (n int, err error) {
     73 	// read buffer size
     74 	var size int
     75 	size, err = readInt(r, buf)
     76 	if err != nil {
     77 		return
     78 	}
     79 
     80 	// read buffer w/o the size
     81 	if _, err = io.ReadFull(r, buf[binary.MaxVarintLen64:size]); err != nil {
     82 		return
     83 	}
     84 
     85 	// decode as many elements as present in buf
     86 	for p := binary.MaxVarintLen64; p < size; n++ {
     87 		x, w := binary.Uvarint(buf[p:])
     88 		data[n] = int(x)
     89 		p += w
     90 	}
     91 
     92 	return
     93 }
     94 
     95 const bufSize = 16 << 10 // reasonable for BenchmarkSaveRestore
     96 
     97 // Read reads the index from r into x; x must not be nil.
     98 func (x *Index) Read(r io.Reader) error {
     99 	// buffer for all reads
    100 	buf := make([]byte, bufSize)
    101 
    102 	// read length
    103 	n, err := readInt(r, buf)
    104 	if err != nil {
    105 		return err
    106 	}
    107 
    108 	// allocate space
    109 	if 2*n < cap(x.data) || cap(x.data) < n {
    110 		// new data is significantly smaller or larger then
    111 		// existing buffers - allocate new ones
    112 		x.data = make([]byte, n)
    113 		x.sa = make([]int, n)
    114 	} else {
    115 		// re-use existing buffers
    116 		x.data = x.data[0:n]
    117 		x.sa = x.sa[0:n]
    118 	}
    119 
    120 	// read data
    121 	if _, err := io.ReadFull(r, x.data); err != nil {
    122 		return err
    123 	}
    124 
    125 	// read index
    126 	for sa := x.sa; len(sa) > 0; {
    127 		n, err := readSlice(r, buf, sa)
    128 		if err != nil {
    129 			return err
    130 		}
    131 		sa = sa[n:]
    132 	}
    133 	return nil
    134 }
    135 
    136 // Write writes the index x to w.
    137 func (x *Index) Write(w io.Writer) error {
    138 	// buffer for all writes
    139 	buf := make([]byte, bufSize)
    140 
    141 	// write length
    142 	if err := writeInt(w, buf, len(x.data)); err != nil {
    143 		return err
    144 	}
    145 
    146 	// write data
    147 	if _, err := w.Write(x.data); err != nil {
    148 		return err
    149 	}
    150 
    151 	// write index
    152 	for sa := x.sa; len(sa) > 0; {
    153 		n, err := writeSlice(w, buf, sa)
    154 		if err != nil {
    155 			return err
    156 		}
    157 		sa = sa[n:]
    158 	}
    159 	return nil
    160 }
    161 
    162 // Bytes returns the data over which the index was created.
    163 // It must not be modified.
    164 //
    165 func (x *Index) Bytes() []byte {
    166 	return x.data
    167 }
    168 
    169 func (x *Index) at(i int) []byte {
    170 	return x.data[x.sa[i]:]
    171 }
    172 
    173 // lookupAll returns a slice into the matching region of the index.
    174 // The runtime is O(log(N)*len(s)).
    175 func (x *Index) lookupAll(s []byte) []int {
    176 	// find matching suffix index range [i:j]
    177 	// find the first index where s would be the prefix
    178 	i := sort.Search(len(x.sa), func(i int) bool { return bytes.Compare(x.at(i), s) >= 0 })
    179 	// starting at i, find the first index at which s is not a prefix
    180 	j := i + sort.Search(len(x.sa)-i, func(j int) bool { return !bytes.HasPrefix(x.at(j+i), s) })
    181 	return x.sa[i:j]
    182 }
    183 
    184 // Lookup returns an unsorted list of at most n indices where the byte string s
    185 // occurs in the indexed data. If n < 0, all occurrences are returned.
    186 // The result is nil if s is empty, s is not found, or n == 0.
    187 // Lookup time is O(log(N)*len(s) + len(result)) where N is the
    188 // size of the indexed data.
    189 //
    190 func (x *Index) Lookup(s []byte, n int) (result []int) {
    191 	if len(s) > 0 && n != 0 {
    192 		matches := x.lookupAll(s)
    193 		if n < 0 || len(matches) < n {
    194 			n = len(matches)
    195 		}
    196 		// 0 <= n <= len(matches)
    197 		if n > 0 {
    198 			result = make([]int, n)
    199 			copy(result, matches)
    200 		}
    201 	}
    202 	return
    203 }
    204 
    205 // FindAllIndex returns a sorted list of non-overlapping matches of the
    206 // regular expression r, where a match is a pair of indices specifying
    207 // the matched slice of x.Bytes(). If n < 0, all matches are returned
    208 // in successive order. Otherwise, at most n matches are returned and
    209 // they may not be successive. The result is nil if there are no matches,
    210 // or if n == 0.
    211 //
    212 func (x *Index) FindAllIndex(r *regexp.Regexp, n int) (result [][]int) {
    213 	// a non-empty literal prefix is used to determine possible
    214 	// match start indices with Lookup
    215 	prefix, complete := r.LiteralPrefix()
    216 	lit := []byte(prefix)
    217 
    218 	// worst-case scenario: no literal prefix
    219 	if prefix == "" {
    220 		return r.FindAllIndex(x.data, n)
    221 	}
    222 
    223 	// if regexp is a literal just use Lookup and convert its
    224 	// result into match pairs
    225 	if complete {
    226 		// Lookup returns indices that may belong to overlapping matches.
    227 		// After eliminating them, we may end up with fewer than n matches.
    228 		// If we don't have enough at the end, redo the search with an
    229 		// increased value n1, but only if Lookup returned all the requested
    230 		// indices in the first place (if it returned fewer than that then
    231 		// there cannot be more).
    232 		for n1 := n; ; n1 += 2 * (n - len(result)) /* overflow ok */ {
    233 			indices := x.Lookup(lit, n1)
    234 			if len(indices) == 0 {
    235 				return
    236 			}
    237 			sort.Ints(indices)
    238 			pairs := make([]int, 2*len(indices))
    239 			result = make([][]int, len(indices))
    240 			count := 0
    241 			prev := 0
    242 			for _, i := range indices {
    243 				if count == n {
    244 					break
    245 				}
    246 				// ignore indices leading to overlapping matches
    247 				if prev <= i {
    248 					j := 2 * count
    249 					pairs[j+0] = i
    250 					pairs[j+1] = i + len(lit)
    251 					result[count] = pairs[j : j+2]
    252 					count++
    253 					prev = i + len(lit)
    254 				}
    255 			}
    256 			result = result[0:count]
    257 			if len(result) >= n || len(indices) != n1 {
    258 				// found all matches or there's no chance to find more
    259 				// (n and n1 can be negative)
    260 				break
    261 			}
    262 		}
    263 		if len(result) == 0 {
    264 			result = nil
    265 		}
    266 		return
    267 	}
    268 
    269 	// regexp has a non-empty literal prefix; Lookup(lit) computes
    270 	// the indices of possible complete matches; use these as starting
    271 	// points for anchored searches
    272 	// (regexp "^" matches beginning of input, not beginning of line)
    273 	r = regexp.MustCompile("^" + r.String()) // compiles because r compiled
    274 
    275 	// same comment about Lookup applies here as in the loop above
    276 	for n1 := n; ; n1 += 2 * (n - len(result)) /* overflow ok */ {
    277 		indices := x.Lookup(lit, n1)
    278 		if len(indices) == 0 {
    279 			return
    280 		}
    281 		sort.Ints(indices)
    282 		result = result[0:0]
    283 		prev := 0
    284 		for _, i := range indices {
    285 			if len(result) == n {
    286 				break
    287 			}
    288 			m := r.FindIndex(x.data[i:]) // anchored search - will not run off
    289 			// ignore indices leading to overlapping matches
    290 			if m != nil && prev <= i {
    291 				m[0] = i // correct m
    292 				m[1] += i
    293 				result = append(result, m)
    294 				prev = m[1]
    295 			}
    296 		}
    297 		if len(result) >= n || len(indices) != n1 {
    298 			// found all matches or there's no chance to find more
    299 			// (n and n1 can be negative)
    300 			break
    301 		}
    302 	}
    303 	if len(result) == 0 {
    304 		result = nil
    305 	}
    306 	return
    307 }
    308