this repo has no description
at trunk 1303 lines 47 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "dict-builtins.h" 3 4#include "builtins.h" 5#include "frame.h" 6#include "globals.h" 7#include "int-builtins.h" 8#include "interpreter.h" 9#include "objects.h" 10#include "runtime.h" 11#include "str-builtins.h" 12#include "thread.h" 13#include "type-builtins.h" 14#include "utils.h" 15 16namespace py { 17 18namespace { 19 20// Helper functions for accessing sparse array from dict.indices(). 21static const uint32_t kTombstoneValue = 0xFFFFFFFE; 22static const uint32_t kEmptyValue = 0xFFFFFFFF; 23static const word kNumBytesExponent = 2; 24 25static word probeBegin(word num_indices, word hash, word* indices_mask, 26 uword* perturb) { 27 DCHECK(Utils::isPowerOfTwo(num_indices), "%ld is not a power of 2", 28 num_indices); 29 DCHECK(num_indices > 0, "indicesxs size <= 0"); 30 DCHECK(RawSmallInt::isValid(hash), "hash out of range"); 31 *perturb = static_cast<uword>(hash); 32 *indices_mask = num_indices - 1; 33 return *indices_mask & hash; 34} 35 36static word probeNext(word current, word indices_mask, uword* perturb) { 37 // Given that current stands for the index into dict.indices, this advances 38 // current to (5 * current + 1 + perturb). Note that it's guaranteed that 39 // keeping calling this function returns a permutation of all indices when 40 // the number of the indices is power of two. See 41 // https://en.wikipedia.org/wiki/Linear_congruential_generator#c_%E2%89%A0_0. 42 *perturb >>= 5; 43 return (current * 5 + 1 + *perturb) & indices_mask; 44} 45 46// Returns the bytes offset into the indices array given an index 47static word indexOffset(word index) { return index << kNumBytesExponent; } 48 49// Return the item index stored at indices[bytes_offset]. 50static uint32_t itemIndexAt(RawMutableBytes indices, word bytes_offset) { 51 DCHECK(bytes_offset % 4 == 0, "bytes_offset must be a multiple of 4"); 52 return indices.uint32At(bytes_offset); 53} 54 55// Set `item_index` at indices[bytes_offset]. 56static void itemIndexAtPut(RawMutableBytes indices, word bytes_offset, 57 uint32_t item_index) { 58 indices.uint32AtPut(bytes_offset, item_index); 59} 60 61// Set a tombstone at indices[bytes_offset] given `data_length` from 62// data.length(). 63static void indicesSetTombstone(RawMutableBytes indices, word bytes_offset) { 64 itemIndexAtPut(indices, bytes_offset, kTombstoneValue); 65} 66 67// Return true if the indices[bytes_offset] is filled with an active item. 68static bool indicesIsFull(RawMutableBytes indices, word bytes_offset, 69 uint32_t* item_index) { 70 *item_index = itemIndexAt(indices, bytes_offset); 71 return *item_index < kTombstoneValue; 72} 73 74// Return true if the indices[bytes_offset] is never used. 75static bool indicesIsEmpty(RawMutableBytes indices, word bytes_offset) { 76 return itemIndexAt(indices, bytes_offset) == kEmptyValue; 77} 78 79// Helper functions for accessing dict items from dict.data(). 80 81// Data tuple Layout. 82static const word kItemHashOffset = 0; 83static const word kItemKeyOffset = 1; 84static const word kItemValueOffset = 2; 85static const word kItemNumPointers = 3; 86 87static RawObject itemKey(RawMutableTuple data, word index) { 88 return data.at(index + kItemKeyOffset); 89} 90 91static RawObject itemValue(RawMutableTuple data, word index) { 92 return data.at(index + kItemValueOffset); 93} 94 95static word itemHash(RawMutableTuple data, word index) { 96 return SmallInt::cast(data.at(index + kItemHashOffset)).value(); 97} 98 99static RawObject itemHashRaw(RawMutableTuple data, word index) { 100 return data.at(index + kItemHashOffset); 101} 102 103static void itemSet(RawMutableTuple data, word index, word hash, RawObject key, 104 RawObject value) { 105 data.atPut(index + kItemHashOffset, SmallInt::fromWordTruncated(hash)); 106 data.atPut(index + kItemKeyOffset, key); 107 data.atPut(index + kItemValueOffset, value); 108} 109 110static void itemSetTombstone(RawMutableTuple data, word index) { 111 data.atPut(index + kItemHashOffset, Unbound::object()); 112 data.atPut(index + kItemKeyOffset, NoneType::object()); 113 data.atPut(index + kItemValueOffset, NoneType::object()); 114} 115 116static void itemSetValue(RawMutableTuple data, word index, RawObject value) { 117 data.atPut(index + kItemValueOffset, value); 118} 119 120static bool itemIsEmpty(RawMutableTuple data, word index) { 121 return data.at(index + kItemHashOffset).isNoneType(); 122} 123 124static bool itemIsFull(RawMutableTuple data, word index) { 125 return data.at(index + kItemHashOffset).isSmallInt(); 126} 127 128static bool itemIsTombstone(RawMutableTuple data, word index) { 129 return data.at(index + kItemHashOffset).isUnbound(); 130} 131 132} // namespace 133 134// Returns one of the three possible values: 135// - `key` was found at indices[bytes_offset] : SmallInt::fromWord(bytes_offset) 136// - `key` was not found : SmallInt::fromWord(-1) 137// - Exception that was raised from key comparison __eq__ function. 138static RawObject dictLookup(Thread* thread, const MutableTuple& data, 139 MutableBytes& indices, word num_indices, 140 const Object& key, word hash) { 141 DCHECK(data.length() > 0, "data shouldn't be empty"); 142 uword perturb; 143 word indices_mask; 144 RawSmallInt hash_int = SmallInt::fromWord(hash); 145 for (word current_index = 146 probeBegin(num_indices, hash, &indices_mask, &perturb); 147 ; current_index = probeNext(current_index, indices_mask, &perturb)) { 148 word bytes_offset = indexOffset(current_index); 149 uint32_t item_index; 150 if (indicesIsFull(*indices, bytes_offset, &item_index)) { 151 if (itemHashRaw(*data, item_index) == hash_int) { 152 RawObject eq = 153 Runtime::objectEquals(thread, itemKey(*data, item_index), *key); 154 if (eq == Bool::trueObj()) { 155 return SmallInt::fromWord(bytes_offset); 156 } 157 if (UNLIKELY(eq.isErrorException())) { 158 return eq; 159 } 160 } 161 continue; 162 } 163 if (indicesIsEmpty(*indices, bytes_offset)) { 164 return SmallInt::fromWord(-1); 165 } 166 } 167 UNREACHABLE("Expected to have found an empty index"); 168} 169 170// Returns one of the three possible values: 171// - `key` was found at indices[bytes_offset] : SmallInt::fromWord(bytes_offset) 172// - `key` was not found, but insertion can be done to indices[bytes_offset] : 173// SmallInt::fromWord(bytes_offset - data.length()) 174// - Exception that was raised from key comparison __eq__ function. 175static RawObject dictLookupForInsertion(Thread* thread, 176 const MutableTuple& data, 177 MutableBytes& indices, word num_indices, 178 const Object& key, word hash) { 179 DCHECK(data.length() > 0, "data shouldn't be empty"); 180 word next_free_index = -1; 181 uword perturb; 182 word indices_mask; 183 RawSmallInt hash_int = SmallInt::fromWord(hash); 184 for (word current_index = 185 probeBegin(num_indices, hash, &indices_mask, &perturb); 186 ; current_index = probeNext(current_index, indices_mask, &perturb)) { 187 word bytes_offset = indexOffset(current_index); 188 uint32_t item_index; 189 if (indicesIsFull(*indices, bytes_offset, &item_index)) { 190 if (itemHashRaw(*data, item_index) == hash_int) { 191 RawObject eq = 192 Runtime::objectEquals(thread, itemKey(*data, item_index), *key); 193 if (eq == Bool::trueObj()) { 194 return SmallInt::fromWord(bytes_offset); 195 } 196 if (UNLIKELY(eq.isErrorException())) { 197 return eq; 198 } 199 } 200 continue; 201 } 202 if (next_free_index == -1) { 203 next_free_index = bytes_offset; 204 } 205 if (indicesIsEmpty(*indices, bytes_offset)) { 206 return SmallInt::fromWord(next_free_index - indexOffset(num_indices)); 207 } 208 } 209 UNREACHABLE("Expected to have found an empty index"); 210} 211 212static word nextItemIndex(RawObject data, word* index, word end) { 213 for (word i = *index; i < end; i += kItemNumPointers) { 214 if (!itemIsFull(MutableTuple::cast(data), i)) continue; 215 *index = i + kItemNumPointers; 216 return i; 217 } 218 return -1; 219} 220 221bool dictNextItem(const Dict& dict, word* index, Object* key_out, 222 Object* value_out) { 223 RawObject data = dict.data(); 224 word next_item_index = nextItemIndex(data, index, dict.firstEmptyItemIndex()); 225 if (next_item_index < 0) { 226 return false; 227 } 228 *key_out = itemKey(MutableTuple::cast(data), next_item_index); 229 *value_out = itemValue(MutableTuple::cast(data), next_item_index); 230 return true; 231} 232 233bool dictNextItemHash(const Dict& dict, word* index, Object* key_out, 234 Object* value_out, word* hash_out) { 235 RawObject data = dict.data(); 236 word next_item_index = nextItemIndex(data, index, dict.firstEmptyItemIndex()); 237 if (next_item_index < 0) { 238 return false; 239 } 240 *key_out = itemKey(MutableTuple::cast(data), next_item_index); 241 *value_out = itemValue(MutableTuple::cast(data), next_item_index); 242 *hash_out = itemHash(MutableTuple::cast(data), next_item_index); 243 return true; 244} 245 246bool dictNextKey(const Dict& dict, word* index, Object* key_out) { 247 RawObject data = dict.data(); 248 word next_item_index = nextItemIndex(data, index, dict.firstEmptyItemIndex()); 249 if (next_item_index < 0) { 250 return false; 251 } 252 *key_out = itemKey(MutableTuple::cast(data), next_item_index); 253 return true; 254} 255 256bool dictNextKeyHash(const Dict& dict, word* index, Object* key_out, 257 word* hash_out) { 258 RawObject data = dict.data(); 259 word next_item_index = nextItemIndex(data, index, dict.firstEmptyItemIndex()); 260 if (next_item_index < 0) { 261 return false; 262 } 263 *key_out = itemKey(MutableTuple::cast(data), next_item_index); 264 *hash_out = itemHash(MutableTuple::cast(data), next_item_index); 265 return true; 266} 267 268bool dictNextValue(const Dict& dict, word* index, Object* value_out) { 269 RawObject data = dict.data(); 270 word next_item_index = nextItemIndex(data, index, dict.firstEmptyItemIndex()); 271 if (next_item_index < 0) { 272 return false; 273 } 274 *value_out = itemValue(MutableTuple::cast(data), next_item_index); 275 return true; 276} 277 278static word sizeOfDataTuple(word num_indices) { return (num_indices * 2) / 3; } 279 280static const word kDictGrowthFactor = 2; 281// Initial size of the dict. According to comments in CPython's 282// dictobject.c this accommodates the majority of dictionaries without needing 283// a resize (obviously this depends on the load factor used to resize the 284// dict). 285static const word kInitialDictIndicesLength = 8; 286 287void dictAllocateArrays(Thread* thread, const Dict& dict, word num_indices) { 288 num_indices = Utils::maximum(num_indices, kInitialDictIndicesLength); 289 DCHECK(Utils::isPowerOfTwo(num_indices), "%ld is not a power of 2", 290 num_indices); 291 Runtime* runtime = thread->runtime(); 292 dict.setData(runtime->newMutableTuple(sizeOfDataTuple(num_indices) * 293 kItemNumPointers)); 294 MutableTuple::cast(dict.data()).fill(NoneType::object()); 295 dict.setIndices( 296 runtime->mutableBytesWith(indexOffset(num_indices), kMaxByte)); 297 dict.setFirstEmptyItemIndex(0); 298} 299 300// Return true if `dict` has an available item for insertion. 301static bool dictHasUsableItem(const Dict& dict) { 302 return dict.firstEmptyItemIndex() < 303 RawMutableTuple::cast(dict.data()).length(); 304} 305 306// Insert `key`/`value` into dictionary assuming no item with an equivalent 307// key and no tombstones exist. 308static void dictInsertNoUpdate(const MutableTuple& data, 309 const MutableBytes& indices, word num_indices, 310 word item_count, const Object& key, word hash, 311 const Object& value) { 312 DCHECK(data.length() > 0, "dict must not be empty"); 313 uword perturb; 314 word indices_mask; 315 for (word current_index = 316 probeBegin(num_indices, hash, &indices_mask, &perturb); 317 ; current_index = probeNext(current_index, indices_mask, &perturb)) { 318 word bytes_offset = indexOffset(current_index); 319 if (indicesIsEmpty(*indices, bytes_offset)) { 320 uint32_t item_index = item_count * kItemNumPointers; 321 itemSet(*data, item_index, hash, *key, *value); 322 itemIndexAtPut(*indices, bytes_offset, item_index); 323 return; 324 } 325 } 326} 327 328static void dictEnsureCapacity(Thread* thread, const Dict& dict) { 329 DCHECK(dict.numIndices() && Utils::isPowerOfTwo(dict.numIndices()), 330 "dict capacity must be power of two, greater than zero"); 331 if (dictHasUsableItem(dict)) { 332 return; 333 } 334 335 // TODO(T44247845): Handle overflow here. 336 word new_num_indices = dict.numIndices() * kDictGrowthFactor; 337 DCHECK(new_num_indices < kTombstoneValue, 338 "new_num_indices is expected to be less than kTombstoneValue"); 339 HandleScope scope(thread); 340 Runtime* runtime = thread->runtime(); 341 MutableTuple new_data( 342 &scope, runtime->newMutableTuple(sizeOfDataTuple(new_num_indices) * 343 kItemNumPointers)); 344 new_data.fill(NoneType::object()); 345 MutableBytes new_indices(&scope, runtime->mutableBytesWith( 346 indexOffset(new_num_indices), kMaxByte)); 347 348 // Re-insert items 349 Object key(&scope, NoneType::object()); 350 Object value(&scope, NoneType::object()); 351 word hash; 352 word item_count = 0; 353 for (word i = 0; dictNextItemHash(dict, &i, &key, &value, &hash); 354 item_count++) { 355 dictInsertNoUpdate(new_data, new_indices, new_num_indices, item_count, key, 356 hash, value); 357 } 358 DCHECK(item_count == dict.numItems(), "found entries != dictNumItems()"); 359 dict.setData(*new_data); 360 dict.setIndices(*new_indices); 361 dict.setFirstEmptyItemIndex(dict.numItems() * kItemNumPointers); 362} 363 364RawObject dictAtPut(Thread* thread, const Dict& dict, const Object& key, 365 word hash, const Object& value) { 366 if (dict.indices() == SmallInt::fromWord(0)) { 367 dictAllocateArrays(thread, dict, kInitialDictIndicesLength); 368 } 369 HandleScope scope(thread); 370 MutableTuple data(&scope, dict.data()); 371 MutableBytes indices(&scope, dict.indices()); 372 word num_indices = dict.numIndices(); 373 RawObject lookup_result = 374 dictLookupForInsertion(thread, data, indices, num_indices, key, hash); 375 if (UNLIKELY(lookup_result.isErrorException())) { 376 return lookup_result; 377 } 378 word bytes_offset = SmallInt::cast(lookup_result).value(); 379 if (bytes_offset >= 0) { 380 uint32_t item_index = itemIndexAt(*indices, bytes_offset); 381 itemSetValue(*data, item_index, *value); 382 return NoneType::object(); 383 } 384 385 bytes_offset += indexOffset(num_indices); 386 word item_index = dict.firstEmptyItemIndex(); 387 DCHECK(itemIsEmpty(*data, item_index), "item is expected to be empty"); 388 itemSet(*data, item_index, hash, *key, *value); 389 itemIndexAtPut(*indices, bytes_offset, item_index); 390 dict.setNumItems(dict.numItems() + 1); 391 dict.setFirstEmptyItemIndex(dict.firstEmptyItemIndex() + kItemNumPointers); 392 dictEnsureCapacity(thread, dict); 393 DCHECK(dictHasUsableItem(dict), "dict must have an empty item left"); 394 return NoneType::object(); 395} 396 397void dictAtPutByStr(Thread* thread, const Dict& dict, const Object& name, 398 const Object& value) { 399 word hash = strHash(thread, *name); 400 UNUSED RawObject result = dictAtPut(thread, dict, name, hash, value); 401 DCHECK(!result.isError(), "result must not be an error"); 402} 403 404void dictAtPutById(Thread* thread, const Dict& dict, SymbolId id, 405 const Object& value) { 406 HandleScope scope(thread); 407 Object name(&scope, thread->runtime()->symbols()->at(id)); 408 dictAtPutByStr(thread, dict, name, value); 409} 410 411RawObject dictAt(Thread* thread, const Dict& dict, const Object& key, 412 word hash) { 413 if (dict.numItems() == 0) { 414 return Error::notFound(); 415 } 416 HandleScope scope(thread); 417 MutableTuple data(&scope, dict.data()); 418 MutableBytes indices(&scope, dict.indices()); 419 RawObject lookup_result = 420 dictLookup(thread, data, indices, dict.numIndices(), key, hash); 421 if (UNLIKELY(lookup_result.isErrorException())) { 422 return lookup_result; 423 } 424 word bytes_offset = SmallInt::cast(lookup_result).value(); 425 if (bytes_offset >= 0) { 426 uint32_t item_index = itemIndexAt(*indices, bytes_offset); 427 return itemValue(*data, item_index); 428 } 429 return Error::notFound(); 430} 431 432RawObject dictAtByStr(Thread* thread, const Dict& dict, const Object& name) { 433 word hash = strHash(thread, *name); 434 return dictAt(thread, dict, name, hash); 435} 436 437RawObject dictAtById(Thread* thread, const Dict& dict, SymbolId id) { 438 HandleScope scope(thread); 439 Object name(&scope, thread->runtime()->symbols()->at(id)); 440 return dictAtByStr(thread, dict, name); 441} 442 443RawObject dictAtPutInValueCellByStr(Thread* thread, const Dict& dict, 444 const Object& name, const Object& value) { 445 if (dict.indices() == SmallInt::fromWord(0)) { 446 dictAllocateArrays(thread, dict, kInitialDictIndicesLength); 447 } 448 HandleScope scope(thread); 449 MutableTuple data(&scope, dict.data()); 450 MutableBytes indices(&scope, dict.indices()); 451 word num_indices = dict.numIndices(); 452 word hash = strHash(thread, *name); 453 RawObject lookup_result = 454 dictLookupForInsertion(thread, data, indices, num_indices, name, hash); 455 if (UNLIKELY(lookup_result.isErrorException())) { 456 return lookup_result; 457 } 458 word bytes_offset = SmallInt::cast(lookup_result).value(); 459 if (bytes_offset >= 0) { 460 uint32_t item_index = itemIndexAt(*indices, bytes_offset); 461 RawValueCell value_cell = ValueCell::cast(itemValue(*data, item_index)); 462 value_cell.setValue(*value); 463 return value_cell; 464 } 465 bytes_offset += indexOffset(num_indices); 466 word item_index = dict.firstEmptyItemIndex(); 467 DCHECK(itemIsEmpty(*data, item_index), "item is expected to be empty"); 468 ValueCell value_cell(&scope, thread->runtime()->newValueCell()); 469 itemSet(*data, item_index, hash, *name, *value_cell); 470 itemIndexAtPut(*indices, bytes_offset, item_index); 471 dict.setNumItems(dict.numItems() + 1); 472 dict.setFirstEmptyItemIndex(dict.firstEmptyItemIndex() + kItemNumPointers); 473 dictEnsureCapacity(thread, dict); 474 DCHECK(dictHasUsableItem(dict), "dict must have an empty item left"); 475 value_cell.setValue(*value); 476 return *value_cell; 477} 478 479void dictClear(Thread* thread, const Dict& dict) { 480 if (dict.indices() == SmallInt::fromWord(0)) return; 481 482 HandleScope scope(thread); 483 MutableTuple data(&scope, dict.data()); 484 data.fill(NoneType::object()); 485 MutableBytes indices(&scope, dict.indices()); 486 indices.replaceFromWithByte(0, kMaxByte, indices.length()); 487 dict.setNumItems(0); 488 dict.setFirstEmptyItemIndex(0); 489} 490 491RawObject dictIncludes(Thread* thread, const Dict& dict, const Object& key, 492 word hash) { 493 if (dict.numItems() == 0) { 494 return Bool::falseObj(); 495 } 496 HandleScope scope(thread); 497 MutableTuple data(&scope, dict.data()); 498 MutableBytes indices(&scope, dict.indices()); 499 word num_indices = dict.numIndices(); 500 RawObject lookup_result = 501 dictLookup(thread, data, indices, num_indices, key, hash); 502 if (UNLIKELY(lookup_result.isErrorException())) { 503 return lookup_result; 504 } 505 return Bool::fromBool(SmallInt::cast(lookup_result).value() >= 0); 506} 507 508RawObject dictRemoveByStr(Thread* thread, const Dict& dict, 509 const Object& name) { 510 word hash = strHash(thread, *name); 511 return dictRemove(thread, dict, name, hash); 512} 513 514RawObject dictRemove(Thread* thread, const Dict& dict, const Object& key, 515 word hash) { 516 if (dict.numItems() == 0) { 517 return Error::notFound(); 518 } 519 HandleScope scope(thread); 520 MutableTuple data(&scope, dict.data()); 521 MutableBytes indices(&scope, dict.indices()); 522 word num_indices = dict.numIndices(); 523 RawObject lookup_result = 524 dictLookup(thread, data, indices, num_indices, key, hash); 525 if (UNLIKELY(lookup_result.isErrorException())) { 526 return lookup_result; 527 } 528 word bytes_offset = SmallInt::cast(lookup_result).value(); 529 if (bytes_offset < 0) { 530 return Error::notFound(); 531 } 532 uint32_t item_index = itemIndexAt(*indices, bytes_offset); 533 Object result(&scope, itemValue(*data, item_index)); 534 itemSetTombstone(*data, item_index); 535 indicesSetTombstone(*indices, bytes_offset); 536 dict.setNumItems(dict.numItems() - 1); 537 return *result; 538} 539 540RawObject dictKeys(Thread* thread, const Dict& dict) { 541 word len = dict.numItems(); 542 Runtime* runtime = thread->runtime(); 543 if (len == 0) { 544 return runtime->newList(); 545 } 546 HandleScope scope(thread); 547 MutableTuple keys(&scope, runtime->newMutableTuple(len)); 548 Object key(&scope, NoneType::object()); 549 word num_keys = 0; 550 for (word i = 0; dictNextKey(dict, &i, &key);) { 551 DCHECK(num_keys < keys.length(), "%ld ! < %ld", num_keys, keys.length()); 552 keys.atPut(num_keys, *key); 553 num_keys++; 554 } 555 List result(&scope, runtime->newList()); 556 result.setItems(*keys); 557 result.setNumItems(len); 558 return *result; 559} 560 561RawObject dictCopy(Thread* thread, const Dict& dict) { 562 HandleScope scope(thread); 563 Dict copy(&scope, thread->runtime()->newDict()); 564 Object result(&scope, dictMergeError(thread, copy, dict)); 565 if (result.isError()) { 566 return *result; 567 } 568 return *copy; 569} 570 571namespace { 572enum class Override { 573 kIgnore, 574 kOverride, 575 kError, 576}; 577 578RawObject dictMergeDict(Thread* thread, const Dict& dict, const Object& mapping, 579 Override do_override) { 580 HandleScope scope(thread); 581 if (*mapping == *dict) return NoneType::object(); 582 583 Object key(&scope, NoneType::object()); 584 Object value(&scope, NoneType::object()); 585 word hash; 586 Dict other(&scope, *mapping); 587 Object included(&scope, NoneType::object()); 588 Object dict_result(&scope, NoneType::object()); 589 for (word i = 0; dictNextItemHash(other, &i, &key, &value, &hash);) { 590 if (do_override == Override::kOverride) { 591 dict_result = dictAtPut(thread, dict, key, hash, value); 592 if (dict_result.isErrorException()) return *dict_result; 593 } else { 594 included = dictIncludes(thread, dict, key, hash); 595 if (included.isErrorException()) return *included; 596 if (included == Bool::falseObj()) { 597 dict_result = dictAtPut(thread, dict, key, hash, value); 598 if (dict_result.isErrorException()) return *dict_result; 599 } else if (do_override == Override::kError) { 600 return thread->raise(LayoutId::kKeyError, *key); 601 } 602 } 603 } 604 return NoneType::object(); 605} 606 607RawObject dictMergeImpl(Thread* thread, const Dict& dict, const Object& mapping, 608 Override do_override) { 609 Runtime* runtime = thread->runtime(); 610 if (runtime->isInstanceOfDict(*mapping)) { 611 return dictMergeDict(thread, dict, mapping, do_override); 612 } 613 614 HandleScope scope(thread); 615 Object key(&scope, NoneType::object()); 616 Object hash_obj(&scope, NoneType::object()); 617 Object value(&scope, NoneType::object()); 618 Object included(&scope, NoneType::object()); 619 Object keys_method(&scope, 620 runtime->attributeAtById(thread, mapping, ID(keys))); 621 if (keys_method.isError()) { 622 return *keys_method; 623 } 624 625 // Generic mapping, use keys() and __getitem__() 626 Object subscr_method( 627 &scope, runtime->attributeAtById(thread, mapping, ID(__getitem__))); 628 629 if (subscr_method.isError()) { 630 return *subscr_method; 631 } 632 Object keys(&scope, Interpreter::callMethod1(thread, keys_method, mapping)); 633 if (keys.isError()) return *keys; 634 635 if (keys.isList()) { 636 List keys_list(&scope, *keys); 637 Object dict_result(&scope, NoneType::object()); 638 for (word i = 0; i < keys_list.numItems(); ++i) { 639 key = keys_list.at(i); 640 hash_obj = Interpreter::hash(thread, key); 641 if (hash_obj.isErrorException()) return *hash_obj; 642 word hash = SmallInt::cast(*hash_obj).value(); 643 if (do_override == Override::kOverride) { 644 value = Interpreter::callMethod2(thread, subscr_method, mapping, key); 645 if (value.isError()) return *value; 646 dict_result = dictAtPut(thread, dict, key, hash, value); 647 if (dict_result.isErrorException()) return *dict_result; 648 } else { 649 included = dictIncludes(thread, dict, key, hash); 650 if (included.isErrorException()) return *included; 651 if (included == Bool::falseObj()) { 652 value = Interpreter::callMethod2(thread, subscr_method, mapping, key); 653 if (value.isError()) return *value; 654 dict_result = dictAtPut(thread, dict, key, hash, value); 655 if (dict_result.isErrorException()) return *dict_result; 656 } else if (do_override == Override::kError) { 657 return thread->raise(LayoutId::kKeyError, *key); 658 } 659 } 660 } 661 return NoneType::object(); 662 } 663 664 if (keys.isTuple()) { 665 Tuple keys_tuple(&scope, *keys); 666 Object dict_result(&scope, NoneType::object()); 667 for (word i = 0; i < keys_tuple.length(); ++i) { 668 key = keys_tuple.at(i); 669 hash_obj = Interpreter::hash(thread, key); 670 if (hash_obj.isErrorException()) return *hash_obj; 671 word hash = SmallInt::cast(*hash_obj).value(); 672 if (do_override == Override::kOverride) { 673 value = Interpreter::callMethod2(thread, subscr_method, mapping, key); 674 if (value.isError()) return *value; 675 dict_result = dictAtPut(thread, dict, key, hash, value); 676 if (dict_result.isErrorException()) return *dict_result; 677 } else { 678 included = dictIncludes(thread, dict, key, hash); 679 if (included.isErrorException()) return *included; 680 if (included == Bool::falseObj()) { 681 value = Interpreter::callMethod2(thread, subscr_method, mapping, key); 682 if (value.isError()) return *value; 683 dict_result = dictAtPut(thread, dict, key, hash, value); 684 if (dict_result.isErrorException()) return *dict_result; 685 } else if (do_override == Override::kError) { 686 return thread->raise(LayoutId::kKeyError, *key); 687 } 688 } 689 } 690 return NoneType::object(); 691 } 692 693 // keys is probably an iterator 694 Object iter_method(&scope, 695 Interpreter::lookupMethod(thread, keys, ID(__iter__))); 696 if (iter_method.isError()) { 697 return thread->raiseWithFmt(LayoutId::kTypeError, "keys() is not iterable"); 698 } 699 700 Object iterator(&scope, Interpreter::callMethod1(thread, iter_method, keys)); 701 if (iterator.isError()) { 702 return thread->raiseWithFmt(LayoutId::kTypeError, "keys() is not iterable"); 703 } 704 Object next_method(&scope, 705 Interpreter::lookupMethod(thread, iterator, ID(__next__))); 706 if (next_method.isError()) { 707 return thread->raiseWithFmt(LayoutId::kTypeError, "keys() is not iterable"); 708 } 709 Object dict_result(&scope, NoneType::object()); 710 for (;;) { 711 key = Interpreter::callMethod1(thread, next_method, iterator); 712 if (key.isError()) { 713 if (thread->clearPendingStopIteration()) break; 714 return *key; 715 } 716 hash_obj = Interpreter::hash(thread, key); 717 if (hash_obj.isErrorException()) return *hash_obj; 718 word hash = SmallInt::cast(*hash_obj).value(); 719 if (do_override == Override::kOverride) { 720 value = Interpreter::callMethod2(thread, subscr_method, mapping, key); 721 if (value.isError()) return *value; 722 dict_result = dictAtPut(thread, dict, key, hash, value); 723 if (dict_result.isErrorException()) return *dict_result; 724 } else { 725 included = dictIncludes(thread, dict, key, hash); 726 if (included.isErrorException()) return *included; 727 if (included == Bool::falseObj()) { 728 value = Interpreter::callMethod2(thread, subscr_method, mapping, key); 729 if (value.isError()) return *value; 730 dict_result = dictAtPut(thread, dict, key, hash, value); 731 if (dict_result.isErrorException()) return *dict_result; 732 } else if (do_override == Override::kError) { 733 return thread->raise(LayoutId::kKeyError, *key); 734 } 735 } 736 } 737 return NoneType::object(); 738} 739} // namespace 740 741RawObject dictMergeOverride(Thread* thread, const Dict& dict, 742 const Object& mapping) { 743 return dictMergeImpl(thread, dict, mapping, Override::kOverride); 744} 745 746RawObject dictMergeError(Thread* thread, const Dict& dict, 747 const Object& mapping) { 748 return dictMergeImpl(thread, dict, mapping, Override::kError); 749} 750 751RawObject dictMergeIgnore(Thread* thread, const Dict& dict, 752 const Object& mapping) { 753 return dictMergeImpl(thread, dict, mapping, Override::kIgnore); 754} 755 756RawObject dictEq(Thread* thread, const Dict& left, const Dict& right) { 757 if (left.numItems() != right.numItems()) { 758 return Bool::falseObj(); 759 } 760 HandleScope scope(thread); 761 Object key(&scope, NoneType::object()); 762 Object left_value(&scope, NoneType::object()); 763 word hash; 764 Object right_value(&scope, NoneType::object()); 765 Object result(&scope, NoneType::object()); 766 for (word i = 0; dictNextItemHash(left, &i, &key, &left_value, &hash);) { 767 right_value = dictAt(thread, right, key, hash); 768 if (right_value.isErrorNotFound()) { 769 return Bool::falseObj(); 770 } 771 if (left_value == right_value) { 772 continue; 773 } 774 result = Interpreter::compareOperation(thread, EQ, left_value, right_value); 775 if (result.isErrorException()) { 776 // equality comparison raised 777 return *result; 778 } 779 result = Interpreter::isTrue(thread, *result); 780 if (result != Bool::trueObj()) { 781 // bool conversion raised or returned false 782 return *result; 783 } 784 } 785 return Bool::trueObj(); 786} 787 788RawObject dictItemIteratorNext(Thread* thread, const DictItemIterator& iter) { 789 HandleScope scope(thread); 790 Dict dict(&scope, iter.iterable()); 791 Object key(&scope, NoneType::object()); 792 Object value(&scope, NoneType::object()); 793 word i = iter.index(); 794 if (dictNextItem(dict, &i, &key, &value)) { 795 iter.setIndex(i); 796 iter.setNumFound(iter.numFound() + 1); 797 return thread->runtime()->newTupleWith2(key, value); 798 } 799 800 // We hit the end. 801 iter.setIndex(i); 802 return Error::noMoreItems(); 803} 804 805RawObject dictKeyIteratorNext(Thread* thread, const DictKeyIterator& iter) { 806 HandleScope scope(thread); 807 Dict dict(&scope, iter.iterable()); 808 Object key(&scope, NoneType::object()); 809 word i = iter.index(); 810 if (dictNextKey(dict, &i, &key)) { 811 iter.setIndex(i); 812 iter.setNumFound(iter.numFound() + 1); 813 return *key; 814 } 815 816 // We hit the end. 817 iter.setIndex(i); 818 return Error::noMoreItems(); 819} 820 821RawObject dictValueIteratorNext(Thread* thread, const DictValueIterator& iter) { 822 HandleScope scope(thread); 823 Dict dict(&scope, iter.iterable()); 824 Object value(&scope, NoneType::object()); 825 word i = iter.index(); 826 if (dictNextValue(dict, &i, &value)) { 827 iter.setIndex(i); 828 iter.setNumFound(iter.numFound() + 1); 829 return *value; 830 } 831 832 // We hit the end. 833 iter.setIndex(i); 834 return Error::noMoreItems(); 835} 836 837static const BuiltinAttribute kDictAttributes[] = { 838 {ID(_dict__num_items), RawDict::kNumItemsOffset, AttributeFlags::kHidden}, 839 {ID(_dict__data), RawDict::kDataOffset, AttributeFlags::kHidden}, 840 {ID(_dict__sparse), RawDict::kIndicesOffset, AttributeFlags::kHidden}, 841 {ID(_dict__first_empty_item_index), RawDict::kFirstEmptyItemIndexOffset, 842 AttributeFlags::kHidden}, 843}; 844 845static const BuiltinAttribute kDictItemIteratorAttributes[] = { 846 {ID(_dict_item_iterator__iterable), RawDictItemIterator::kIterableOffset, 847 AttributeFlags::kHidden}, 848 {ID(_dict_item_iterator__index), RawDictItemIterator::kIndexOffset, 849 AttributeFlags::kHidden}, 850 {ID(_dict_item_iterator__num_found), RawDictItemIterator::kNumFoundOffset, 851 AttributeFlags::kHidden}, 852}; 853 854static const BuiltinAttribute kDictItemsAttributes[] = { 855 {ID(_dict_items__dict), RawDictItems::kDictOffset, AttributeFlags::kHidden}, 856}; 857 858static const BuiltinAttribute kDictKeyIteratorAttributes[] = { 859 {ID(_dict_key_iterator__iterable), RawDictKeyIterator::kIterableOffset, 860 AttributeFlags::kHidden}, 861 {ID(_dict_key_iterator__index), RawDictKeyIterator::kIndexOffset, 862 AttributeFlags::kHidden}, 863 {ID(_dict_key_iterator__num_found), RawDictKeyIterator::kNumFoundOffset, 864 AttributeFlags::kHidden}, 865}; 866 867static const BuiltinAttribute kDictKeysAttributes[] = { 868 {ID(_dict_keys__dict), RawDictKeys::kDictOffset, AttributeFlags::kHidden}, 869}; 870 871static const BuiltinAttribute kDictValueIteratorAttributes[] = { 872 {ID(_dict_value_iterator__iterable), RawDictValueIterator::kIterableOffset, 873 AttributeFlags::kHidden}, 874 {ID(_dict_value_iterator__index), RawDictValueIterator::kIndexOffset, 875 AttributeFlags::kHidden}, 876 {ID(_dict_value_iterator__num_found), RawDictValueIterator::kNumFoundOffset, 877 AttributeFlags::kHidden}, 878}; 879 880static const BuiltinAttribute kDictValuesAttributes[] = { 881 {ID(_dict_values__dict), RawDictValues::kDictOffset, 882 AttributeFlags::kHidden}, 883}; 884 885void initializeDictTypes(Thread* thread) { 886 addBuiltinType(thread, ID(dict), LayoutId::kDict, 887 /*superclass_id=*/LayoutId::kObject, kDictAttributes, 888 Dict::kSize, /*basetype=*/true); 889 890 addBuiltinType(thread, ID(dict_itemiterator), LayoutId::kDictItemIterator, 891 /*superclass_id=*/LayoutId::kObject, 892 kDictItemIteratorAttributes, DictItemIterator::kSize, 893 /*basetype=*/false); 894 895 addBuiltinType(thread, ID(dict_items), LayoutId::kDictItems, 896 /*superclass_id=*/LayoutId::kObject, kDictItemsAttributes, 897 DictItems::kSize, /*basetype=*/false); 898 899 addBuiltinType(thread, ID(dict_keyiterator), LayoutId::kDictKeyIterator, 900 /*superclass_id=*/LayoutId::kObject, 901 kDictKeyIteratorAttributes, DictKeyIterator::kSize, 902 /*basetype=*/false); 903 904 addBuiltinType(thread, ID(dict_keys), LayoutId::kDictKeys, 905 /*superclass_id=*/LayoutId::kObject, kDictKeysAttributes, 906 DictKeys::kSize, /*basetype=*/false); 907 908 addBuiltinType(thread, ID(dict_valueiterator), LayoutId::kDictValueIterator, 909 /*superclass_id=*/LayoutId::kObject, 910 kDictValueIteratorAttributes, DictValueIterator::kSize, 911 /*basetype=*/false); 912 913 addBuiltinType(thread, ID(dict_values), LayoutId::kDictValues, 914 /*superclass_id=*/LayoutId::kObject, kDictValuesAttributes, 915 DictValues::kSize, /*basetype=*/false); 916} 917 918RawObject METH(dict, clear)(Thread* thread, Arguments args) { 919 HandleScope scope(thread); 920 Object self(&scope, args.get(0)); 921 if (!thread->runtime()->isInstanceOfDict(*self)) { 922 return thread->raiseRequiresType(self, ID(dict)); 923 } 924 Dict dict(&scope, *self); 925 dictClear(thread, dict); 926 return NoneType::object(); 927} 928 929RawObject METH(dict, __delitem__)(Thread* thread, Arguments args) { 930 HandleScope scope(thread); 931 Object self(&scope, args.get(0)); 932 Object key(&scope, args.get(1)); 933 Runtime* runtime = thread->runtime(); 934 if (!runtime->isInstanceOfDict(*self)) { 935 return thread->raiseRequiresType(self, ID(dict)); 936 } 937 Dict dict(&scope, *self); 938 Object hash_obj(&scope, Interpreter::hash(thread, key)); 939 if (hash_obj.isErrorException()) return *hash_obj; 940 word hash = SmallInt::cast(*hash_obj).value(); 941 // Remove the key. If it doesn't exist, throw a KeyError. 942 if (dictRemove(thread, dict, key, hash).isError()) { 943 return thread->raise(LayoutId::kKeyError, *key); 944 } 945 return NoneType::object(); 946} 947 948RawObject METH(dict, __eq__)(Thread* thread, Arguments args) { 949 Runtime* runtime = thread->runtime(); 950 HandleScope scope(thread); 951 Object self_obj(&scope, args.get(0)); 952 if (!runtime->isInstanceOfDict(*self_obj)) { 953 return thread->raiseRequiresType(self_obj, ID(dict)); 954 } 955 Object other_obj(&scope, args.get(1)); 956 if (!runtime->isInstanceOfDict(*other_obj)) { 957 return NotImplementedType::object(); 958 } 959 Dict a(&scope, *self_obj); 960 Dict b(&scope, *other_obj); 961 return dictEq(thread, a, b); 962} 963 964RawObject METH(dict, __len__)(Thread* thread, Arguments args) { 965 HandleScope scope(thread); 966 Object self(&scope, args.get(0)); 967 if (!thread->runtime()->isInstanceOfDict(*self)) { 968 return thread->raiseRequiresType(self, ID(dict)); 969 } 970 Dict dict(&scope, *self); 971 return SmallInt::fromWord(dict.numItems()); 972} 973 974RawObject METH(dict, __iter__)(Thread* thread, Arguments args) { 975 HandleScope scope(thread); 976 Object self(&scope, args.get(0)); 977 Runtime* runtime = thread->runtime(); 978 if (!runtime->isInstanceOfDict(*self)) { 979 return thread->raiseRequiresType(self, ID(dict)); 980 } 981 Dict dict(&scope, *self); 982 // .iter() on a dict returns a keys iterator 983 return runtime->newDictKeyIterator(thread, dict); 984} 985 986RawObject METH(dict, items)(Thread* thread, Arguments args) { 987 HandleScope scope(thread); 988 Object self(&scope, args.get(0)); 989 Runtime* runtime = thread->runtime(); 990 if (!runtime->isInstanceOfDict(*self)) { 991 return thread->raiseRequiresType(self, ID(dict)); 992 } 993 Dict dict(&scope, *self); 994 return runtime->newDictItems(thread, dict); 995} 996 997RawObject METH(dict, keys)(Thread* thread, Arguments args) { 998 HandleScope scope(thread); 999 Object self(&scope, args.get(0)); 1000 Runtime* runtime = thread->runtime(); 1001 if (!runtime->isInstanceOfDict(*self)) { 1002 return thread->raiseRequiresType(self, ID(dict)); 1003 } 1004 Dict dict(&scope, *self); 1005 return runtime->newDictKeys(thread, dict); 1006} 1007 1008RawObject METH(dict, popitem)(Thread* thread, Arguments args) { 1009 HandleScope scope(thread); 1010 Object self(&scope, args.get(0)); 1011 Runtime* runtime = thread->runtime(); 1012 if (!runtime->isInstanceOfDict(*self)) { 1013 return thread->raiseRequiresType(self, ID(dict)); 1014 } 1015 Dict dict(&scope, *self); 1016 if (dict.numItems() == 0) { 1017 return thread->raiseWithFmt(LayoutId::kKeyError, 1018 "popitem(): dictionary is empty"); 1019 } 1020 MutableTuple data(&scope, dict.data()); 1021 for (word item_index = dict.firstEmptyItemIndex() - kItemNumPointers; 1022 item_index >= 0; item_index -= kItemNumPointers) { 1023 if (!itemIsEmpty(*data, item_index) && 1024 !itemIsTombstone(*data, item_index)) { 1025 Object key(&scope, itemKey(*data, item_index)); 1026 Object value(&scope, itemValue(*data, item_index)); 1027 Tuple result(&scope, runtime->newTupleWith2(key, value)); 1028 // Find the item for the entry and set a tombstone in it. 1029 // Note that this would take amortized cost O(1). 1030 word indices_index = -1; 1031 MutableBytes indices(&scope, dict.indices()); 1032 uword perturb; 1033 word indices_mask; 1034 word hash = itemHash(*data, item_index); 1035 word num_indices = dict.numIndices(); 1036 for (word current_index = 1037 probeBegin(num_indices, hash, &indices_mask, &perturb); 1038 ; current_index = probeNext(current_index, indices_mask, &perturb)) { 1039 word bytes_offset = indexOffset(current_index); 1040 uint32_t comp; 1041 if (indicesIsFull(*indices, bytes_offset, &comp) && 1042 comp == item_index) { 1043 indices_index = current_index; 1044 break; 1045 } 1046 } 1047 DCHECK(indices_index >= 0, "cannot find index for entry in dict.sparse"); 1048 itemSetTombstone(*data, item_index); 1049 indicesSetTombstone(*indices, indexOffset(indices_index)); 1050 dict.setNumItems(dict.numItems() - 1); 1051 return *result; 1052 } 1053 } 1054 UNREACHABLE("dict.numItems() > 0, but couldn't find any active item"); 1055} 1056 1057RawObject METH(dict, values)(Thread* thread, Arguments args) { 1058 HandleScope scope(thread); 1059 Object self(&scope, args.get(0)); 1060 Runtime* runtime = thread->runtime(); 1061 if (!runtime->isInstanceOfDict(*self)) { 1062 return thread->raiseRequiresType(self, ID(dict)); 1063 } 1064 Dict dict(&scope, *self); 1065 return runtime->newDictValues(thread, dict); 1066} 1067 1068RawObject METH(dict, __new__)(Thread* thread, Arguments args) { 1069 HandleScope scope(thread); 1070 Object type_obj(&scope, args.get(0)); 1071 Runtime* runtime = thread->runtime(); 1072 if (!runtime->isInstanceOfType(*type_obj)) { 1073 return thread->raiseWithFmt(LayoutId::kTypeError, "not a type object"); 1074 } 1075 Type type(&scope, *type_obj); 1076 if (type.builtinBase() != LayoutId::kDict) { 1077 return thread->raiseWithFmt(LayoutId::kTypeError, "not a subtype of dict"); 1078 } 1079 Layout layout(&scope, type.instanceLayout()); 1080 Dict result(&scope, runtime->newInstance(layout)); 1081 result.setNumItems(0); 1082 result.setData(SmallInt::fromWord(0)); 1083 result.setIndices(SmallInt::fromWord(0)); 1084 result.setFirstEmptyItemIndex(0); 1085 return *result; 1086} 1087 1088RawObject METH(dict, __contains__)(Thread* thread, Arguments args) { 1089 HandleScope scope(thread); 1090 Object self(&scope, args.get(0)); 1091 Object key(&scope, args.get(1)); 1092 Runtime* runtime = thread->runtime(); 1093 if (!runtime->isInstanceOfDict(*self)) { 1094 return thread->raiseRequiresType(self, ID(dict)); 1095 } 1096 Object hash_obj(&scope, Interpreter::hash(thread, key)); 1097 if (hash_obj.isErrorException()) { 1098 return *hash_obj; 1099 } 1100 Dict dict(&scope, *self); 1101 word hash = SmallInt::cast(*hash_obj).value(); 1102 return dictIncludes(thread, dict, key, hash); 1103} 1104 1105RawObject METH(dict, pop)(Thread* thread, Arguments args) { 1106 HandleScope scope(thread); 1107 Object self(&scope, args.get(0)); 1108 Object key(&scope, args.get(1)); 1109 Runtime* runtime = thread->runtime(); 1110 if (!runtime->isInstanceOfDict(*self)) { 1111 return thread->raiseRequiresType(self, ID(dict)); 1112 } 1113 Dict dict(&scope, *self); 1114 Object hash_obj(&scope, Interpreter::hash(thread, key)); 1115 if (hash_obj.isErrorException()) { 1116 return *hash_obj; 1117 } 1118 word hash = SmallInt::cast(*hash_obj).value(); 1119 Object result(&scope, dictRemove(thread, dict, key, hash)); 1120 if (result.isErrorNotFound()) { 1121 Object default_obj(&scope, args.get(2)); 1122 return default_obj.isUnbound() ? thread->raise(LayoutId::kKeyError, *key) 1123 : *default_obj; 1124 } 1125 return *result; 1126} 1127 1128// TODO(T35787656): Instead of re-writing everything for every class, make a 1129// helper function that takes a member function (type check) and string for the 1130// Python symbol name 1131 1132RawObject METH(dict_itemiterator, __iter__)(Thread* thread, Arguments args) { 1133 HandleScope scope(thread); 1134 Object self(&scope, args.get(0)); 1135 if (!self.isDictItemIterator()) { 1136 return thread->raiseRequiresType(self, ID(dict_itemiterator)); 1137 } 1138 return *self; 1139} 1140 1141RawObject METH(dict_itemiterator, __next__)(Thread* thread, Arguments args) { 1142 HandleScope scope(thread); 1143 Object self(&scope, args.get(0)); 1144 if (!self.isDictItemIterator()) { 1145 return thread->raiseRequiresType(self, ID(dict_itemiterator)); 1146 } 1147 DictItemIterator iter(&scope, *self); 1148 Object value(&scope, dictItemIteratorNext(thread, iter)); 1149 if (value.isError()) { 1150 return thread->raise(LayoutId::kStopIteration, NoneType::object()); 1151 } 1152 return *value; 1153} 1154 1155RawObject METH(dict_itemiterator, __length_hint__)(Thread* thread, 1156 Arguments args) { 1157 HandleScope scope(thread); 1158 Object self(&scope, args.get(0)); 1159 if (!self.isDictItemIterator()) { 1160 return thread->raiseRequiresType(self, ID(dict_itemiterator)); 1161 } 1162 DictItemIterator iter(&scope, *self); 1163 Dict dict(&scope, iter.iterable()); 1164 return SmallInt::fromWord(dict.numItems() - iter.numFound()); 1165} 1166 1167RawObject METH(dict_items, __iter__)(Thread* thread, Arguments args) { 1168 HandleScope scope(thread); 1169 Object self(&scope, args.get(0)); 1170 if (!self.isDictItems()) { 1171 return thread->raiseRequiresType(self, ID(dict_items)); 1172 } 1173 1174 Dict dict(&scope, DictItems::cast(*self).dict()); 1175 return thread->runtime()->newDictItemIterator(thread, dict); 1176} 1177 1178RawObject METH(dict_items, __len__)(Thread* thread, Arguments args) { 1179 HandleScope scope(thread); 1180 Object self(&scope, args.get(0)); 1181 if (!self.isDictItems()) { 1182 return thread->raiseRequiresType(self, ID(dict_items)); 1183 } 1184 1185 Dict dict(&scope, DictItems::cast(*self).dict()); 1186 return thread->runtime()->newInt(dict.numItems()); 1187} 1188 1189RawObject METH(dict_keyiterator, __iter__)(Thread* thread, Arguments args) { 1190 HandleScope scope(thread); 1191 Object self(&scope, args.get(0)); 1192 if (!self.isDictKeyIterator()) { 1193 return thread->raiseRequiresType(self, ID(dict_keyiterator)); 1194 } 1195 return *self; 1196} 1197 1198RawObject METH(dict_keyiterator, __next__)(Thread* thread, Arguments args) { 1199 HandleScope scope(thread); 1200 Object self(&scope, args.get(0)); 1201 if (!self.isDictKeyIterator()) { 1202 return thread->raiseRequiresType(self, ID(dict_keyiterator)); 1203 } 1204 DictKeyIterator iter(&scope, *self); 1205 Object value(&scope, dictKeyIteratorNext(thread, iter)); 1206 if (value.isError()) { 1207 return thread->raise(LayoutId::kStopIteration, NoneType::object()); 1208 } 1209 return *value; 1210} 1211 1212RawObject METH(dict_keyiterator, __length_hint__)(Thread* thread, 1213 Arguments args) { 1214 HandleScope scope(thread); 1215 Object self(&scope, args.get(0)); 1216 if (!self.isDictKeyIterator()) { 1217 return thread->raiseRequiresType(self, ID(dict_keyiterator)); 1218 } 1219 DictKeyIterator iter(&scope, *self); 1220 Dict dict(&scope, iter.iterable()); 1221 return SmallInt::fromWord(dict.numItems() - iter.numFound()); 1222} 1223 1224RawObject METH(dict_keys, __iter__)(Thread* thread, Arguments args) { 1225 HandleScope scope(thread); 1226 Object self(&scope, args.get(0)); 1227 if (!self.isDictKeys()) { 1228 return thread->raiseRequiresType(self, ID(dict_keys)); 1229 } 1230 1231 Dict dict(&scope, DictKeys::cast(*self).dict()); 1232 return thread->runtime()->newDictKeyIterator(thread, dict); 1233} 1234 1235RawObject METH(dict_keys, __len__)(Thread* thread, Arguments args) { 1236 HandleScope scope(thread); 1237 Object self(&scope, args.get(0)); 1238 if (!self.isDictKeys()) { 1239 return thread->raiseRequiresType(self, ID(dict_keys)); 1240 } 1241 1242 Dict dict(&scope, DictKeys::cast(*self).dict()); 1243 return thread->runtime()->newInt(dict.numItems()); 1244} 1245 1246RawObject METH(dict_valueiterator, __iter__)(Thread* thread, Arguments args) { 1247 HandleScope scope(thread); 1248 Object self(&scope, args.get(0)); 1249 if (!self.isDictValueIterator()) { 1250 return thread->raiseRequiresType(self, ID(dict_valueiterator)); 1251 } 1252 return *self; 1253} 1254 1255RawObject METH(dict_valueiterator, __next__)(Thread* thread, Arguments args) { 1256 HandleScope scope(thread); 1257 Object self(&scope, args.get(0)); 1258 if (!self.isDictValueIterator()) { 1259 return thread->raiseRequiresType(self, ID(dict_valueiterator)); 1260 } 1261 DictValueIterator iter(&scope, *self); 1262 Object value(&scope, dictValueIteratorNext(thread, iter)); 1263 if (value.isError()) { 1264 return thread->raise(LayoutId::kStopIteration, NoneType::object()); 1265 } 1266 return *value; 1267} 1268 1269RawObject METH(dict_valueiterator, __length_hint__)(Thread* thread, 1270 Arguments args) { 1271 HandleScope scope(thread); 1272 Object self(&scope, args.get(0)); 1273 if (!self.isDictValueIterator()) { 1274 return thread->raiseRequiresType(self, ID(dict_valueiterator)); 1275 } 1276 DictValueIterator iter(&scope, *self); 1277 Dict dict(&scope, iter.iterable()); 1278 return SmallInt::fromWord(dict.numItems() - iter.numFound()); 1279} 1280 1281RawObject METH(dict_values, __iter__)(Thread* thread, Arguments args) { 1282 HandleScope scope(thread); 1283 Object self(&scope, args.get(0)); 1284 if (!self.isDictValues()) { 1285 return thread->raiseRequiresType(self, ID(dict_values)); 1286 } 1287 1288 Dict dict(&scope, DictValues::cast(*self).dict()); 1289 return thread->runtime()->newDictValueIterator(thread, dict); 1290} 1291 1292RawObject METH(dict_values, __len__)(Thread* thread, Arguments args) { 1293 HandleScope scope(thread); 1294 Object self(&scope, args.get(0)); 1295 if (!self.isDictValues()) { 1296 return thread->raiseRequiresType(self, ID(dict_values)); 1297 } 1298 1299 Dict dict(&scope, DictValues::cast(*self).dict()); 1300 return thread->runtime()->newInt(dict.numItems()); 1301} 1302 1303} // namespace py