@@ -223,6 +223,59 @@ func (d *Decoder) ApproxLen() int {
223223
224224type searchFunc func (int ) bool
225225
226+ // SeekToBlock will find the nearest block, and unpack it. Unlike Seek, it doesn't
227+ // apply search in the resulting uid list and then move the pointer forward. When we are going
228+ // to intersect the list later, this function is useful.
229+ func (d * Decoder ) SeekToBlock (uid uint64 , whence seekPos ) []uint64 {
230+ if d .Pack == nil {
231+ return []uint64 {}
232+ }
233+ prevBlockIdx := d .blockIdx
234+ d .blockIdx = 0
235+ if uid == 0 {
236+ return d .UnpackBlock ()
237+ }
238+
239+ pack := d .Pack
240+ blocksFunc := func () searchFunc {
241+ var f searchFunc
242+ switch whence {
243+ case SeekStart :
244+ f = func (i int ) bool { return pack .Blocks [i + prevBlockIdx ].Base >= uid }
245+ case SeekCurrent :
246+ f = func (i int ) bool { return pack .Blocks [i + prevBlockIdx ].Base > uid }
247+ }
248+ return f
249+ }
250+
251+ idx := sort .Search (len (pack .Blocks [prevBlockIdx :]), blocksFunc ()) + prevBlockIdx
252+ // The first block.Base >= uid.
253+ if idx == 0 {
254+ return d .UnpackBlock ()
255+ }
256+ // The uid is the first entry in the block.
257+ if idx < len (pack .Blocks ) && pack .Blocks [idx ].Base == uid {
258+ d .blockIdx = idx
259+ return d .UnpackBlock ()
260+ }
261+
262+ // Either the idx = len(pack.Blocks) that means it wasn't found in any of the block's base. Or,
263+ // we found the first block index whose base is greater than uid. In these cases, go to the
264+ // previous block and search there.
265+ d .blockIdx = idx - 1 // Move to the previous block. If blockIdx<0, unpack will deal with it.
266+ if d .blockIdx != prevBlockIdx {
267+ d .UnpackBlock () // And get all their uids.
268+ }
269+
270+ if uid < d .uids [len (d .uids )- 1 ] {
271+ return d .uids
272+ }
273+
274+ // Could not find any uid in the block, which is >= uid. The next block might still have valid
275+ // entries > uid.
276+ return d .Next ()
277+ }
278+
226279// Seek will search for uid in a packed block using the specified whence position.
227280// The value of whence must be one of the predefined values SeekStart or SeekCurrent.
228281// SeekStart searches uid and includes it as part of the results.
@@ -233,6 +286,7 @@ func (d *Decoder) Seek(uid uint64, whence seekPos) []uint64 {
233286 if d .Pack == nil {
234287 return []uint64 {}
235288 }
289+ prevBlockIdx := d .blockIdx
236290 d .blockIdx = 0
237291 if uid == 0 {
238292 return d .UnpackBlock ()
@@ -243,14 +297,14 @@ func (d *Decoder) Seek(uid uint64, whence seekPos) []uint64 {
243297 var f searchFunc
244298 switch whence {
245299 case SeekStart :
246- f = func (i int ) bool { return pack .Blocks [i ].Base >= uid }
300+ f = func (i int ) bool { return pack .Blocks [i + prevBlockIdx ].Base >= uid }
247301 case SeekCurrent :
248- f = func (i int ) bool { return pack .Blocks [i ].Base > uid }
302+ f = func (i int ) bool { return pack .Blocks [i + prevBlockIdx ].Base > uid }
249303 }
250304 return f
251305 }
252306
253- idx := sort .Search (len (pack .Blocks ), blocksFunc ())
307+ idx := sort .Search (len (pack .Blocks [ prevBlockIdx :] ), blocksFunc ()) + prevBlockIdx
254308 // The first block.Base >= uid.
255309 if idx == 0 {
256310 return d .UnpackBlock ()
@@ -265,7 +319,9 @@ func (d *Decoder) Seek(uid uint64, whence seekPos) []uint64 {
265319 // we found the first block index whose base is greater than uid. In these cases, go to the
266320 // previous block and search there.
267321 d .blockIdx = idx - 1 // Move to the previous block. If blockIdx<0, unpack will deal with it.
268- d .UnpackBlock () // And get all their uids.
322+ if d .blockIdx != prevBlockIdx {
323+ d .UnpackBlock () // And get all their uids.
324+ }
269325
270326 uidsFunc := func () searchFunc {
271327 var f searchFunc
0 commit comments