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 }