github.com/zuoyebang/bitalostable@v1.0.1-0.20240229032404-e3b99a834294/internal/keyspan/filter.go (about)

     1  // Copyright 2022 The LevelDB-Go and Pebble Authors. All rights reserved. Use
     2  // of this source code is governed by a BSD-style license that can be found in
     3  // the LICENSE file.
     4  
     5  package keyspan
     6  
     7  // FilterFunc defines a transform from the input Span into the output Span. The
     8  // function returns true if the Span should be returned by the iterator, and
     9  // false if the Span should be skipped. The FilterFunc is permitted to mutate
    10  // the output Span, for example, to elice certain keys, or update the Span's
    11  // bounds if so desired. The output Span's Keys slice may be reused to reduce
    12  // allocations.
    13  type FilterFunc func(in *Span, out *Span) (keep bool)
    14  
    15  // filteringIter is a FragmentIterator that uses a FilterFunc to select which
    16  // Spans from the input iterator are returned in the output.
    17  //
    18  // A note on Span lifetimes: as the FilterFunc reuses a Span with a mutable
    19  // slice of Keys to reduce allocations, Spans returned by this iterator are only
    20  // valid until the next relative or absolute positioning method is called.
    21  type filteringIter struct {
    22  	iter     FragmentIterator
    23  	filterFn FilterFunc
    24  
    25  	// span is a mutable Span passed to the filterFn. The filterFn is free to
    26  	// mutate this Span. The slice of Keys in the Span is reused with every call
    27  	// to the filterFn.
    28  	span Span
    29  }
    30  
    31  var _ FragmentIterator = (*filteringIter)(nil)
    32  
    33  // Filter returns a new filteringIter that will filter the Spans from the
    34  // provided child iterator using the provided FilterFunc.
    35  func Filter(iter FragmentIterator, filter FilterFunc) FragmentIterator {
    36  	return &filteringIter{iter: iter, filterFn: filter}
    37  }
    38  
    39  // SeekGE implements FragmentIterator.
    40  func (i *filteringIter) SeekGE(key []byte) *Span {
    41  	return i.filter(i.iter.SeekGE(key), +1)
    42  }
    43  
    44  // SeekLT implements FragmentIterator.
    45  func (i *filteringIter) SeekLT(key []byte) *Span {
    46  	return i.filter(i.iter.SeekLT(key), -1)
    47  }
    48  
    49  // First implements FragmentIterator.
    50  func (i *filteringIter) First() *Span {
    51  	return i.filter(i.iter.First(), +1)
    52  }
    53  
    54  // Last implements FragmentIterator.
    55  func (i *filteringIter) Last() *Span {
    56  	return i.filter(i.iter.Last(), -1)
    57  }
    58  
    59  // Next implements FragmentIterator.
    60  func (i *filteringIter) Next() *Span {
    61  	return i.filter(i.iter.Next(), +1)
    62  }
    63  
    64  // Prev implements FragmentIterator.
    65  func (i *filteringIter) Prev() *Span {
    66  	return i.filter(i.iter.Prev(), -1)
    67  }
    68  
    69  // Error implements FragmentIterator.
    70  func (i *filteringIter) Error() error {
    71  	return i.iter.Error()
    72  }
    73  
    74  // Close implements FragmentIterator.
    75  func (i *filteringIter) Close() error {
    76  	return i.iter.Close()
    77  }
    78  
    79  // filter uses the filterFn (if configured) to filter and possibly mutate the
    80  // given Span. If the current Span is to be skipped, the iterator continues
    81  // iterating in the given direction until it lands on a Span that should be
    82  // returned, or the iterator becomes invalid.
    83  func (i *filteringIter) filter(span *Span, dir int8) *Span {
    84  	if i.filterFn == nil {
    85  		return span
    86  	}
    87  	for i.Error() == nil && span != nil {
    88  		if keep := i.filterFn(span, &i.span); keep {
    89  			return &i.span
    90  		}
    91  		if dir == +1 {
    92  			span = i.iter.Next()
    93  		} else {
    94  			span = i.iter.Prev()
    95  		}
    96  	}
    97  	return span
    98  }