github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/mapio/merged.go (about)

     1  // Copyright 2018 GRAIL, Inc. All rights reserved.
     2  // Use of this source code is governed by the Apache 2.0
     3  // license that can be found in the LICENSE file.
     4  
     5  package mapio
     6  
     7  import (
     8  	"bytes"
     9  	"container/heap"
    10  )
    11  
    12  var scanSentinel = new(MapScanner)
    13  
    14  // Merged represents the merged contents of multiple underlying maps.
    15  // Like Map, Merged presents a sorted, scannable map, but it does not
    16  // guarantee that the order of traversal is stable.
    17  type Merged []*Map
    18  
    19  // Seek returns a scanner for the merged map that starts at the first
    20  // entry where entryKey <= key.
    21  func (m Merged) Seek(key []byte) *MergedScanner {
    22  	merged := make(MergedScanner, 0, len(m)+1)
    23  	for i := range m {
    24  		s := m[i].Seek(key)
    25  		if !s.Scan() {
    26  			if err := s.Err(); err != nil {
    27  				return &MergedScanner{s}
    28  			}
    29  			// Otherwise it's just empty and we can skip it.
    30  			continue
    31  		}
    32  		merged = append(merged, s)
    33  	}
    34  	if len(merged) == 0 {
    35  		return &MergedScanner{}
    36  	}
    37  	heap.Init(&merged)
    38  	merged = append(merged, scanSentinel)
    39  	return &merged
    40  }
    41  
    42  // MergedScanner is a scanner for merged maps.
    43  type MergedScanner []*MapScanner
    44  
    45  // Len implements heap.Interface
    46  func (m MergedScanner) Len() int { return len(m) }
    47  
    48  // Less implements heap.Interface
    49  func (m MergedScanner) Less(i, j int) bool { return bytes.Compare(m[i].Key(), m[j].Key()) < 0 }
    50  
    51  // Swap implements heap.Interface
    52  func (m MergedScanner) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
    53  
    54  // Push implements heap.Interface
    55  func (m *MergedScanner) Push(x interface{}) {
    56  	*m = append(*m, x.(*MapScanner))
    57  }
    58  
    59  // Pop implements heap.Interface
    60  func (m *MergedScanner) Pop() interface{} {
    61  	n := len(*m)
    62  	elem := (*m)[n-1]
    63  	*m = (*m)[:n-1]
    64  	return elem
    65  }
    66  
    67  // Scan scans the next entry in the merged map, returning true on
    68  // success. If Scan returns false, the caller should check Err to
    69  // distinguish between scan completion and scan error.
    70  func (m *MergedScanner) Scan() bool {
    71  	if len(*m) == 0 || (*m)[0].err != nil {
    72  		return false
    73  	}
    74  	if len(*m) > 0 && (*m)[len(*m)-1] == scanSentinel {
    75  		*m = (*m)[:len(*m)-1]
    76  		return true
    77  	}
    78  
    79  	if (*m)[0].Scan() {
    80  		heap.Fix(m, 0)
    81  	} else if (*m)[0].err == nil {
    82  		heap.Remove(m, 0)
    83  	}
    84  	ok := len(*m) > 0 && (*m)[0].err == nil
    85  	return ok
    86  
    87  }
    88  
    89  // Err returns the last error encountered while scanning, if any.
    90  func (m MergedScanner) Err() error {
    91  	if len(m) == 0 {
    92  		return nil
    93  	}
    94  	return m[0].err
    95  }
    96  
    97  // Key returns the last key scanned.
    98  func (m MergedScanner) Key() []byte {
    99  	return m[0].Key()
   100  }
   101  
   102  // Value returns the last value scanned.
   103  func (m MergedScanner) Value() []byte {
   104  	return m[0].Value()
   105  }