From e388e16e71d2845a9c26979e70e092153ef5a24b Mon Sep 17 00:00:00 2001 From: bloeys Date: Mon, 1 Aug 2022 07:14:35 +0400 Subject: [PATCH] Use binary search in GetParaFromTextBufIndex --- main.go | 34 ++++++++++++++++++---------------- ring/ring.go | 11 +++++++++++ 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/main.go b/main.go index e7c171c..a80e22d 100755 --- a/main.go +++ b/main.go @@ -1096,13 +1096,10 @@ func GetParaFromTextBufIndex(it ring.Iterator[byte], paraIt ring.Iterator[Para], return } - ticks := 0 - - //Find first valid para + // Find first valid para paraIt.GotoStart() for p, done := paraIt.NextPtr(); !done; p, done = paraIt.NextPtr() { - ticks++ if !IsParaValid(it.Buf, p) { continue } @@ -1111,25 +1108,30 @@ func GetParaFromTextBufIndex(it ring.Iterator[byte], paraIt ring.Iterator[Para], break } - // @PERF We need a faster way of finding the current paragraph. Binary search? - for p, done := paraIt.NextPtr(); !done; p, done = paraIt.NextPtr() { + // Binary search for the paragraph + lowIndexRel := paraIt.CurrToRelIndex() + highIndexRel := uint64(paraIt.Buf.Len) + for lowIndexRel <= highIndexRel { + + medianIndexRel := (lowIndexRel + highIndexRel) / 2 + p := paraIt.Buf.GetPtr(medianIndexRel) - ticks++ startIndexRel := it.Buf.RelIndexFromWriteCount(p.StartIndex_WriteCount) endIndexRel := it.Buf.RelIndexFromWriteCount(p.EndIndex_WriteCount) - if textBufStartIndexRel < startIndexRel || textBufStartIndexRel > endIndexRel { - continue - } - outPara = p - pIndex = paraIt.CurrToRelIndex() - break + if textBufStartIndexRel < startIndexRel { + highIndexRel = medianIndexRel - 1 + } else if textBufStartIndexRel > endIndexRel { + lowIndexRel = medianIndexRel + 1 + } else { + outPara = p + pIndex = medianIndexRel + break + } } - println("Ticks to finding para:", ticks) - if outPara == nil { - panic("Could not find para") + panic(fmt.Sprintf("Could not find paragraph for index %d", textBufStartIndexRel)) } return outPara, pIndex diff --git a/ring/ring.go b/ring/ring.go index 71379af..731e533 100755 --- a/ring/ring.go +++ b/ring/ring.go @@ -74,6 +74,17 @@ func (b *Buffer[T]) Get(index uint64) (val T) { return b.Data[(b.Start+int64(index))%b.Cap] } +// Get returns the element at the index relative from Buffer.Start +// If there are no elements then the default value of T is returned +func (b *Buffer[T]) GetPtr(index uint64) (val *T) { + + if index >= uint64(b.Len) { + return new(T) + } + + return &b.Data[(b.Start+int64(index))%b.Cap] +} + // AbsIndexFromRel takes an index relative to Buffer.Start and returns an absolute index into Buffer.Data func (b *Buffer[T]) AbsIndexFromRel(relIndex uint64) uint64 { return uint64((b.Start + int64(relIndex)) % b.Cap)