github.com/attic-labs/noms@v0.0.0-20210827224422-e5fa29d95e8b/go/types/map.go (about)

     1  // Copyright 2016 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  package types
     6  
     7  import (
     8  	"fmt"
     9  	"sort"
    10  
    11  	"github.com/attic-labs/noms/go/d"
    12  )
    13  
    14  type Map struct {
    15  	orderedSequence
    16  }
    17  
    18  func newMap(seq orderedSequence) Map {
    19  	return Map{seq}
    20  }
    21  
    22  func mapHashValueBytes(item sequenceItem, rv *rollingValueHasher) {
    23  	entry := item.(mapEntry)
    24  	hashValueBytes(entry.key, rv)
    25  	hashValueBytes(entry.value, rv)
    26  }
    27  
    28  func NewMap(vrw ValueReadWriter, kv ...Value) Map {
    29  	entries := buildMapData(kv)
    30  	ch := newEmptyMapSequenceChunker(vrw)
    31  
    32  	for _, entry := range entries {
    33  		ch.Append(entry)
    34  	}
    35  
    36  	return newMap(ch.Done().(orderedSequence))
    37  }
    38  
    39  // NewStreamingMap takes an input channel of values and returns a output
    40  // channel that will produce a finished Map. Values sent to the input channel
    41  // must be alternating keys and values. (e.g. k1, v1, k2, v2...). Moreover keys
    42  // need to be added to the channel in Noms sortorder, adding key values to the
    43  // input channel out of order will result in a panic. Once the input channel is
    44  // closed by the caller, a finished Map will be sent to the output channel. See
    45  // graph_builder.go for building collections with values that are not in order.
    46  func NewStreamingMap(vrw ValueReadWriter, kvs <-chan Value) <-chan Map {
    47  	d.PanicIfTrue(vrw == nil)
    48  	return newStreamingMap(vrw, kvs, func(vrw ValueReadWriter, kvs <-chan Value, outChan chan<- Map) {
    49  		go readMapInput(vrw, kvs, outChan)
    50  	})
    51  }
    52  
    53  type streamingMapReadFunc func(vrw ValueReadWriter, kvs <-chan Value, outChan chan<- Map)
    54  
    55  func newStreamingMap(vrw ValueReadWriter, kvs <-chan Value, readFunc streamingMapReadFunc) <-chan Map {
    56  	outChan := make(chan Map, 1)
    57  	readFunc(vrw, kvs, outChan)
    58  	return outChan
    59  }
    60  
    61  func readMapInput(vrw ValueReadWriter, kvs <-chan Value, outChan chan<- Map) {
    62  	defer close(outChan)
    63  	ch := newEmptyMapSequenceChunker(vrw)
    64  	var lastK Value
    65  	nextIsKey := true
    66  	var k Value
    67  	for v := range kvs {
    68  		d.PanicIfTrue(v == nil)
    69  		if nextIsKey {
    70  			k = v
    71  			d.PanicIfFalse(lastK == nil || lastK.Less(k))
    72  			lastK = k
    73  			nextIsKey = false
    74  			continue
    75  		}
    76  		ch.Append(mapEntry{key: k, value: v})
    77  		nextIsKey = true
    78  	}
    79  	outChan <- newMap(ch.Done().(orderedSequence))
    80  }
    81  
    82  // Diff computes the diff from |last| to |m| using the top-down algorithm,
    83  // which completes as fast as possible while taking longer to return early
    84  // results than left-to-right.
    85  func (m Map) Diff(last Map, changes chan<- ValueChanged, closeChan <-chan struct{}) {
    86  	if m.Equals(last) {
    87  		return
    88  	}
    89  	orderedSequenceDiffTopDown(last.orderedSequence, m.orderedSequence, changes, closeChan)
    90  }
    91  
    92  // DiffHybrid computes the diff from |last| to |m| using a hybrid algorithm
    93  // which balances returning results early vs completing quickly, if possible.
    94  func (m Map) DiffHybrid(last Map, changes chan<- ValueChanged, closeChan <-chan struct{}) {
    95  	if m.Equals(last) {
    96  		return
    97  	}
    98  	orderedSequenceDiffBest(last.orderedSequence, m.orderedSequence, changes, closeChan)
    99  }
   100  
   101  // DiffLeftRight computes the diff from |last| to |m| using a left-to-right
   102  // streaming approach, optimised for returning results early, but not
   103  // completing quickly.
   104  func (m Map) DiffLeftRight(last Map, changes chan<- ValueChanged, closeChan <-chan struct{}) {
   105  	if m.Equals(last) {
   106  		return
   107  	}
   108  	orderedSequenceDiffLeftRight(last.orderedSequence, m.orderedSequence, changes, closeChan)
   109  }
   110  
   111  // Collection interface
   112  
   113  func (m Map) asSequence() sequence {
   114  	return m.orderedSequence
   115  }
   116  
   117  // Value interface
   118  func (m Map) Value() Value {
   119  	return m
   120  }
   121  
   122  func (m Map) WalkValues(cb ValueCallback) {
   123  	iterAll(m, func(v Value, idx uint64) {
   124  		cb(v)
   125  	})
   126  	return
   127  }
   128  
   129  func (m Map) firstOrLast(last bool) (Value, Value) {
   130  	cur := newCursorAt(m.orderedSequence, emptyKey, false, last)
   131  	if !cur.valid() {
   132  		return nil, nil
   133  	}
   134  	entry := cur.current().(mapEntry)
   135  	return entry.key, entry.value
   136  }
   137  
   138  func (m Map) First() (Value, Value) {
   139  	return m.firstOrLast(false)
   140  }
   141  
   142  func (m Map) Last() (Value, Value) {
   143  	return m.firstOrLast(true)
   144  }
   145  
   146  func (m Map) At(idx uint64) (key, value Value) {
   147  	if idx >= m.Len() {
   148  		panic(fmt.Errorf("Out of bounds: %d >= %d", idx, m.Len()))
   149  	}
   150  
   151  	cur := newCursorAtIndex(m.orderedSequence, idx)
   152  	entry := cur.current().(mapEntry)
   153  	return entry.key, entry.value
   154  }
   155  
   156  func (m Map) MaybeGet(key Value) (v Value, ok bool) {
   157  	cur := newCursorAtValue(m.orderedSequence, key, false, false)
   158  	if !cur.valid() {
   159  		return nil, false
   160  	}
   161  	entry := cur.current().(mapEntry)
   162  	if !entry.key.Equals(key) {
   163  		return nil, false
   164  	}
   165  
   166  	return entry.value, true
   167  }
   168  
   169  func (m Map) Has(key Value) bool {
   170  	cur := newCursorAtValue(m.orderedSequence, key, false, false)
   171  	if !cur.valid() {
   172  		return false
   173  	}
   174  	entry := cur.current().(mapEntry)
   175  	return entry.key.Equals(key)
   176  }
   177  
   178  func (m Map) Get(key Value) Value {
   179  	v, _ := m.MaybeGet(key)
   180  	return v
   181  }
   182  
   183  type mapIterCallback func(key, value Value) (stop bool)
   184  
   185  func (m Map) Iter(cb mapIterCallback) {
   186  	cur := newCursorAt(m.orderedSequence, emptyKey, false, false)
   187  	cur.iter(func(v interface{}) bool {
   188  		entry := v.(mapEntry)
   189  		return cb(entry.key, entry.value)
   190  	})
   191  }
   192  
   193  // Any returns true if cb() return true for any of the items in the map.
   194  func (m Map) Any(cb func(k, v Value) bool) (yep bool) {
   195  	m.Iter(func(k, v Value) bool {
   196  		if cb(k, v) {
   197  			yep = true
   198  			return true
   199  		}
   200  		return false
   201  	})
   202  	return
   203  }
   204  
   205  func (m Map) Iterator() *MapIterator {
   206  	return m.IteratorAt(0)
   207  }
   208  
   209  func (m Map) IteratorAt(pos uint64) *MapIterator {
   210  	return &MapIterator{
   211  		cursor: newCursorAtIndex(m.orderedSequence, pos),
   212  	}
   213  }
   214  
   215  func (m Map) IteratorFrom(key Value) *MapIterator {
   216  	return &MapIterator{
   217  		cursor: newCursorAtValue(m.orderedSequence, key, false, false),
   218  	}
   219  }
   220  
   221  type mapIterAllCallback func(key, value Value)
   222  
   223  func (m Map) IterAll(cb mapIterAllCallback) {
   224  	var k Value
   225  	iterAll(m, func(v Value, idx uint64) {
   226  		if k != nil {
   227  			cb(k, v)
   228  			k = nil
   229  		} else {
   230  			k = v
   231  		}
   232  	})
   233  	d.PanicIfFalse(k == nil)
   234  }
   235  
   236  func (m Map) IterFrom(start Value, cb mapIterCallback) {
   237  	cur := newCursorAtValue(m.orderedSequence, start, false, false)
   238  	cur.iter(func(v interface{}) bool {
   239  		entry := v.(mapEntry)
   240  		return cb(entry.key, entry.value)
   241  	})
   242  }
   243  
   244  func (m Map) Edit() *MapEditor {
   245  	return NewMapEditor(m)
   246  }
   247  
   248  func buildMapData(values []Value) mapEntrySlice {
   249  	if len(values) == 0 {
   250  		return mapEntrySlice{}
   251  	}
   252  
   253  	if len(values)%2 != 0 {
   254  		d.Panic("Must specify even number of key/value pairs")
   255  	}
   256  	kvs := make(mapEntrySlice, len(values)/2)
   257  
   258  	for i := 0; i < len(values); i += 2 {
   259  		d.PanicIfTrue(values[i] == nil)
   260  		d.PanicIfTrue(values[i+1] == nil)
   261  		entry := mapEntry{values[i], values[i+1]}
   262  		kvs[i/2] = entry
   263  	}
   264  
   265  	uniqueSorted := make(mapEntrySlice, 0, len(kvs))
   266  	sort.Stable(kvs)
   267  	last := kvs[0]
   268  	for i := 1; i < len(kvs); i++ {
   269  		kv := kvs[i]
   270  		if !kv.key.Equals(last.key) {
   271  			uniqueSorted = append(uniqueSorted, last)
   272  		}
   273  
   274  		last = kv
   275  	}
   276  
   277  	return append(uniqueSorted, last)
   278  }
   279  
   280  func makeMapLeafChunkFn(vrw ValueReadWriter) makeChunkFn {
   281  	return func(level uint64, items []sequenceItem) (Collection, orderedKey, uint64) {
   282  		d.PanicIfFalse(level == 0)
   283  		mapData := make([]mapEntry, len(items), len(items))
   284  
   285  		var lastKey Value
   286  		for i, v := range items {
   287  			entry := v.(mapEntry)
   288  			d.PanicIfFalse(lastKey == nil || lastKey.Less(entry.key))
   289  			lastKey = entry.key
   290  			mapData[i] = entry
   291  		}
   292  
   293  		m := newMap(newMapLeafSequence(vrw, mapData...))
   294  		var key orderedKey
   295  		if len(mapData) > 0 {
   296  			key = newOrderedKey(mapData[len(mapData)-1].key)
   297  		}
   298  		return m, key, uint64(len(items))
   299  	}
   300  }
   301  
   302  func newEmptyMapSequenceChunker(vrw ValueReadWriter) *sequenceChunker {
   303  	return newEmptySequenceChunker(vrw, makeMapLeafChunkFn(vrw), newOrderedMetaSequenceChunkFn(MapKind, vrw), mapHashValueBytes)
   304  }