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