it never ends.
This commit is contained in:
35
nip77/negentropy/storage/vector/helpers.go
Normal file
35
nip77/negentropy/storage/vector/helpers.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package vector
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
|
||||
"fiatjaf.com/nostr/nip77/negentropy"
|
||||
)
|
||||
|
||||
func itemCompare(a, b negentropy.Item) int {
|
||||
if a.Timestamp == b.Timestamp {
|
||||
return bytes.Compare(a.ID[:], b.ID[:])
|
||||
}
|
||||
return cmp.Compare(a.Timestamp, b.Timestamp)
|
||||
}
|
||||
|
||||
// binary search with custom function
|
||||
func searchItemWithBound(items []negentropy.Item, bound negentropy.Bound) int {
|
||||
n := len(items)
|
||||
// Define x[-1] < target and x[n] >= target.
|
||||
// Invariant: x[i-1] < target, x[j] >= target.
|
||||
i, j := 0, n
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1) // avoid overflow when computing h
|
||||
// i ≤ h < j
|
||||
if items[h].Timestamp < bound.Timestamp ||
|
||||
(items[h].Timestamp == bound.Timestamp && bytes.Compare(items[h].ID[:], bound.IDPrefix) == -1) {
|
||||
i = h + 1 // preserves x[i-1] < target
|
||||
} else {
|
||||
j = h // preserves x[j] >= target
|
||||
}
|
||||
}
|
||||
// i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i.
|
||||
return i
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package vector
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"iter"
|
||||
"slices"
|
||||
|
||||
@@ -24,10 +23,6 @@ func New() *Vector {
|
||||
}
|
||||
|
||||
func (v *Vector) Insert(createdAt nostr.Timestamp, id nostr.ID) {
|
||||
if len(id) != 64 {
|
||||
panic(fmt.Errorf("bad id size for added item: expected %d bytes, got %d", 32, len(id)/2))
|
||||
}
|
||||
|
||||
item := negentropy.Item{Timestamp: createdAt, ID: id}
|
||||
v.items = append(v.items, item)
|
||||
}
|
||||
@@ -39,12 +34,12 @@ func (v *Vector) Seal() {
|
||||
panic("trying to seal an already sealed vector")
|
||||
}
|
||||
v.sealed = true
|
||||
slices.SortFunc(v.items, negentropy.ItemCompare)
|
||||
slices.SortFunc(v.items, itemCompare)
|
||||
}
|
||||
|
||||
func (v *Vector) GetBound(idx int) negentropy.Bound {
|
||||
if idx < len(v.items) {
|
||||
return negentropy.Bound{Item: v.items[idx]}
|
||||
return negentropy.Bound{Timestamp: v.items[idx].Timestamp, IDPrefix: v.items[idx].ID[:]}
|
||||
}
|
||||
return negentropy.InfiniteBound
|
||||
}
|
||||
@@ -60,7 +55,7 @@ func (v *Vector) Range(begin, end int) iter.Seq2[int, negentropy.Item] {
|
||||
}
|
||||
|
||||
func (v *Vector) FindLowerBound(begin, end int, bound negentropy.Bound) int {
|
||||
idx, _ := slices.BinarySearchFunc(v.items[begin:end], bound.Item, negentropy.ItemCompare)
|
||||
idx := searchItemWithBound(v.items[begin:end], bound)
|
||||
return begin + idx
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package negentropy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"fmt"
|
||||
|
||||
"fiatjaf.com/nostr"
|
||||
@@ -36,13 +34,6 @@ type Item struct {
|
||||
ID nostr.ID
|
||||
}
|
||||
|
||||
func ItemCompare(a, b Item) int {
|
||||
if a.Timestamp == b.Timestamp {
|
||||
return bytes.Compare(a.ID[:], b.ID[:])
|
||||
}
|
||||
return cmp.Compare(a.Timestamp, b.Timestamp)
|
||||
}
|
||||
|
||||
func (i Item) String() string { return fmt.Sprintf("Item<%d:%x>", i.Timestamp, i.ID[:]) }
|
||||
|
||||
type Bound struct {
|
||||
|
||||
Reference in New Issue
Block a user