github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/runtime/dict.go (about) 1 // Copyright 2016 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package grumpy 16 17 import ( 18 "bytes" 19 "fmt" 20 "reflect" 21 "sync/atomic" 22 "unsafe" 23 ) 24 25 var ( 26 // DictType is the object representing the Python 'dict' type. 27 DictType = newBasisType("dict", reflect.TypeOf(Dict{}), toDictUnsafe, ObjectType) 28 dictItemIteratorType = newBasisType("dictionary-itemiterator", reflect.TypeOf(dictItemIterator{}), toDictItemIteratorUnsafe, ObjectType) 29 dictKeyIteratorType = newBasisType("dictionary-keyiterator", reflect.TypeOf(dictKeyIterator{}), toDictKeyIteratorUnsafe, ObjectType) 30 dictValueIteratorType = newBasisType("dictionary-valueiterator", reflect.TypeOf(dictValueIterator{}), toDictValueIteratorUnsafe, ObjectType) 31 deletedEntry = &dictEntry{} 32 ) 33 34 const ( 35 // maxDictSize is the largest number of entries a dictionary can hold. 36 // Dict sizes must be a power of two and this is the largest such 37 // number representable as int32. 38 maxDictSize = 1 << 30 39 minDictSize = 8 40 ) 41 42 // dictEntry represents a slot in the hash table of a Dict. Entries are 43 // intended to be immutable so that they can be read atomically. 44 type dictEntry struct { 45 hash int 46 key *Object 47 value *Object 48 } 49 50 // dictTable is the hash table underlying Dict. 51 type dictTable struct { 52 // used is the number of slots in the entries table that contain values. 53 used int32 54 // fill is the number of slots that are used or once were used but have 55 // since been cleared. Thus used <= fill <= len(entries). 56 fill int 57 // entries is a slice of immutable dict entries. Although elements in 58 // the slice will be modified to point to different dictEntry objects 59 // as the dictionary is updated, the slice itself (i.e. location in 60 // memory and size) will not change for the lifetime of a dictTable. 61 // When the table is no longer large enough to hold a dict's contents, 62 // a new dictTable will be created. 63 entries []*dictEntry 64 } 65 66 // newDictTable allocates a table where at least minCapacity entries can be 67 // accommodated. minCapacity must be <= maxDictSize. 68 func newDictTable(minCapacity int) *dictTable { 69 // This takes the given capacity and sets all bits less than the highest bit. 70 // Adding 1 to that value causes the number to become a multiple of 2 again. 71 // The minDictSize is mixed in to make sure the resulting value is at least 72 // that big. This implementation makes the function able to be inlined, as 73 // well as allows for complete evaluation of constants at compile time. 74 numEntries := (minDictSize - 1) | minCapacity 75 numEntries |= numEntries >> 1 76 numEntries |= numEntries >> 2 77 numEntries |= numEntries >> 4 78 numEntries |= numEntries >> 8 79 numEntries |= numEntries >> 16 80 return &dictTable{entries: make([]*dictEntry, numEntries+1)} 81 } 82 83 // loadEntry atomically loads the i'th entry in t and returns it. 84 func (t *dictTable) loadEntry(i int) *dictEntry { 85 p := (*unsafe.Pointer)(unsafe.Pointer(&t.entries[i])) 86 return (*dictEntry)(atomic.LoadPointer(p)) 87 } 88 89 // storeEntry atomically sets the i'th entry in t to entry. 90 func (t *dictTable) storeEntry(i int, entry *dictEntry) { 91 p := (*unsafe.Pointer)(unsafe.Pointer(&t.entries[i])) 92 atomic.StorePointer(p, unsafe.Pointer(entry)) 93 } 94 95 func (t *dictTable) loadUsed() int { 96 return int(atomic.LoadInt32(&t.used)) 97 } 98 99 func (t *dictTable) incUsed(n int) { 100 atomic.AddInt32(&t.used, int32(n)) 101 } 102 103 // insertAbsentEntry adds the populated entry to t assuming that the key 104 // specified in entry is absent from t. Since the key is absent, no key 105 // comparisons are necessary to perform the insert. 106 func (t *dictTable) insertAbsentEntry(entry *dictEntry) { 107 mask := uint(len(t.entries) - 1) 108 i := uint(entry.hash) & mask 109 perturb := uint(entry.hash) 110 index := i 111 // The key we're trying to insert is known to be absent from the dict 112 // so probe for the first nil entry. 113 for ; t.entries[index] != nil; index = i & mask { 114 i, perturb = dictNextIndex(i, perturb) 115 } 116 t.entries[index] = entry 117 t.incUsed(1) 118 t.fill++ 119 } 120 121 // lookupEntry returns the index and entry in t with the given hash and key. 122 // Elements in the table are updated with immutable entries atomically and 123 // lookupEntry loads them atomically. So it is not necessary to lock the dict 124 // to do entry lookups in a consistent way. 125 func (t *dictTable) lookupEntry(f *Frame, hash int, key *Object) (int, *dictEntry, *BaseException) { 126 mask := uint(len(t.entries) - 1) 127 i, perturb := uint(hash)&mask, uint(hash) 128 // free is the first slot that's available. We don't immediately use it 129 // because it has been previously used and therefore an exact match may 130 // be found further on. 131 free := -1 132 var freeEntry *dictEntry 133 index := int(i & mask) 134 entry := t.loadEntry(index) 135 for { 136 if entry == nil { 137 if free != -1 { 138 index = free 139 // Store the entry instead of fetching by index 140 // later since it may have changed by then. 141 entry = freeEntry 142 } 143 break 144 } 145 if entry == deletedEntry { 146 if free == -1 { 147 free = index 148 } 149 } else if entry.hash == hash { 150 o, raised := Eq(f, entry.key, key) 151 if raised != nil { 152 return -1, nil, raised 153 } 154 eq, raised := IsTrue(f, o) 155 if raised != nil { 156 return -1, nil, raised 157 } 158 if eq { 159 break 160 } 161 } 162 i, perturb = dictNextIndex(i, perturb) 163 index = int(i & mask) 164 entry = t.loadEntry(index) 165 } 166 return index, entry, nil 167 } 168 169 // writeEntry replaces t's entry at the given index with entry. If writing 170 // entry would cause t's fill ratio to grow too large then a new table is 171 // created, the entry is instead inserted there and that table is returned. t 172 // remains unchanged. When a sufficiently sized table cannot be created, false 173 // will be returned for the second value, otherwise true will be returned. 174 func (t *dictTable) writeEntry(f *Frame, index int, entry *dictEntry) (*dictTable, bool) { 175 if t.entries[index] == deletedEntry { 176 t.storeEntry(index, entry) 177 t.incUsed(1) 178 return nil, true 179 } 180 if t.entries[index] != nil { 181 t.storeEntry(index, entry) 182 return nil, true 183 } 184 if (t.fill+1)*3 <= len(t.entries)*2 { 185 // New entry does not necessitate growing the table. 186 t.storeEntry(index, entry) 187 t.incUsed(1) 188 t.fill++ 189 return nil, true 190 } 191 // Grow the table. 192 var n int 193 if t.used <= 50000 { 194 n = int(t.used * 4) 195 } else if t.used <= maxDictSize/2 { 196 n = int(t.used * 2) 197 } else { 198 return nil, false 199 } 200 newTable := newDictTable(n) 201 for _, oldEntry := range t.entries { 202 if oldEntry != nil && oldEntry != deletedEntry { 203 newTable.insertAbsentEntry(oldEntry) 204 } 205 } 206 newTable.insertAbsentEntry(entry) 207 return newTable, true 208 } 209 210 // dictEntryIterator is used to iterate over the entries in a dictTable in an 211 // arbitrary order. 212 type dictEntryIterator struct { 213 index int64 214 table *dictTable 215 } 216 217 // newDictEntryIterator creates a dictEntryIterator object for d. It assumes 218 // that d.mutex is held by the caller. 219 func newDictEntryIterator(d *Dict) dictEntryIterator { 220 return dictEntryIterator{table: d.loadTable()} 221 } 222 223 // next advances this iterator to the next occupied entry and returns it. The 224 // second return value is true if the dict changed since iteration began, false 225 // otherwise. 226 func (iter *dictEntryIterator) next() *dictEntry { 227 numEntries := len(iter.table.entries) 228 var entry *dictEntry 229 for entry == nil { 230 // 64bit atomic ops need to be 8 byte aligned. This compile time check 231 // verifies alignment by creating a negative constant for an unsigned type. 232 // See sync/atomic docs for details. 233 const blank = -(unsafe.Offsetof(iter.index) % 8) 234 index := int(atomic.AddInt64(&iter.index, 1)) - 1 235 if index >= numEntries { 236 break 237 } 238 entry = iter.table.loadEntry(index) 239 if entry == deletedEntry { 240 entry = nil 241 } 242 } 243 return entry 244 } 245 246 // dictVersionGuard is used to detect when a dict has been modified. 247 type dictVersionGuard struct { 248 dict *Dict 249 version int64 250 } 251 252 func newDictVersionGuard(d *Dict) dictVersionGuard { 253 return dictVersionGuard{d, d.loadVersion()} 254 } 255 256 // check returns false if the dict held by g has changed since g was created, 257 // true otherwise. 258 func (g *dictVersionGuard) check() bool { 259 return g.dict.loadVersion() == g.version 260 } 261 262 // Dict represents Python 'dict' objects. The public methods of *Dict are 263 // thread safe. 264 type Dict struct { 265 Object 266 table *dictTable 267 // We use a recursive mutex for synchronization because the hash and 268 // key comparison operations may re-enter DelItem/SetItem. 269 mutex recursiveMutex 270 // version is incremented whenever the Dict is modified. See: 271 // https://www.python.org/dev/peps/pep-0509/ 272 version int64 273 } 274 275 // NewDict returns an empty Dict. 276 func NewDict() *Dict { 277 return &Dict{Object: Object{typ: DictType}, table: newDictTable(0)} 278 } 279 280 func newStringDict(items map[string]*Object) *Dict { 281 if len(items) > maxDictSize/2 { 282 panic(fmt.Sprintf("dictionary too big: %d", len(items))) 283 } 284 n := len(items) * 2 285 table := newDictTable(n) 286 for key, value := range items { 287 table.insertAbsentEntry(&dictEntry{hashString(key), NewStr(key).ToObject(), value}) 288 } 289 return &Dict{Object: Object{typ: DictType}, table: table} 290 } 291 292 func toDictUnsafe(o *Object) *Dict { 293 return (*Dict)(o.toPointer()) 294 } 295 296 // loadTable atomically loads and returns d's underlying dictTable. 297 func (d *Dict) loadTable() *dictTable { 298 p := (*unsafe.Pointer)(unsafe.Pointer(&d.table)) 299 return (*dictTable)(atomic.LoadPointer(p)) 300 } 301 302 // storeTable atomically updates d's underlying dictTable to the one given. 303 func (d *Dict) storeTable(table *dictTable) { 304 p := (*unsafe.Pointer)(unsafe.Pointer(&d.table)) 305 atomic.StorePointer(p, unsafe.Pointer(table)) 306 } 307 308 // loadVersion atomically loads and returns d's version. 309 func (d *Dict) loadVersion() int64 { 310 // 64bit atomic ops need to be 8 byte aligned. This compile time check 311 // verifies alignment by creating a negative constant for an unsigned type. 312 // See sync/atomic docs for details. 313 const blank = -(unsafe.Offsetof(d.version) % 8) 314 return atomic.LoadInt64(&d.version) 315 } 316 317 // incVersion atomically increments d's version. 318 func (d *Dict) incVersion() { 319 // 64bit atomic ops need to be 8 byte aligned. This compile time check 320 // verifies alignment by creating a negative constant for an unsigned type. 321 // See sync/atomic docs for details. 322 const blank = -(unsafe.Offsetof(d.version) % 8) 323 atomic.AddInt64(&d.version, 1) 324 } 325 326 // DelItem removes the entry associated with key from d. It returns true if an 327 // item was removed, or false if it did not exist in d. 328 func (d *Dict) DelItem(f *Frame, key *Object) (bool, *BaseException) { 329 originValue, raised := d.putItem(f, key, nil, true) 330 if raised != nil { 331 return false, raised 332 } 333 return originValue != nil, nil 334 } 335 336 // DelItemString removes the entry associated with key from d. It returns true 337 // if an item was removed, or false if it did not exist in d. 338 func (d *Dict) DelItemString(f *Frame, key string) (bool, *BaseException) { 339 return d.DelItem(f, NewStr(key).ToObject()) 340 } 341 342 // GetItem looks up key in d, returning the associated value or nil if key is 343 // not present in d. 344 func (d *Dict) GetItem(f *Frame, key *Object) (*Object, *BaseException) { 345 hash, raised := Hash(f, key) 346 if raised != nil { 347 return nil, raised 348 } 349 _, entry, raised := d.loadTable().lookupEntry(f, hash.Value(), key) 350 if raised != nil { 351 return nil, raised 352 } 353 if entry != nil && entry != deletedEntry { 354 return entry.value, nil 355 } 356 return nil, nil 357 } 358 359 // GetItemString looks up key in d, returning the associated value or nil if 360 // key is not present in d. 361 func (d *Dict) GetItemString(f *Frame, key string) (*Object, *BaseException) { 362 return d.GetItem(f, NewStr(key).ToObject()) 363 } 364 365 // Pop looks up key in d, returning and removing the associalted value if exist, 366 // or nil if key is not present in d. 367 func (d *Dict) Pop(f *Frame, key *Object) (*Object, *BaseException) { 368 return d.putItem(f, key, nil, true) 369 } 370 371 // Keys returns a list containing all the keys in d. 372 func (d *Dict) Keys(f *Frame) *List { 373 d.mutex.Lock(f) 374 keys := make([]*Object, d.Len()) 375 i := 0 376 for _, entry := range d.table.entries { 377 if entry != nil && entry != deletedEntry { 378 keys[i] = entry.key 379 i++ 380 } 381 } 382 d.mutex.Unlock(f) 383 return NewList(keys...) 384 } 385 386 // Len returns the number of entries in d. 387 func (d *Dict) Len() int { 388 return d.loadTable().loadUsed() 389 } 390 391 // putItem associates value with key in d, returning the old associated value if 392 // the key was added, or nil if it was not already present in d. 393 func (d *Dict) putItem(f *Frame, key, value *Object, overwrite bool) (*Object, *BaseException) { 394 hash, raised := Hash(f, key) 395 if raised != nil { 396 return nil, raised 397 } 398 d.mutex.Lock(f) 399 t := d.table 400 v := d.version 401 index, entry, raised := t.lookupEntry(f, hash.Value(), key) 402 var originValue *Object 403 if raised == nil { 404 if v != d.version { 405 // Dictionary was recursively modified. Blow up instead 406 // of trying to recover. 407 raised = f.RaiseType(RuntimeErrorType, "dictionary changed during write") 408 } else { 409 if value == nil { 410 // Going to delete the entry. 411 if entry != nil && entry != deletedEntry { 412 d.table.storeEntry(index, deletedEntry) 413 d.table.incUsed(-1) 414 d.incVersion() 415 } 416 } else if overwrite || entry == nil { 417 newEntry := &dictEntry{hash.Value(), key, value} 418 if newTable, ok := t.writeEntry(f, index, newEntry); ok { 419 if newTable != nil { 420 d.storeTable(newTable) 421 } 422 d.incVersion() 423 } else { 424 raised = f.RaiseType(OverflowErrorType, errResultTooLarge) 425 } 426 } 427 if entry != nil && entry != deletedEntry { 428 originValue = entry.value 429 } 430 } 431 } 432 d.mutex.Unlock(f) 433 return originValue, raised 434 } 435 436 // SetItem associates value with key in d. 437 func (d *Dict) SetItem(f *Frame, key, value *Object) *BaseException { 438 _, raised := d.putItem(f, key, value, true) 439 return raised 440 } 441 442 // SetItemString associates value with key in d. 443 func (d *Dict) SetItemString(f *Frame, key string, value *Object) *BaseException { 444 return d.SetItem(f, NewStr(key).ToObject(), value) 445 } 446 447 // ToObject upcasts d to an Object. 448 func (d *Dict) ToObject() *Object { 449 return &d.Object 450 } 451 452 // Update copies the items from the mapping or sequence of 2-tuples o into d. 453 func (d *Dict) Update(f *Frame, o *Object) (raised *BaseException) { 454 var iter *Object 455 if o.isInstance(DictType) { 456 d2 := toDictUnsafe(o) 457 d2.mutex.Lock(f) 458 // Concurrent modifications to d2 will cause Update to raise 459 // "dictionary changed during iteration". 460 iter = newDictItemIterator(d2).ToObject() 461 d2.mutex.Unlock(f) 462 } else { 463 iter, raised = Iter(f, o) 464 } 465 if raised != nil { 466 return raised 467 } 468 return seqForEach(f, iter, func(item *Object) *BaseException { 469 return seqApply(f, item, func(elems []*Object, _ bool) *BaseException { 470 if numElems := len(elems); numElems != 2 { 471 format := "dictionary update sequence element has length %d; 2 is required" 472 return f.RaiseType(ValueErrorType, fmt.Sprintf(format, numElems)) 473 } 474 return d.SetItem(f, elems[0], elems[1]) 475 }) 476 }) 477 } 478 479 // dictsAreEqual returns true if d1 and d2 have the same keys and values, false 480 // otherwise. If either d1 or d2 are concurrently modified then RuntimeError is 481 // raised. 482 func dictsAreEqual(f *Frame, d1, d2 *Dict) (bool, *BaseException) { 483 if d1 == d2 { 484 return true, nil 485 } 486 // Do not hold both locks at the same time to avoid deadlock. 487 d1.mutex.Lock(f) 488 iter := newDictEntryIterator(d1) 489 g1 := newDictVersionGuard(d1) 490 len1 := d1.Len() 491 d1.mutex.Unlock(f) 492 d2.mutex.Lock(f) 493 g2 := newDictVersionGuard(d1) 494 len2 := d2.Len() 495 d2.mutex.Unlock(f) 496 if len1 != len2 { 497 return false, nil 498 } 499 result := true 500 for entry := iter.next(); entry != nil && result; entry = iter.next() { 501 if v, raised := d2.GetItem(f, entry.key); raised != nil { 502 return false, raised 503 } else if v == nil { 504 result = false 505 } else { 506 eq, raised := Eq(f, entry.value, v) 507 if raised != nil { 508 return false, raised 509 } 510 result, raised = IsTrue(f, eq) 511 if raised != nil { 512 return false, raised 513 } 514 } 515 } 516 if !g1.check() || !g2.check() { 517 return false, f.RaiseType(RuntimeErrorType, "dictionary changed during iteration") 518 } 519 return result, nil 520 } 521 522 func dictClear(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 523 if raised := checkMethodArgs(f, "clear", args, DictType); raised != nil { 524 return nil, raised 525 } 526 d := toDictUnsafe(args[0]) 527 d.mutex.Lock(f) 528 d.table = newDictTable(0) 529 d.incVersion() 530 d.mutex.Unlock(f) 531 return None, nil 532 } 533 534 func dictContains(f *Frame, seq, value *Object) (*Object, *BaseException) { 535 item, raised := toDictUnsafe(seq).GetItem(f, value) 536 if raised != nil { 537 return nil, raised 538 } 539 return GetBool(item != nil).ToObject(), nil 540 } 541 542 func dictCopy(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 543 if raised := checkMethodArgs(f, "copy", args, DictType); raised != nil { 544 return nil, raised 545 } 546 return DictType.Call(f, args, nil) 547 } 548 549 func dictDelItem(f *Frame, o, key *Object) *BaseException { 550 deleted, raised := toDictUnsafe(o).DelItem(f, key) 551 if raised != nil { 552 return raised 553 } 554 if !deleted { 555 return raiseKeyError(f, key) 556 } 557 return nil 558 } 559 560 func dictEq(f *Frame, v, w *Object) (*Object, *BaseException) { 561 if !w.isInstance(DictType) { 562 return NotImplemented, nil 563 } 564 eq, raised := dictsAreEqual(f, toDictUnsafe(v), toDictUnsafe(w)) 565 if raised != nil { 566 return nil, raised 567 } 568 return GetBool(eq).ToObject(), nil 569 } 570 571 func dictGet(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 572 expectedTypes := []*Type{DictType, ObjectType, ObjectType} 573 argc := len(args) 574 if argc == 2 { 575 expectedTypes = expectedTypes[:2] 576 } 577 if raised := checkMethodArgs(f, "get", args, expectedTypes...); raised != nil { 578 return nil, raised 579 } 580 item, raised := toDictUnsafe(args[0]).GetItem(f, args[1]) 581 if raised == nil && item == nil { 582 item = None 583 if argc > 2 { 584 item = args[2] 585 } 586 } 587 return item, raised 588 } 589 590 func dictHasKey(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 591 if raised := checkMethodArgs(f, "has_key", args, DictType, ObjectType); raised != nil { 592 return nil, raised 593 } 594 return dictContains(f, args[0], args[1]) 595 } 596 597 func dictItems(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 598 if raised := checkMethodArgs(f, "items", args, DictType); raised != nil { 599 return nil, raised 600 } 601 d := toDictUnsafe(args[0]) 602 d.mutex.Lock(f) 603 iter := newDictItemIterator(d).ToObject() 604 d.mutex.Unlock(f) 605 return ListType.Call(f, Args{iter}, nil) 606 } 607 608 func dictIterItems(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 609 if raised := checkMethodArgs(f, "iteritems", args, DictType); raised != nil { 610 return nil, raised 611 } 612 d := toDictUnsafe(args[0]) 613 d.mutex.Lock(f) 614 iter := newDictItemIterator(d).ToObject() 615 d.mutex.Unlock(f) 616 return iter, nil 617 } 618 619 func dictIterKeys(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 620 if raised := checkMethodArgs(f, "iterkeys", args, DictType); raised != nil { 621 return nil, raised 622 } 623 return dictIter(f, args[0]) 624 } 625 626 func dictIterValues(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 627 if raised := checkMethodArgs(f, "itervalues", args, DictType); raised != nil { 628 return nil, raised 629 } 630 d := toDictUnsafe(args[0]) 631 d.mutex.Lock(f) 632 iter := newDictValueIterator(d).ToObject() 633 d.mutex.Unlock(f) 634 return iter, nil 635 } 636 637 func dictKeys(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 638 if raised := checkMethodArgs(f, "keys", args, DictType); raised != nil { 639 return nil, raised 640 } 641 return toDictUnsafe(args[0]).Keys(f).ToObject(), nil 642 } 643 644 func dictGetItem(f *Frame, o, key *Object) (*Object, *BaseException) { 645 item, raised := toDictUnsafe(o).GetItem(f, key) 646 if raised != nil { 647 return nil, raised 648 } 649 if item == nil { 650 return nil, raiseKeyError(f, key) 651 } 652 return item, nil 653 } 654 655 func dictInit(f *Frame, o *Object, args Args, kwargs KWArgs) (*Object, *BaseException) { 656 var expectedTypes []*Type 657 argc := len(args) 658 if argc > 0 { 659 expectedTypes = []*Type{ObjectType} 660 } 661 if raised := checkFunctionArgs(f, "__init__", args, expectedTypes...); raised != nil { 662 return nil, raised 663 } 664 d := toDictUnsafe(o) 665 if argc > 0 { 666 if raised := d.Update(f, args[0]); raised != nil { 667 return nil, raised 668 } 669 } 670 for _, kwarg := range kwargs { 671 if raised := d.SetItemString(f, kwarg.Name, kwarg.Value); raised != nil { 672 return nil, raised 673 } 674 } 675 return None, nil 676 } 677 678 func dictIter(f *Frame, o *Object) (*Object, *BaseException) { 679 d := toDictUnsafe(o) 680 d.mutex.Lock(f) 681 iter := newDictKeyIterator(d).ToObject() 682 d.mutex.Unlock(f) 683 return iter, nil 684 } 685 686 func dictLen(f *Frame, o *Object) (*Object, *BaseException) { 687 d := toDictUnsafe(o) 688 ret := NewInt(d.Len()).ToObject() 689 return ret, nil 690 } 691 692 func dictNE(f *Frame, v, w *Object) (*Object, *BaseException) { 693 if !w.isInstance(DictType) { 694 return NotImplemented, nil 695 } 696 eq, raised := dictsAreEqual(f, toDictUnsafe(v), toDictUnsafe(w)) 697 if raised != nil { 698 return nil, raised 699 } 700 return GetBool(!eq).ToObject(), nil 701 } 702 703 func dictNew(f *Frame, t *Type, _ Args, _ KWArgs) (*Object, *BaseException) { 704 d := toDictUnsafe(newObject(t)) 705 d.table = &dictTable{entries: make([]*dictEntry, minDictSize, minDictSize)} 706 return d.ToObject(), nil 707 } 708 709 func dictPop(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 710 expectedTypes := []*Type{DictType, ObjectType, ObjectType} 711 argc := len(args) 712 if argc == 2 { 713 expectedTypes = expectedTypes[:2] 714 } 715 if raised := checkMethodArgs(f, "pop", args, expectedTypes...); raised != nil { 716 return nil, raised 717 } 718 key := args[1] 719 d := toDictUnsafe(args[0]) 720 item, raised := d.Pop(f, key) 721 if raised == nil && item == nil { 722 if argc > 2 { 723 item = args[2] 724 } else { 725 raised = raiseKeyError(f, key) 726 } 727 } 728 return item, raised 729 } 730 731 func dictPopItem(f *Frame, args Args, _ KWArgs) (item *Object, raised *BaseException) { 732 if raised := checkMethodArgs(f, "popitem", args, DictType); raised != nil { 733 return nil, raised 734 } 735 d := toDictUnsafe(args[0]) 736 d.mutex.Lock(f) 737 iter := newDictEntryIterator(d) 738 entry := iter.next() 739 if entry == nil { 740 raised = f.RaiseType(KeyErrorType, "popitem(): dictionary is empty") 741 } else { 742 item = NewTuple(entry.key, entry.value).ToObject() 743 d.table.storeEntry(int(iter.index-1), deletedEntry) 744 d.table.incUsed(-1) 745 d.incVersion() 746 } 747 d.mutex.Unlock(f) 748 return item, raised 749 } 750 751 func dictRepr(f *Frame, o *Object) (*Object, *BaseException) { 752 d := toDictUnsafe(o) 753 if f.reprEnter(d.ToObject()) { 754 return NewStr("{...}").ToObject(), nil 755 } 756 defer f.reprLeave(d.ToObject()) 757 // Lock d so that we get a consistent view of it. Otherwise we may 758 // return a state that d was never actually in. 759 d.mutex.Lock(f) 760 defer d.mutex.Unlock(f) 761 var buf bytes.Buffer 762 buf.WriteString("{") 763 iter := newDictEntryIterator(d) 764 i := 0 765 for entry := iter.next(); entry != nil; entry = iter.next() { 766 if i > 0 { 767 buf.WriteString(", ") 768 } 769 s, raised := Repr(f, entry.key) 770 if raised != nil { 771 return nil, raised 772 } 773 buf.WriteString(s.Value()) 774 buf.WriteString(": ") 775 if s, raised = Repr(f, entry.value); raised != nil { 776 return nil, raised 777 } 778 buf.WriteString(s.Value()) 779 i++ 780 } 781 buf.WriteString("}") 782 return NewStr(buf.String()).ToObject(), nil 783 } 784 785 func dictSetDefault(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 786 argc := len(args) 787 if argc == 1 { 788 return nil, f.RaiseType(TypeErrorType, "setdefault expected at least 1 arguments, got 0") 789 } 790 if argc > 3 { 791 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("setdefault expected at most 2 arguments, got %v", argc-1)) 792 } 793 expectedTypes := []*Type{DictType, ObjectType, ObjectType} 794 if argc == 2 { 795 expectedTypes = expectedTypes[:2] 796 } 797 if raised := checkMethodArgs(f, "setdefault", args, expectedTypes...); raised != nil { 798 return nil, raised 799 } 800 d := toDictUnsafe(args[0]) 801 key := args[1] 802 var value *Object 803 if argc > 2 { 804 value = args[2] 805 } else { 806 value = None 807 } 808 originValue, raised := d.putItem(f, key, value, false) 809 if originValue != nil { 810 return originValue, raised 811 } 812 return value, raised 813 } 814 815 func dictSetItem(f *Frame, o, key, value *Object) *BaseException { 816 return toDictUnsafe(o).SetItem(f, key, value) 817 } 818 819 func dictUpdate(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 820 expectedTypes := []*Type{DictType, ObjectType} 821 argc := len(args) 822 if argc == 1 { 823 expectedTypes = expectedTypes[:1] 824 } 825 if raised := checkMethodArgs(f, "update", args, expectedTypes...); raised != nil { 826 return nil, raised 827 } 828 d := toDictUnsafe(args[0]) 829 if argc > 1 { 830 if raised := d.Update(f, args[1]); raised != nil { 831 return nil, raised 832 } 833 } 834 for _, kwarg := range kwargs { 835 if raised := d.SetItemString(f, kwarg.Name, kwarg.Value); raised != nil { 836 return nil, raised 837 } 838 } 839 return None, nil 840 } 841 842 func dictValues(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 843 if raised := checkMethodArgs(f, "values", args, DictType); raised != nil { 844 return nil, raised 845 } 846 iter, raised := dictIterValues(f, args, nil) 847 if raised != nil { 848 return nil, raised 849 } 850 return ListType.Call(f, Args{iter}, nil) 851 } 852 853 func initDictType(dict map[string]*Object) { 854 dict["clear"] = newBuiltinFunction("clear", dictClear).ToObject() 855 dict["copy"] = newBuiltinFunction("copy", dictCopy).ToObject() 856 dict["get"] = newBuiltinFunction("get", dictGet).ToObject() 857 dict["has_key"] = newBuiltinFunction("has_key", dictHasKey).ToObject() 858 dict["items"] = newBuiltinFunction("items", dictItems).ToObject() 859 dict["iteritems"] = newBuiltinFunction("iteritems", dictIterItems).ToObject() 860 dict["iterkeys"] = newBuiltinFunction("iterkeys", dictIterKeys).ToObject() 861 dict["itervalues"] = newBuiltinFunction("itervalues", dictIterValues).ToObject() 862 dict["keys"] = newBuiltinFunction("keys", dictKeys).ToObject() 863 dict["pop"] = newBuiltinFunction("pop", dictPop).ToObject() 864 dict["popitem"] = newBuiltinFunction("popitem", dictPopItem).ToObject() 865 dict["setdefault"] = newBuiltinFunction("setdefault", dictSetDefault).ToObject() 866 dict["update"] = newBuiltinFunction("update", dictUpdate).ToObject() 867 dict["values"] = newBuiltinFunction("values", dictValues).ToObject() 868 DictType.slots.Contains = &binaryOpSlot{dictContains} 869 DictType.slots.DelItem = &delItemSlot{dictDelItem} 870 DictType.slots.Eq = &binaryOpSlot{dictEq} 871 DictType.slots.GetItem = &binaryOpSlot{dictGetItem} 872 DictType.slots.Hash = &unaryOpSlot{hashNotImplemented} 873 DictType.slots.Init = &initSlot{dictInit} 874 DictType.slots.Iter = &unaryOpSlot{dictIter} 875 DictType.slots.Len = &unaryOpSlot{dictLen} 876 DictType.slots.NE = &binaryOpSlot{dictNE} 877 DictType.slots.New = &newSlot{dictNew} 878 DictType.slots.Repr = &unaryOpSlot{dictRepr} 879 DictType.slots.SetItem = &setItemSlot{dictSetItem} 880 } 881 882 type dictItemIterator struct { 883 Object 884 iter dictEntryIterator 885 guard dictVersionGuard 886 } 887 888 // newDictItemIterator creates a dictItemIterator object for d. It assumes that 889 // d.mutex is held by the caller. 890 func newDictItemIterator(d *Dict) *dictItemIterator { 891 return &dictItemIterator{ 892 Object: Object{typ: dictItemIteratorType}, 893 iter: newDictEntryIterator(d), 894 guard: newDictVersionGuard(d), 895 } 896 } 897 898 func toDictItemIteratorUnsafe(o *Object) *dictItemIterator { 899 return (*dictItemIterator)(o.toPointer()) 900 } 901 902 func (iter *dictItemIterator) ToObject() *Object { 903 return &iter.Object 904 } 905 906 func dictItemIteratorIter(f *Frame, o *Object) (*Object, *BaseException) { 907 return o, nil 908 } 909 910 func dictItemIteratorNext(f *Frame, o *Object) (ret *Object, raised *BaseException) { 911 iter := toDictItemIteratorUnsafe(o) 912 entry, raised := dictIteratorNext(f, &iter.iter, &iter.guard) 913 if raised != nil { 914 return nil, raised 915 } 916 return NewTuple2(entry.key, entry.value).ToObject(), nil 917 } 918 919 func initDictItemIteratorType(map[string]*Object) { 920 dictItemIteratorType.flags &^= typeFlagBasetype | typeFlagInstantiable 921 dictItemIteratorType.slots.Iter = &unaryOpSlot{dictItemIteratorIter} 922 dictItemIteratorType.slots.Next = &unaryOpSlot{dictItemIteratorNext} 923 } 924 925 type dictKeyIterator struct { 926 Object 927 iter dictEntryIterator 928 guard dictVersionGuard 929 } 930 931 // newDictKeyIterator creates a dictKeyIterator object for d. It assumes that 932 // d.mutex is held by the caller. 933 func newDictKeyIterator(d *Dict) *dictKeyIterator { 934 return &dictKeyIterator{ 935 Object: Object{typ: dictKeyIteratorType}, 936 iter: newDictEntryIterator(d), 937 guard: newDictVersionGuard(d), 938 } 939 } 940 941 func toDictKeyIteratorUnsafe(o *Object) *dictKeyIterator { 942 return (*dictKeyIterator)(o.toPointer()) 943 } 944 945 func (iter *dictKeyIterator) ToObject() *Object { 946 return &iter.Object 947 } 948 949 func dictKeyIteratorIter(f *Frame, o *Object) (*Object, *BaseException) { 950 return o, nil 951 } 952 953 func dictKeyIteratorNext(f *Frame, o *Object) (*Object, *BaseException) { 954 iter := toDictKeyIteratorUnsafe(o) 955 entry, raised := dictIteratorNext(f, &iter.iter, &iter.guard) 956 if raised != nil { 957 return nil, raised 958 } 959 return entry.key, nil 960 } 961 962 func initDictKeyIteratorType(map[string]*Object) { 963 dictKeyIteratorType.flags &^= typeFlagBasetype | typeFlagInstantiable 964 dictKeyIteratorType.slots.Iter = &unaryOpSlot{dictKeyIteratorIter} 965 dictKeyIteratorType.slots.Next = &unaryOpSlot{dictKeyIteratorNext} 966 } 967 968 type dictValueIterator struct { 969 Object 970 iter dictEntryIterator 971 guard dictVersionGuard 972 } 973 974 // newDictValueIterator creates a dictValueIterator object for d. It assumes 975 // that d.mutex is held by the caller. 976 func newDictValueIterator(d *Dict) *dictValueIterator { 977 return &dictValueIterator{ 978 Object: Object{typ: dictValueIteratorType}, 979 iter: newDictEntryIterator(d), 980 guard: newDictVersionGuard(d), 981 } 982 } 983 984 func toDictValueIteratorUnsafe(o *Object) *dictValueIterator { 985 return (*dictValueIterator)(o.toPointer()) 986 } 987 988 func (iter *dictValueIterator) ToObject() *Object { 989 return &iter.Object 990 } 991 992 func dictValueIteratorIter(f *Frame, o *Object) (*Object, *BaseException) { 993 return o, nil 994 } 995 996 func dictValueIteratorNext(f *Frame, o *Object) (*Object, *BaseException) { 997 iter := toDictValueIteratorUnsafe(o) 998 entry, raised := dictIteratorNext(f, &iter.iter, &iter.guard) 999 if raised != nil { 1000 return nil, raised 1001 } 1002 return entry.value, nil 1003 } 1004 1005 func initDictValueIteratorType(map[string]*Object) { 1006 dictValueIteratorType.flags &^= typeFlagBasetype | typeFlagInstantiable 1007 dictValueIteratorType.slots.Iter = &unaryOpSlot{dictValueIteratorIter} 1008 dictValueIteratorType.slots.Next = &unaryOpSlot{dictValueIteratorNext} 1009 } 1010 1011 func raiseKeyError(f *Frame, key *Object) *BaseException { 1012 s, raised := ToStr(f, key) 1013 if raised == nil { 1014 raised = f.RaiseType(KeyErrorType, s.Value()) 1015 } 1016 return raised 1017 } 1018 1019 func dictNextIndex(i, perturb uint) (uint, uint) { 1020 return (i << 2) + i + perturb + 1, perturb >> 5 1021 } 1022 1023 func dictIteratorNext(f *Frame, iter *dictEntryIterator, guard *dictVersionGuard) (*dictEntry, *BaseException) { 1024 // NOTE: The behavior here diverges from CPython where an iterator that 1025 // is exhausted will always return StopIteration regardless whether the 1026 // underlying dict is subsequently modified. In Grumpy, an iterator for 1027 // a dict that has been modified will always raise RuntimeError even if 1028 // the iterator was exhausted before the modification. 1029 entry := iter.next() 1030 if !guard.check() { 1031 return nil, f.RaiseType(RuntimeErrorType, "dictionary changed during iteration") 1032 } 1033 if entry == nil { 1034 return nil, f.Raise(StopIterationType.ToObject(), nil, nil) 1035 } 1036 return entry, nil 1037 }