Skip to content

Commit

Permalink
segment.Set API improvements.
Browse files Browse the repository at this point in the history
- Replace Add with TryInsertRange; for symmetry with RemoveRange, to establish
  the convention that *Range methods perform an implicit search in the set, and
  so that we can fork InsertRange which has Insert-like semantics (panics on
  conflict), which the majority of callers want.

- Rename MergeRange and MergeAdjacent to MergeInsideRange and MergeOutsideRange
  respectively; for the same convention, and to more clearly describe the
  difference between these functions.

- Add MergePrev and MergeNext. These solve the longstanding problem of
  requiring a separate call to Merge{Inside,Outside}Range (which will perform
  additional searches) after mutating a set in a relatively simple manner.

- Add SplitBefore and SplitAfter, which are halves of Isolate. These are
  slightly preferable to Isolate in many use cases for the latter (when
  iterating segments within a range, only the first segment can include a key
  before the start, so this saves some useless comparisons in almost every
  iteration of such loops), and are useful in some more complex algorithms.
  Also add LowerBoundSegmentSplitBefore and UpperBoundSegmentSplitAfter as
  ergonomic aids for the former use case.

- Add {Visit,Mutate}[Full]Range, which are convenience wrappers around the
  iterator API (including new functions) for simple use cases (and hence also
  serve to demonstrate how the new iterator functions are used).
  MutateFullRange in particular replaces ApplyContiguous and adds merging
  during iteration.

- Add RemoveFullRange, which (analogous to {Visit,Mutate}FullRange) is a
  variant of RemoveRange that checks that the range is fully covered by
  segments.

- Add Unisolate, which combines MergePrev and MergeNext in the same way that
  Isolate combines SplitBefore and SplitAfter. This is useful for merging after
  mutation of a single segment.

- Add {First,Last,LowerBound,UpperBound}LargeEnoughGap, which are convenient
  loop starters when using gap tracking.

- Replace SegmentDataSlices with FlatSegment, which is easier to use when
  specifying "set literals" (as in tests).

- Make {prev,next}LargeEnoughGapHelper iterative rather than tail-recursive.

- Slightly optimize Iterator.{Prev,Next}NonEmpty: GapIterator.{Start,End} needs
  to find the corresponding Iterator, so call Iterator.{Prev,Next}Segment
  directly rather than doing so twice.

PiperOrigin-RevId: 583506148
  • Loading branch information
nixprime authored and gvisor-bot committed Nov 17, 2023
1 parent 2ef56fe commit 88d35cd
Show file tree
Hide file tree
Showing 16 changed files with 768 additions and 490 deletions.
668 changes: 507 additions & 161 deletions pkg/segment/set.go

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions pkg/segment/set_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@

package segment

func (s *Set) saveRoot() *SegmentDataSlices {
return s.ExportSortedSlices()
func (s *Set) saveRoot() []FlatSegment {
fs := s.ExportSlice()
// The state package saves data in slice capacity beyond slice length; save
// it some time by cutting ours off.
fs = fs[:len(fs):len(fs)]
return fs
}

func (s *Set) loadRoot(sds *SegmentDataSlices) {
if err := s.ImportSortedSlices(sds); err != nil {
func (s *Set) loadRoot(fs []FlatSegment) {
if err := s.ImportSlice(fs); err != nil {
panic(err)
}
}
Loading

0 comments on commit 88d35cd

Please sign in to comment.