fzf/src/merger.go

122 lines
2.5 KiB
Go
Raw Normal View History

package fzf
import "fmt"
2016-08-14 04:51:34 -04:00
// EmptyMerger is a Merger with no data
2016-08-19 12:46:54 -04:00
var EmptyMerger = NewMerger(nil, [][]*Result{}, false, false)
2015-01-11 13:01:24 -05:00
// Merger holds a set of locally sorted lists of items and provides the view of
// a single, globally-sorted list
type Merger struct {
2016-08-19 12:46:54 -04:00
pattern *Pattern
lists [][]*Result
merged []*Result
chunks *[]*Chunk
cursors []int
sorted bool
tac bool
final bool
count int
}
2015-03-22 03:05:54 -04:00
// PassMerger returns a new Merger that simply returns the items in the
// original order
func PassMerger(chunks *[]*Chunk, tac bool) *Merger {
mg := Merger{
2016-08-19 12:46:54 -04:00
pattern: nil,
chunks: chunks,
tac: tac,
count: 0}
for _, chunk := range *mg.chunks {
mg.count += len(*chunk)
}
return &mg
}
2015-01-11 13:01:24 -05:00
// NewMerger returns a new Merger
2016-08-19 12:46:54 -04:00
func NewMerger(pattern *Pattern, lists [][]*Result, sorted bool, tac bool) *Merger {
mg := Merger{
2016-08-19 12:46:54 -04:00
pattern: pattern,
lists: lists,
merged: []*Result{},
chunks: nil,
cursors: make([]int, len(lists)),
sorted: sorted,
tac: tac,
final: false,
count: 0}
for _, list := range mg.lists {
mg.count += len(list)
}
return &mg
}
2015-01-11 13:01:24 -05:00
// Length returns the number of items
func (mg *Merger) Length() int {
return mg.count
}
// Get returns the pointer to the Result object indexed by the given integer
func (mg *Merger) Get(idx int) *Result {
if mg.chunks != nil {
if mg.tac {
idx = mg.count - idx - 1
}
chunk := (*mg.chunks)[idx/chunkSize]
return &Result{item: (*chunk)[idx%chunkSize]}
}
if mg.sorted {
return mg.mergedGet(idx)
}
if mg.tac {
idx = mg.count - idx - 1
}
for _, list := range mg.lists {
numItems := len(list)
if idx < numItems {
return list[idx]
}
idx -= numItems
}
panic(fmt.Sprintf("Index out of bounds (unsorted, %d/%d)", idx, mg.count))
}
2015-08-02 00:06:15 -04:00
func (mg *Merger) cacheable() bool {
return mg.count < mergerCacheMax
}
func (mg *Merger) mergedGet(idx int) *Result {
for i := len(mg.merged); i <= idx; i++ {
minRank := minRank()
minIdx := -1
for listIdx, list := range mg.lists {
cursor := mg.cursors[listIdx]
if cursor < 0 || cursor == len(list) {
mg.cursors[listIdx] = -1
continue
}
if cursor >= 0 {
rank := list[cursor].rank
if minIdx < 0 || compareRanks(rank, minRank, mg.tac) {
minRank = rank
minIdx = listIdx
}
}
mg.cursors[listIdx] = cursor
}
if minIdx >= 0 {
chosen := mg.lists[minIdx]
mg.merged = append(mg.merged, chosen[mg.cursors[minIdx]])
2015-01-11 13:01:24 -05:00
mg.cursors[minIdx]++
} else {
panic(fmt.Sprintf("Index out of bounds (sorted, %d/%d)", i, mg.count))
}
}
return mg.merged[idx]
}