Something went wrong. Try again.
Fast, indexed regexp search over large file trees
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202// Copyright 2024 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 index
import ( "bytes" "encoding/binary" "iter" "os" "strings")
// A Path is a Path stored in the index,// either in the root list or the file list.//// Paths stored in the index are ordered// using the [Path.cmp] method.type Path struct { s string}
func MakePath(s string) Path { return Path{s}}
func (p Path) String() string { return p.s}
func (p Path) HasPathPrefix(parent Path) bool { return strings.HasPrefix(p.s, parent.s) && (p.s == parent.s || p.s[len(parent.s)] == '/' || p.s[len(parent.s)] == os.PathSeparator)}
// Compare returns the comparison of p and q.// It is analogous to strings.Compare(p, q)// but x/y is ordered before x.foo by treating// slashes as if they had byte value 0.// On Windows, backslashes are treated as equal to slashes.func (p Path) Compare(q Path) int { for i := range min(len(p.s), len(q.s)) { pi := p.s[i] qi := q.s[i] if pi == '/' || pi == os.PathSeparator { pi = 0 } if qi == '/' || qi == os.PathSeparator { qi = 0 } if pi != qi { return int(pi) - int(qi) } } return len(p.s) - len(q.s)}
type PathWriter struct { data *Buffer index *Buffer version int group int start int n int last Path}
func NewPathWriter(data, index *Buffer, version, group int) *PathWriter { if version != 1 && version != 2 { panic("bad PathWriter version") } return &PathWriter{ data: data, index: index, version: version, group: group, start: data.Offset(), }}
func (w *PathWriter) Write(p Path) { if w.version == 1 { if w.index != nil { w.index.WriteUint(w.data.Offset() - w.start) } w.data.WriteString(p.s) w.data.WriteByte(0) return }
pre := 0 if w.group == 0 && w.n == 0 || w.group > 0 && w.n%w.group == 0 { if w.index != nil { w.index.WriteUint(w.data.Offset() - w.start) } } else { for pre < len(w.last.s) && pre < len(p.s) && w.last.s[pre] == p.s[pre] { pre++ } } w.data.WriteVarint(pre) w.data.WriteVarint(len(p.s) - pre) w.data.WriteString(string(p.s[pre:])) w.last = p w.n++}
// Count returns the number of paths written to w.func (w *PathWriter) Count() int { return w.n}
// Collect iterates over paths and writes all the paths to w.func (w *PathWriter) Collect(paths iter.Seq[Path]) { for p := range paths { w.Write(p) }}
type PathReader struct { version int data []byte path Path n int limit int}
func NewPathReader(version int, data []byte, limit int) *PathReader { if version != 1 && version != 2 { panic("bad PathWriter version") } r := &PathReader{ version: version, data: data, limit: limit, } r.Next() return r}
func (r *PathReader) All() iter.Seq[Path] { return func(yield func(Path) bool) { if !r.Valid() { return } for yield(r.Path()) && r.Next() { continue } }}
func (r *PathReader) Valid() bool { return r.path.s != ""}
func (r *PathReader) Next() bool { if r.limit == 0 { r.path.s = "" return false } if r.limit > 0 { r.limit-- } if r.version == 1 { i := bytes.IndexByte(r.data, '\x00') if i <= 0 { r.path.s = "" return false } r.path.s, r.data = string(r.data[:i]), r.data[i+1:] return true }
pre, w := binary.Uvarint(r.data) if w <= 0 || pre > uint64(len(r.path.s)) { r.path.s = "" return false } r.data = r.data[w:]
n, w := binary.Uvarint(r.data) if w <= 0 || n > uint64(len(r.data)-w) { r.path.s = "" return false } r.data = r.data[w:] r.path.s = r.path.s[:pre] + string(r.data[:n]) r.data = r.data[n:] return true}
func (r *PathReader) Path() Path { return r.path}
func (r *PathReader) NumPaths() int { return r.n}