this repo has no description
at trunk 1208 lines 40 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "set-builtins.h" 3 4#include "builtins.h" 5#include "dict-builtins.h" 6#include "frame.h" 7#include "globals.h" 8#include "objects.h" 9#include "runtime.h" 10#include "thread.h" 11#include "type-builtins.h" 12 13namespace py { 14// Data tuple layout 15static const word kHashOffset = 0; 16static const word kValueOffset = kHashOffset + 1; 17static const word kNumPointers = kValueOffset + 1; 18 19static word getIndex(RawTuple data, word hash) { 20 DCHECK(SmallInt::isValid(hash), "hash out of range"); 21 word nitems = data.length() / kNumPointers; 22 DCHECK(Utils::isPowerOfTwo(nitems), "%ld not a power of 2", nitems); 23 return (hash & (nitems - 1)) * kNumPointers; 24} 25 26static bool isEmpty(RawTuple data, word index) { 27 return data.at(index + kHashOffset).isNoneType(); 28} 29 30static bool isFull(RawTuple data, word index) { 31 return data.at(index + kHashOffset).isSmallInt(); 32} 33 34static bool isTombstone(RawTuple data, word index) { 35 return data.at(index + kHashOffset).isUnbound(); 36} 37 38static word itemHash(RawTuple data, word index) { 39 return SmallInt::cast(data.at(index + kHashOffset)).value(); 40} 41 42static RawObject itemValue(RawTuple data, word index) { 43 return data.at(index + kValueOffset); 44} 45 46static void itemAtPut(RawTuple data, word index, word hash, RawObject value) { 47 data.atPut(index + kHashOffset, SmallInt::fromWordTruncated(hash)); 48 data.atPut(index + kValueOffset, value); 49} 50 51static void itemAtPutTombstone(RawTuple data, word index) { 52 data.atPut(index + kHashOffset, Unbound::object()); 53 data.atPut(index + kValueOffset, NoneType::object()); 54} 55 56static word nextItemIndex(RawTuple data, word* index) { 57 for (word i = *index; i < data.length(); i += kNumPointers) { 58 if (!isFull(data, i)) continue; 59 *index = i + kNumPointers; 60 return i; 61 } 62 return -1; 63} 64 65bool setNextItem(const SetBase& set, word* index, RawObject* value_out) { 66 RawTuple data = RawTuple::cast(set.data()); 67 word next_item_index = nextItemIndex(data, index); 68 if (next_item_index < 0) { 69 return false; 70 } 71 *value_out = itemValue(data, next_item_index); 72 return true; 73} 74 75bool setNextItemHash(const SetBase& set, word* index, RawObject* value_out, 76 word* hash_out) { 77 DCHECK(hash_out != nullptr, "hash_out must not be null"); 78 RawTuple data = RawTuple::cast(set.data()); 79 word next_item_index = nextItemIndex(data, index); 80 if (next_item_index < 0) { 81 return false; 82 } 83 *value_out = itemValue(data, next_item_index); 84 *hash_out = itemHash(data, next_item_index); 85 86 return true; 87} 88 89static word entryMatches(Thread* thread, RawTuple data, word entry, 90 word hash_value, const Object& key) { 91 DCHECK(isFull(data, entry), "entry cannot be a tombstone"); 92 if (itemHash(data, entry) == hash_value) { 93 RawObject start_key = itemValue(data, entry); 94 RawObject eq = Runtime::objectEquals(thread, start_key, *key); 95 if (eq == Bool::trueObj()) { 96 return entry; 97 } 98 if (eq.isErrorException()) { 99 UNIMPLEMENTED("exception in value comparison"); 100 } 101 return -1; 102 } 103 return -1; 104} 105 106static const word kNumLinearProbes = 9; 107static const word kPerturbShift = 5; 108 109static word setLookup(Thread* thread, const Tuple& data, const Object& key, 110 word hash_value) { 111 word length = data.length(); 112 if (length == 0) { 113 return -1; 114 } 115 uword perturb = static_cast<uword>(hash_value); 116 word mask = length - 1; 117 word i = hash_value & mask; 118 word entry = getIndex(*data, i); 119 120 if (isEmpty(*data, entry)) { 121 return -1; 122 } 123 124 for (;;) { 125 if (isFull(*data, entry)) { 126 word match = entryMatches(thread, *data, entry, hash_value, key); 127 if (match != -1) { 128 return match; 129 } 130 } 131 if (entry + kNumLinearProbes * kNumPointers <= mask) { 132 for (int j = 1; j <= kNumLinearProbes; j++) { 133 entry += kNumPointers; 134 if (isEmpty(*data, entry)) { 135 return -1; 136 } 137 if (!isTombstone(*data, entry)) { 138 word match = entryMatches(thread, *data, entry, hash_value, key); 139 if (match != -1) { 140 return match; 141 } 142 } 143 } 144 } 145 perturb >>= kPerturbShift; 146 i = (i * 5 + 1 + perturb) & mask; 147 entry = getIndex(*data, i); 148 if (isEmpty(*data, entry)) { 149 return -1; 150 } 151 } 152} 153 154static word setLookupForInsertion(Thread* thread, const Tuple& data, 155 const Object& key, word hash_value) { 156 word length = data.length(); 157 if (length == 0) { 158 return -1; 159 } 160 uword perturb = static_cast<uword>(hash_value); 161 word mask = length - 1; 162 word i = hash_value & mask; 163 word entry = getIndex(*data, i); 164 165 if (isEmpty(*data, entry)) { 166 return entry; 167 } 168 169 for (word freeslot = -1;;) { 170 if (isFull(*data, entry)) { 171 word match = entryMatches(thread, *data, entry, hash_value, key); 172 if (match != -1) { 173 return match; 174 } 175 } else if (isTombstone(*data, entry)) { 176 freeslot = entry; 177 } 178 if (entry + kNumLinearProbes * kNumPointers <= mask) { 179 for (int j = 1; j <= kNumLinearProbes; j++) { 180 entry += kNumPointers; 181 if (isEmpty(*data, entry)) { 182 return entry; 183 } 184 if (!isTombstone(*data, entry)) { 185 word match = entryMatches(thread, *data, entry, hash_value, key); 186 if (match != -1) { 187 return match; 188 } 189 } else if (isTombstone(*data, entry)) { 190 freeslot = entry; 191 } 192 } 193 } 194 perturb >>= kPerturbShift; 195 i = (i * 5 + 1 + perturb) & mask; 196 entry = getIndex(*data, i); 197 if (isEmpty(*data, entry)) { 198 return (freeslot == -1) ? entry : freeslot; 199 } 200 } 201} 202 203static RawTuple setGrow(Thread* thread, const SetBase& set) { 204 HandleScope scope(thread); 205 Tuple data(&scope, set.data()); 206 word new_length = data.length() * Runtime::kSetGrowthFactor; 207 if (new_length == 0) { 208 new_length = Runtime::kInitialSetCapacity * kNumPointers; 209 } 210 MutableTuple new_data(&scope, thread->runtime()->newMutableTuple(new_length)); 211 new_data.fill(NoneType::object()); 212 // Re-insert items 213 Object value(&scope, NoneType::object()); 214 for (word i = 0, hash; setNextItemHash(set, &i, &value, &hash);) { 215 word index = setLookupForInsertion(thread, new_data, value, hash); 216 DCHECK(index != -1, "unexpected index %ld", index); 217 itemAtPut(*new_data, index, hash, *value); 218 } 219 set.setNumFilled(set.numItems()); 220 return *new_data; 221} 222 223RawObject setAdd(Thread* thread, const SetBase& set, const Object& value, 224 word hash) { 225 HandleScope scope(thread); 226 Tuple data(&scope, set.data()); 227 word index = setLookup(thread, data, value, hash); 228 if (index != -1) { 229 return itemValue(*data, index); 230 } 231 232 Tuple new_data(&scope, *data); 233 if (data.length() == 0 || 10 * set.numFilled() >= 3 * data.length()) { 234 new_data = setGrow(thread, set); 235 } 236 index = setLookupForInsertion(thread, new_data, value, hash); 237 DCHECK(index != -1, "unexpected index %ld", index); 238 set.setData(*new_data); 239 itemAtPut(*new_data, index, hash, *value); 240 set.setNumItems(set.numItems() + 1); 241 set.setNumFilled(set.numFilled() + 1); 242 return *value; 243} 244 245bool setIncludes(Thread* thread, const SetBase& set, const Object& key, 246 word hash) { 247 HandleScope scope(thread); 248 Tuple data(&scope, set.data()); 249 return setLookup(thread, data, key, hash) != -1; 250} 251 252RawObject setIntersection(Thread* thread, const SetBase& set, 253 const Object& iterable) { 254 HandleScope scope(thread); 255 Runtime* runtime = thread->runtime(); 256 SetBase dst(&scope, runtime->isInstanceOfSet(*set) ? runtime->newSet() 257 : runtime->newFrozenSet()); 258 Object value(&scope, NoneType::object()); 259 // Special case for sets 260 if (runtime->isInstanceOfSetBase(*iterable)) { 261 SetBase self(&scope, *set); 262 SetBase other(&scope, *iterable); 263 if (set.numItems() == 0 || other.numItems() == 0) { 264 return *dst; 265 } 266 // Iterate over the smaller set 267 if (set.numItems() > other.numItems()) { 268 self = *iterable; 269 other = *set; 270 } 271 Tuple other_data(&scope, other.data()); 272 for (word i = 0, hash; setNextItemHash(self, &i, &value, &hash);) { 273 if (setLookup(thread, other_data, value, hash) != -1) { 274 setAdd(thread, dst, value, hash); 275 } 276 } 277 return *dst; 278 } 279 // Generic case 280 Object iter_method(&scope, 281 Interpreter::lookupMethod(thread, iterable, ID(__iter__))); 282 if (iter_method.isError()) { 283 return thread->raiseWithFmt(LayoutId::kTypeError, "object is not iterable"); 284 } 285 Object iterator(&scope, 286 Interpreter::callMethod1(thread, iter_method, iterable)); 287 if (iterator.isError()) { 288 return thread->raiseWithFmt(LayoutId::kTypeError, "object is not iterable"); 289 } 290 Object next_method(&scope, 291 Interpreter::lookupMethod(thread, iterator, ID(__next__))); 292 if (next_method.isError()) { 293 return thread->raiseWithFmt(LayoutId::kTypeError, 294 "iter() returned a non-iterator"); 295 } 296 if (set.numItems() == 0) { 297 return *dst; 298 } 299 Tuple data(&scope, set.data()); 300 Object hash_obj(&scope, NoneType::object()); 301 for (;;) { 302 value = Interpreter::callMethod1(thread, next_method, iterator); 303 if (value.isError()) { 304 if (thread->clearPendingStopIteration()) break; 305 return *value; 306 } 307 hash_obj = Interpreter::hash(thread, value); 308 if (hash_obj.isErrorException()) return *hash_obj; 309 word hash = SmallInt::cast(*hash_obj).value(); 310 if (setLookup(thread, data, value, hash) != -1) { 311 setAdd(thread, dst, value, hash); 312 } 313 } 314 return *dst; 315} 316 317bool setRemove(Thread* thread, const Set& set, const Object& key, word hash) { 318 HandleScope scope(thread); 319 Tuple data(&scope, set.data()); 320 word index = setLookup(thread, data, key, hash); 321 if (index != -1) { 322 itemAtPutTombstone(*data, index); 323 set.setNumItems(set.numItems() - 1); 324 return true; 325 } 326 return false; 327} 328 329RawObject setUpdate(Thread* thread, const SetBase& dst, 330 const Object& iterable) { 331 HandleScope scope(thread); 332 Object elt(&scope, NoneType::object()); 333 Object hash_obj(&scope, NoneType::object()); 334 // Special case for lists 335 if (iterable.isList()) { 336 List src(&scope, *iterable); 337 for (word i = 0; i < src.numItems(); i++) { 338 elt = src.at(i); 339 hash_obj = Interpreter::hash(thread, elt); 340 if (hash_obj.isErrorException()) return *hash_obj; 341 word hash = SmallInt::cast(*hash_obj).value(); 342 setAdd(thread, dst, elt, hash); 343 } 344 return *dst; 345 } 346 // Special case for lists iterators 347 if (iterable.isListIterator()) { 348 ListIterator list_iter(&scope, *iterable); 349 List src(&scope, list_iter.iterable()); 350 for (word i = 0; i < src.numItems(); i++) { 351 elt = src.at(i); 352 hash_obj = Interpreter::hash(thread, elt); 353 if (hash_obj.isErrorException()) return *hash_obj; 354 word hash = SmallInt::cast(*hash_obj).value(); 355 setAdd(thread, dst, elt, hash); 356 } 357 } 358 // Special case for tuples 359 if (iterable.isTuple()) { 360 Tuple tuple(&scope, *iterable); 361 if (tuple.length() > 0) { 362 for (word i = 0; i < tuple.length(); i++) { 363 elt = tuple.at(i); 364 hash_obj = Interpreter::hash(thread, elt); 365 if (hash_obj.isErrorException()) return *hash_obj; 366 word hash = SmallInt::cast(*hash_obj).value(); 367 setAdd(thread, dst, elt, hash); 368 } 369 } 370 return *dst; 371 } 372 // Special case for built-in set types 373 if (thread->runtime()->isInstanceOfSetBase(*iterable)) { 374 SetBase src(&scope, *iterable); 375 if (src.numItems() > 0) { 376 for (word i = 0, hash; setNextItemHash(src, &i, &elt, &hash);) { 377 // take hash from data to avoid recomputing it. 378 setAdd(thread, dst, elt, hash); 379 } 380 } 381 return *dst; 382 } 383 // Special case for dicts 384 if (iterable.isDict()) { 385 Dict dict(&scope, *iterable); 386 for (word i = 0, hash; dictNextKeyHash(dict, &i, &elt, &hash);) { 387 setAdd(thread, dst, elt, hash); 388 } 389 return *dst; 390 } 391 // Generic case 392 Object iter_method(&scope, 393 Interpreter::lookupMethod(thread, iterable, ID(__iter__))); 394 if (iter_method.isError()) { 395 return thread->raiseWithFmt(LayoutId::kTypeError, 396 "'%T' object is not iterable", &iterable); 397 } 398 Object iterator(&scope, 399 Interpreter::callMethod1(thread, iter_method, iterable)); 400 if (iterator.isError()) { 401 return thread->raiseWithFmt(LayoutId::kTypeError, 402 "'%T' object is not iterable", &iterable); 403 } 404 Object next_method(&scope, 405 Interpreter::lookupMethod(thread, iterator, ID(__next__))); 406 if (next_method.isError()) { 407 return thread->raiseWithFmt(LayoutId::kTypeError, 408 "iter() returned a non-iterator"); 409 } 410 for (;;) { 411 elt = Interpreter::callMethod1(thread, next_method, iterator); 412 if (elt.isError()) { 413 if (thread->clearPendingStopIteration()) break; 414 return *elt; 415 } 416 hash_obj = Interpreter::hash(thread, elt); 417 if (hash_obj.isErrorException()) return *hash_obj; 418 word hash = SmallInt::cast(*hash_obj).value(); 419 setAdd(thread, dst, elt, hash); 420 } 421 return *dst; 422} 423 424RawSmallInt frozensetHash(Thread* thread, const Object& frozenset) { 425 HandleScope scope(thread); 426 FrozenSet set(&scope, *frozenset); 427 uword result = 0; 428 Object value(&scope, NoneType::object()); 429 for (word i = 0, value_hash; setNextItemHash(set, &i, &value, &value_hash);) { 430 uword h = static_cast<uword>(value_hash); 431 result ^= ((h ^ uword{89869747}) ^ (h << 16)) * uword{3644798167}; 432 } 433 result ^= static_cast<uword>(set.numItems() + 1) * uword{1927868237}; 434 435 result ^= (result >> 11) ^ (result >> 25); 436 result = result * uword{69069} + uword{907133923}; 437 438 // cpython replaces `-1` results with -2, because -1 is used as an 439 // "uninitialized hash" marker in some situations. We do not use the same 440 // marker, but do the same to match behavior. 441 if (result == static_cast<uword>(word{-1})) { 442 result--; 443 } 444 return SmallInt::fromWordTruncated(result); 445} 446 447static RawObject dunderLenImpl(Thread* thread, Arguments args, SymbolId id) { 448 HandleScope scope(thread); 449 Object self(&scope, args.get(0)); 450 if (!thread->runtime()->isInstanceOfSetBase(*self)) { 451 return thread->raiseRequiresType(self, id); 452 } 453 SetBase set(&scope, *self); 454 return SmallInt::fromWord(set.numItems()); 455} 456 457static RawObject dunderContainsImpl(Thread* thread, Arguments args, 458 SymbolId id) { 459 HandleScope scope(thread); 460 Object self(&scope, args.get(0)); 461 if (!thread->runtime()->isInstanceOfSetBase(*self)) { 462 return thread->raiseRequiresType(self, id); 463 } 464 SetBase set(&scope, *self); 465 Object key(&scope, args.get(1)); 466 Object hash_obj(&scope, Interpreter::hash(thread, key)); 467 if (hash_obj.isErrorException()) return *hash_obj; 468 word hash = SmallInt::cast(*hash_obj).value(); 469 return Bool::fromBool(setIncludes(thread, set, key, hash)); 470} 471 472static RawObject dunderIterImpl(Thread* thread, Arguments args, SymbolId id) { 473 HandleScope scope(thread); 474 Object self(&scope, args.get(0)); 475 if (!thread->runtime()->isInstanceOfSetBase(*self)) { 476 return thread->raiseRequiresType(self, id); 477 } 478 return thread->runtime()->newSetIterator(self); 479} 480 481static RawObject isdisjointImpl(Thread* thread, Arguments args, SymbolId id) { 482 HandleScope scope(thread); 483 Object self(&scope, args.get(0)); 484 Object other(&scope, args.get(1)); 485 Object value(&scope, NoneType::object()); 486 if (!thread->runtime()->isInstanceOfSetBase(*self)) { 487 return thread->raiseRequiresType(self, id); 488 } 489 SetBase a(&scope, *self); 490 if (a.numItems() == 0) { 491 return Bool::trueObj(); 492 } 493 if (thread->runtime()->isInstanceOfSetBase(*other)) { 494 SetBase b(&scope, *other); 495 if (b.numItems() == 0) { 496 return Bool::trueObj(); 497 } 498 // Iterate over the smaller set 499 if (a.numItems() > b.numItems()) { 500 a = *other; 501 b = *self; 502 } 503 for (word i = 0, hash; setNextItemHash(a, &i, &value, &hash);) { 504 if (setIncludes(thread, b, value, hash)) { 505 return Bool::falseObj(); 506 } 507 } 508 return Bool::trueObj(); 509 } 510 // Generic iterator case 511 Object iter_method(&scope, 512 Interpreter::lookupMethod(thread, other, ID(__iter__))); 513 if (iter_method.isError()) { 514 return thread->raiseWithFmt(LayoutId::kTypeError, "object is not iterable"); 515 } 516 Object iterator(&scope, Interpreter::callMethod1(thread, iter_method, other)); 517 if (iterator.isError()) { 518 return thread->raiseWithFmt(LayoutId::kTypeError, "object is not iterable"); 519 } 520 Object next_method(&scope, 521 Interpreter::lookupMethod(thread, iterator, ID(__next__))); 522 if (next_method.isError()) { 523 return thread->raiseWithFmt(LayoutId::kTypeError, 524 "iter() returned a non-iterator"); 525 } 526 Object hash_obj(&scope, NoneType::object()); 527 for (;;) { 528 value = Interpreter::callMethod1(thread, next_method, iterator); 529 if (value.isError()) { 530 if (thread->clearPendingStopIteration()) break; 531 return *value; 532 } 533 hash_obj = Interpreter::hash(thread, value); 534 if (hash_obj.isErrorException()) return *hash_obj; 535 word hash = SmallInt::cast(*hash_obj).value(); 536 if (setIncludes(thread, a, value, hash)) { 537 return Bool::falseObj(); 538 } 539 } 540 return Bool::trueObj(); 541} 542 543static RawObject intersectionImpl(Thread* thread, Arguments args, SymbolId id) { 544 HandleScope scope(thread); 545 Object self(&scope, args.get(0)); 546 if (!thread->runtime()->isInstanceOfSetBase(*self)) { 547 return thread->raiseRequiresType(self, id); 548 } 549 SetBase set(&scope, *self); 550 Object other(&scope, args.get(1)); 551 return setIntersection(thread, set, other); 552} 553 554static RawObject dunderEqImpl(Thread* thread, Arguments args, SymbolId id) { 555 Runtime* runtime = thread->runtime(); 556 HandleScope scope(thread); 557 Object self(&scope, args.get(0)); 558 Object other(&scope, args.get(1)); 559 if (!runtime->isInstanceOfSetBase(*self)) { 560 return thread->raiseRequiresType(self, id); 561 } 562 if (!runtime->isInstanceOfSetBase(*other)) { 563 return NotImplementedType::object(); 564 } 565 SetBase set(&scope, *self); 566 SetBase other_set(&scope, *other); 567 return Bool::fromBool(setEquals(thread, set, other_set)); 568} 569 570static RawObject dunderNeImpl(Thread* thread, Arguments args, SymbolId id) { 571 Runtime* runtime = thread->runtime(); 572 HandleScope scope(thread); 573 Object self(&scope, args.get(0)); 574 Object other(&scope, args.get(1)); 575 if (!runtime->isInstanceOfSetBase(*self)) { 576 return thread->raiseRequiresType(self, id); 577 } 578 if (!runtime->isInstanceOfSetBase(*other)) { 579 return NotImplementedType::object(); 580 } 581 SetBase set(&scope, *self); 582 SetBase other_set(&scope, *other); 583 return Bool::fromBool(!setEquals(thread, set, other_set)); 584} 585 586static RawObject dunderLeImpl(Thread* thread, Arguments args, SymbolId id) { 587 Runtime* runtime = thread->runtime(); 588 HandleScope scope(thread); 589 Object self(&scope, args.get(0)); 590 Object other(&scope, args.get(1)); 591 if (!runtime->isInstanceOfSetBase(*self)) { 592 return thread->raiseRequiresType(self, id); 593 } 594 if (!runtime->isInstanceOfSetBase(*other)) { 595 return NotImplementedType::object(); 596 } 597 SetBase set(&scope, *self); 598 SetBase other_set(&scope, *other); 599 return Bool::fromBool(setIsSubset(thread, set, other_set)); 600} 601 602static RawObject dunderLtImpl(Thread* thread, Arguments args, SymbolId id) { 603 Runtime* runtime = thread->runtime(); 604 HandleScope scope(thread); 605 Object self(&scope, args.get(0)); 606 Object other(&scope, args.get(1)); 607 if (!runtime->isInstanceOfSetBase(*self)) { 608 return thread->raiseRequiresType(self, id); 609 } 610 if (!runtime->isInstanceOfSetBase(*other)) { 611 return NotImplementedType::object(); 612 } 613 SetBase set(&scope, *self); 614 SetBase other_set(&scope, *other); 615 return Bool::fromBool(setIsProperSubset(thread, set, other_set)); 616} 617 618static RawObject dunderGeImpl(Thread* thread, Arguments args, SymbolId id) { 619 Runtime* runtime = thread->runtime(); 620 HandleScope scope(thread); 621 Object self(&scope, args.get(0)); 622 Object other(&scope, args.get(1)); 623 if (!runtime->isInstanceOfSetBase(*self)) { 624 return thread->raiseRequiresType(self, id); 625 } 626 if (!runtime->isInstanceOfSetBase(*other)) { 627 return NotImplementedType::object(); 628 } 629 SetBase set(&scope, *self); 630 SetBase other_set(&scope, *other); 631 return Bool::fromBool(setIsSubset(thread, other_set, set)); 632} 633 634static RawObject dunderGtImpl(Thread* thread, Arguments args, SymbolId id) { 635 Runtime* runtime = thread->runtime(); 636 HandleScope scope(thread); 637 Object self(&scope, args.get(0)); 638 Object other(&scope, args.get(1)); 639 if (!runtime->isInstanceOfSetBase(*self)) { 640 return thread->raiseRequiresType(self, id); 641 } 642 if (!runtime->isInstanceOfSetBase(*other)) { 643 return NotImplementedType::object(); 644 } 645 SetBase set(&scope, *self); 646 SetBase other_set(&scope, *other); 647 return Bool::fromBool(setIsProperSubset(thread, other_set, set)); 648} 649 650static const BuiltinAttribute kFrozenSetAttributes[] = { 651 {ID(_frozenset__data), RawFrozenSet::kDataOffset, AttributeFlags::kHidden}, 652 {ID(_frozenset__num_items), RawFrozenSet::kNumItemsOffset, 653 AttributeFlags::kHidden}, 654 {ID(_frozenset__num_filled), RawFrozenSet::kNumFilledOffset, 655 AttributeFlags::kHidden}, 656}; 657 658RawObject METH(frozenset, __and__)(Thread* thread, Arguments args) { 659 HandleScope scope(thread); 660 Object self(&scope, args.get(0)); 661 Object other(&scope, args.get(1)); 662 Runtime* runtime = thread->runtime(); 663 if (!runtime->isInstanceOfFrozenSet(*self)) { 664 return thread->raiseRequiresType(self, ID(frozenset)); 665 } 666 if (!runtime->isInstanceOfSetBase(*other)) { 667 return NotImplementedType::object(); 668 } 669 FrozenSet set(&scope, *self); 670 SetBase other_set(&scope, *other); 671 return setIntersection(thread, set, other_set); 672} 673 674RawObject METH(frozenset, __contains__)(Thread* thread, Arguments args) { 675 return dunderContainsImpl(thread, args, ID(frozenset)); 676} 677 678RawObject METH(frozenset, __eq__)(Thread* thread, Arguments args) { 679 return dunderEqImpl(thread, args, ID(frozenset)); 680} 681 682RawObject METH(frozenset, __ge__)(Thread* thread, Arguments args) { 683 return dunderGeImpl(thread, args, ID(frozenset)); 684} 685 686RawObject METH(frozenset, __gt__)(Thread* thread, Arguments args) { 687 return dunderGtImpl(thread, args, ID(frozenset)); 688} 689 690RawObject METH(frozenset, __hash__)(Thread* thread, Arguments args) { 691 HandleScope scope(thread); 692 Object self(&scope, args.get(0)); 693 if (!thread->runtime()->isInstanceOfFrozenSet(*self)) { 694 return thread->raiseRequiresType(self, ID(frozenset)); 695 } 696 FrozenSet set(&scope, *self); 697 return frozensetHash(thread, set); 698} 699 700RawObject METH(frozenset, __iter__)(Thread* thread, Arguments args) { 701 return dunderIterImpl(thread, args, ID(frozenset)); 702} 703 704RawObject METH(frozenset, __le__)(Thread* thread, Arguments args) { 705 return dunderLeImpl(thread, args, ID(frozenset)); 706} 707 708RawObject METH(frozenset, __len__)(Thread* thread, Arguments args) { 709 return dunderLenImpl(thread, args, ID(frozenset)); 710} 711 712RawObject METH(frozenset, __lt__)(Thread* thread, Arguments args) { 713 return dunderLtImpl(thread, args, ID(frozenset)); 714} 715 716RawObject METH(frozenset, __ne__)(Thread* thread, Arguments args) { 717 return dunderNeImpl(thread, args, ID(frozenset)); 718} 719 720RawObject METH(frozenset, __new__)(Thread* thread, Arguments args) { 721 HandleScope scope(thread); 722 Object type_obj(&scope, args.get(0)); 723 Runtime* runtime = thread->runtime(); 724 if (!runtime->isInstanceOfType(*type_obj)) { 725 return thread->raiseRequiresType(type_obj, ID(type)); 726 } 727 Type type(&scope, *type_obj); 728 if (type.builtinBase() != LayoutId::kFrozenSet) { 729 return thread->raiseWithFmt(LayoutId::kTypeError, 730 "not a subtype of frozenset"); 731 } 732 if (args.get(1).isUnbound()) { 733 // Iterable not provided 734 if (type.isBuiltin() && type.builtinBase() == LayoutId::kFrozenSet) { 735 // Called with exact frozenset type, should return singleton 736 return runtime->emptyFrozenSet(); 737 } 738 // Not called with exact frozenset type, should return new distinct 739 // frozenset 740 Layout layout(&scope, type.instanceLayout()); 741 FrozenSet result(&scope, runtime->newInstance(layout)); 742 result.setNumItems(0); 743 result.setNumFilled(0); 744 result.setData(runtime->emptyTuple()); 745 return *result; 746 } 747 // Called with iterable, so iterate 748 Object iterable(&scope, args.get(1)); 749 // frozenset(f) where f is a frozenset is idempotent 750 if (iterable.isFrozenSet()) { 751 return *iterable; 752 } 753 Object dunder_iter(&scope, 754 Interpreter::lookupMethod(thread, iterable, ID(__iter__))); 755 if (dunder_iter.isError()) { 756 return thread->raiseWithFmt( 757 LayoutId::kTypeError, 758 "frozenset.__new__ must be called with an iterable"); 759 } 760 if (type.isBuiltin() && type.builtinBase() == LayoutId::kFrozenSet) { 761 // Called with exact frozenset type 762 FrozenSet result(&scope, runtime->newFrozenSet()); 763 RawObject maybe_error = setUpdate(thread, result, iterable); 764 if (maybe_error.isError()) return maybe_error; 765 result = maybe_error; 766 if (result.numItems() == 0) { 767 return runtime->emptyFrozenSet(); 768 } 769 return *result; 770 } 771 // Not called with exact frozenset type, should return new frozenset subclass 772 Layout layout(&scope, type.instanceLayout()); 773 FrozenSet result(&scope, runtime->newInstance(layout)); 774 result.setNumItems(0); 775 result.setNumFilled(0); 776 result.setData(runtime->emptyTuple()); 777 return setUpdate(thread, result, iterable); 778} 779 780RawObject METH(frozenset, __or__)(Thread* thread, Arguments args) { 781 HandleScope scope(thread); 782 Object self_obj(&scope, args.get(0)); 783 Object other(&scope, args.get(1)); 784 Runtime* runtime = thread->runtime(); 785 if (!runtime->isInstanceOfFrozenSet(*self_obj)) { 786 return thread->raiseRequiresType(self_obj, ID(frozenset)); 787 } 788 if (!runtime->isInstanceOfSetBase(*other)) { 789 return NotImplementedType::object(); 790 } 791 FrozenSet self(&scope, *self_obj); 792 if (*self == *other) { 793 // Make a shallow copy; we can alias the underlying immutable data 794 // structure 795 FrozenSet result(&scope, runtime->newFrozenSet()); 796 result.setData(self.data()); 797 result.setNumItems(self.numItems()); 798 result.setNumFilled(self.numFilled()); 799 return *result; 800 } 801 FrozenSet result(&scope, runtime->newFrozenSet()); 802 Object maybe_error(&scope, setUpdate(thread, result, self)); 803 if (maybe_error.isError()) return *maybe_error; 804 result = *maybe_error; 805 return setUpdate(thread, result, other); 806} 807 808RawObject METH(frozenset, copy)(Thread* thread, Arguments args) { 809 HandleScope scope(thread); 810 Object self(&scope, args.get(0)); 811 if (!thread->runtime()->isInstanceOfFrozenSet(*self)) { 812 return thread->raiseRequiresType(self, ID(frozenset)); 813 } 814 FrozenSet set(&scope, *self); 815 if (set.isFrozenSet()) { 816 return *set; 817 } 818 return setCopy(thread, set); 819} 820 821RawObject METH(frozenset, intersection)(Thread* thread, Arguments args) { 822 return intersectionImpl(thread, args, ID(frozenset)); 823} 824 825RawObject METH(frozenset, isdisjoint)(Thread* thread, Arguments args) { 826 return isdisjointImpl(thread, args, ID(frozenset)); 827} 828 829RawObject setCopy(Thread* thread, const SetBase& set) { 830 word num_items = set.numItems(); 831 Runtime* runtime = thread->runtime(); 832 if (num_items == 0) { 833 return runtime->isInstanceOfSet(*set) ? runtime->newSet() 834 : runtime->emptyFrozenSet(); 835 } 836 837 HandleScope scope(thread); 838 SetBase new_set(&scope, runtime->isInstanceOfSet(*set) 839 ? runtime->newSet() 840 : runtime->newFrozenSet()); 841 Tuple data(&scope, set.data()); 842 MutableTuple new_data(&scope, runtime->newMutableTuple(data.length())); 843 new_data.fill(NoneType::object()); 844 Object value(&scope, NoneType::object()); 845 for (word i = 0, hash; setNextItemHash(set, &i, &value, &hash);) { 846 word dst_index = i - kNumPointers; 847 itemAtPut(*new_data, dst_index, hash, *value); 848 } 849 new_set.setData(*new_data); 850 new_set.setNumItems(set.numItems()); 851 new_set.setNumFilled(set.numItems()); 852 return *new_set; 853} 854 855bool setIsSubset(Thread* thread, const SetBase& set, const SetBase& other) { 856 HandleScope scope(thread); 857 Object value(&scope, NoneType::object()); 858 for (word i = 0, hash; setNextItemHash(set, &i, &value, &hash);) { 859 if (!setIncludes(thread, other, value, hash)) { 860 return false; 861 } 862 } 863 return true; 864} 865 866bool setIsProperSubset(Thread* thread, const SetBase& set, 867 const SetBase& other) { 868 if (set.numItems() == other.numItems()) { 869 return false; 870 } 871 return setIsSubset(thread, set, other); 872} 873 874bool setEquals(Thread* thread, const SetBase& set, const SetBase& other) { 875 if (set.numItems() != other.numItems()) { 876 return false; 877 } 878 if (*set == *other) { 879 return true; 880 } 881 return setIsSubset(thread, set, other); 882} 883 884RawObject setPop(Thread* thread, const Set& set) { 885 HandleScope scope(thread); 886 Tuple data(&scope, set.data()); 887 word num_items = set.numItems(); 888 if (num_items != 0) { 889 Object value(&scope, NoneType::object()); 890 for (word i = 0; setNextItem(set, &i, &value);) { 891 itemAtPutTombstone(*data, i - kNumPointers); 892 set.setNumItems(num_items - 1); 893 return *value; 894 } 895 } 896 // num_items == 0 or all items were found empty 897 return thread->raiseWithFmt(LayoutId::kKeyError, "pop from an empty set"); 898} 899 900RawObject setIteratorNext(Thread* thread, const SetIterator& iter) { 901 word idx = iter.index(); 902 HandleScope scope(thread); 903 SetBase underlying(&scope, iter.iterable()); 904 Object value(&scope, NoneType::object()); 905 // Find the next non empty item 906 if (!setNextItem(underlying, &idx, &value)) { 907 return Error::noMoreItems(); 908 } 909 iter.setConsumedCount(iter.consumedCount() + 1); 910 iter.setIndex(idx); 911 return *value; 912} 913 914static const BuiltinAttribute kSetAttributes[] = { 915 {ID(_set__data), RawSet::kDataOffset, AttributeFlags::kHidden}, 916 {ID(_set__num_items), RawSet::kNumItemsOffset, AttributeFlags::kHidden}, 917 {ID(_set__num_filled), RawSet::kNumFilledOffset, AttributeFlags::kHidden}, 918}; 919 920RawObject METH(set, __and__)(Thread* thread, Arguments args) { 921 HandleScope scope(thread); 922 Object self(&scope, args.get(0)); 923 Object other(&scope, args.get(1)); 924 Runtime* runtime = thread->runtime(); 925 if (!runtime->isInstanceOfSet(*self)) { 926 return thread->raiseRequiresType(self, ID(set)); 927 } 928 if (!runtime->isInstanceOfSetBase(*other)) { 929 return NotImplementedType::object(); 930 } 931 Set set(&scope, *self); 932 SetBase other_set(&scope, *other); 933 return setIntersection(thread, set, other_set); 934} 935 936RawObject METH(set, __contains__)(Thread* thread, Arguments args) { 937 return dunderContainsImpl(thread, args, ID(set)); 938} 939 940RawObject METH(set, __eq__)(Thread* thread, Arguments args) { 941 return dunderEqImpl(thread, args, ID(set)); 942} 943 944RawObject METH(set, __ge__)(Thread* thread, Arguments args) { 945 return dunderGeImpl(thread, args, ID(set)); 946} 947 948RawObject METH(set, __gt__)(Thread* thread, Arguments args) { 949 return dunderGtImpl(thread, args, ID(set)); 950} 951 952RawObject METH(set, __iand__)(Thread* thread, Arguments args) { 953 HandleScope scope(thread); 954 Object self(&scope, args.get(0)); 955 Object other(&scope, args.get(1)); 956 Runtime* runtime = thread->runtime(); 957 if (!runtime->isInstanceOfSet(*self)) { 958 return thread->raiseRequiresType(self, ID(set)); 959 } 960 if (!runtime->isInstanceOfSet(*other)) { 961 return NotImplementedType::object(); 962 } 963 Set set(&scope, *self); 964 Object intersection(&scope, setIntersection(thread, set, other)); 965 if (intersection.isError()) { 966 return *intersection; 967 } 968 RawSet intersection_set = Set::cast(*intersection); 969 set.setData(intersection_set.data()); 970 set.setNumItems(intersection_set.numItems()); 971 set.setNumFilled(intersection_set.numFilled()); 972 return *set; 973} 974 975RawObject METH(set, __init__)(Thread* thread, Arguments args) { 976 Runtime* runtime = thread->runtime(); 977 HandleScope scope(thread); 978 Object self(&scope, args.get(0)); 979 if (!runtime->isInstanceOfSet(*self)) { 980 return thread->raiseRequiresType(self, ID(set)); 981 } 982 Set set(&scope, *self); 983 Object iterable(&scope, args.get(1)); 984 Object result(&scope, setUpdate(thread, set, iterable)); 985 if (result.isError()) { 986 return *result; 987 } 988 return NoneType::object(); 989} 990 991RawObject METH(set, __iter__)(Thread* thread, Arguments args) { 992 return dunderIterImpl(thread, args, ID(set)); 993} 994 995RawObject METH(set, __le__)(Thread* thread, Arguments args) { 996 return dunderLeImpl(thread, args, ID(set)); 997} 998 999RawObject METH(set, __len__)(Thread* thread, Arguments args) { 1000 return dunderLenImpl(thread, args, ID(set)); 1001} 1002 1003RawObject METH(set, __lt__)(Thread* thread, Arguments args) { 1004 return dunderLtImpl(thread, args, ID(set)); 1005} 1006 1007RawObject METH(set, __ne__)(Thread* thread, Arguments args) { 1008 return dunderNeImpl(thread, args, ID(set)); 1009} 1010 1011RawObject METH(set, __new__)(Thread* thread, Arguments args) { 1012 HandleScope scope(thread); 1013 Runtime* runtime = thread->runtime(); 1014 Object type_obj(&scope, args.get(0)); 1015 if (!runtime->isInstanceOfType(*type_obj)) { 1016 return thread->raiseRequiresType(type_obj, ID(type)); 1017 } 1018 Type type(&scope, *type_obj); 1019 if (type.builtinBase() != LayoutId::kSet) { 1020 return thread->raiseWithFmt(LayoutId::kTypeError, "not a subtype of set"); 1021 } 1022 Layout layout(&scope, type.instanceLayout()); 1023 Set result(&scope, runtime->newInstance(layout)); 1024 result.setNumItems(0); 1025 result.setNumFilled(0); 1026 result.setData(runtime->emptyTuple()); 1027 return *result; 1028} 1029 1030RawObject METH(set, add)(Thread* thread, Arguments args) { 1031 HandleScope scope(thread); 1032 Object self(&scope, args.get(0)); 1033 Runtime* runtime = thread->runtime(); 1034 if (!runtime->isInstanceOfSet(*self)) { 1035 return thread->raiseRequiresType(self, ID(set)); 1036 } 1037 Set set(&scope, *self); 1038 Object value(&scope, args.get(1)); 1039 Object hash_obj(&scope, Interpreter::hash(thread, value)); 1040 if (hash_obj.isErrorException()) return *hash_obj; 1041 word hash = SmallInt::cast(*hash_obj).value(); 1042 1043 Object result(&scope, setAdd(thread, set, value, hash)); 1044 if (result.isError()) return *result; 1045 return NoneType::object(); 1046} 1047 1048RawObject METH(set, clear)(Thread* thread, Arguments args) { 1049 HandleScope scope(thread); 1050 Object self(&scope, args.get(0)); 1051 if (!thread->runtime()->isInstanceOfSet(*self)) { 1052 return thread->raiseRequiresType(self, ID(set)); 1053 } 1054 Set set(&scope, *self); 1055 if (set.numItems() == 0) { 1056 return NoneType::object(); 1057 } 1058 set.setNumItems(0); 1059 set.setNumFilled(0); 1060 MutableTuple data(&scope, set.data()); 1061 data.fill(NoneType::object()); 1062 return NoneType::object(); 1063} 1064 1065RawObject METH(set, copy)(Thread* thread, Arguments args) { 1066 HandleScope scope(thread); 1067 Object self(&scope, args.get(0)); 1068 if (!thread->runtime()->isInstanceOfSet(*self)) { 1069 return thread->raiseRequiresType(self, ID(set)); 1070 } 1071 Set set(&scope, *self); 1072 return setCopy(thread, set); 1073} 1074 1075RawObject METH(set, discard)(Thread* thread, Arguments args) { 1076 HandleScope scope(thread); 1077 Object self_obj(&scope, args.get(0)); 1078 Runtime* runtime = thread->runtime(); 1079 if (!runtime->isInstanceOfSet(*self_obj)) { 1080 return thread->raiseRequiresType(self_obj, ID(set)); 1081 } 1082 Set self(&scope, *self_obj); 1083 Object key(&scope, args.get(1)); 1084 Object hash_obj(&scope, Interpreter::hash(thread, key)); 1085 if (hash_obj.isErrorException()) return *hash_obj; 1086 word hash = SmallInt::cast(*hash_obj).value(); 1087 setRemove(thread, self, key, hash); 1088 return NoneType::object(); 1089} 1090 1091RawObject METH(set, intersection)(Thread* thread, Arguments args) { 1092 return intersectionImpl(thread, args, ID(set)); 1093} 1094 1095RawObject METH(set, isdisjoint)(Thread* thread, Arguments args) { 1096 return isdisjointImpl(thread, args, ID(set)); 1097} 1098 1099RawObject METH(set, pop)(Thread* thread, Arguments args) { 1100 HandleScope scope(thread); 1101 Object self(&scope, args.get(0)); 1102 if (!thread->runtime()->isInstanceOfSet(*self)) { 1103 return thread->raiseRequiresType(self, ID(set)); 1104 } 1105 Set set(&scope, args.get(0)); 1106 return setPop(thread, set); 1107} 1108 1109RawObject METH(set, remove)(Thread* thread, Arguments args) { 1110 HandleScope scope(thread); 1111 Object self(&scope, args.get(0)); 1112 Runtime* runtime = thread->runtime(); 1113 if (!runtime->isInstanceOfSet(*self)) { 1114 return thread->raiseRequiresType(self, ID(set)); 1115 } 1116 Set set(&scope, *self); 1117 Object key(&scope, args.get(1)); 1118 Object hash_obj(&scope, Interpreter::hash(thread, key)); 1119 if (hash_obj.isErrorException()) return *hash_obj; 1120 word hash = SmallInt::cast(*hash_obj).value(); 1121 if (!setRemove(thread, set, key, hash)) { 1122 return thread->raise(LayoutId::kKeyError, *key); 1123 } 1124 return NoneType::object(); 1125} 1126 1127RawObject METH(set, update)(Thread* thread, Arguments args) { 1128 HandleScope scope(thread); 1129 Runtime* runtime = thread->runtime(); 1130 Object self_obj(&scope, args.get(0)); 1131 if (!runtime->isInstanceOfSet(*self_obj)) { 1132 return thread->raiseRequiresType(self_obj, ID(set)); 1133 } 1134 Set self(&scope, *self_obj); 1135 Object starargs_obj(&scope, args.get(1)); 1136 if (!runtime->isInstanceOfTuple(*starargs_obj)) { 1137 return thread->raiseRequiresType(starargs_obj, ID(tuple)); 1138 } 1139 Tuple starargs(&scope, tupleUnderlying(*starargs_obj)); 1140 Object result(&scope, NoneType::object()); 1141 for (word i = 0; i < starargs.length(); i++) { 1142 Object other(&scope, starargs.at(i)); 1143 result = setUpdate(thread, self, other); 1144 if (result.isError()) { 1145 return *result; 1146 } 1147 } 1148 return NoneType::object(); 1149} 1150 1151static const BuiltinAttribute kSetIteratorAttributes[] = { 1152 {ID(_set_iterator__iterable), RawSetIterator::kIterableOffset, 1153 AttributeFlags::kHidden}, 1154 {ID(_set_iterator__index), RawSetIterator::kIndexOffset, 1155 AttributeFlags::kHidden}, 1156 {ID(_set_iterator__consumed_count), RawSetIterator::kConsumedCountOffset, 1157 AttributeFlags::kHidden}, 1158}; 1159 1160RawObject METH(set_iterator, __iter__)(Thread* thread, Arguments args) { 1161 HandleScope scope(thread); 1162 Object self(&scope, args.get(0)); 1163 if (!self.isSetIterator()) { 1164 return thread->raiseRequiresType(self, ID(set_iterator)); 1165 } 1166 return *self; 1167} 1168 1169RawObject METH(set_iterator, __next__)(Thread* thread, Arguments args) { 1170 HandleScope scope(thread); 1171 Object self_obj(&scope, args.get(0)); 1172 if (!self_obj.isSetIterator()) { 1173 return thread->raiseRequiresType(self_obj, ID(set_iterator)); 1174 } 1175 SetIterator self(&scope, *self_obj); 1176 Object value(&scope, setIteratorNext(thread, self)); 1177 if (value.isError()) { 1178 return thread->raise(LayoutId::kStopIteration, NoneType::object()); 1179 } 1180 return *value; 1181} 1182 1183RawObject METH(set_iterator, __length_hint__)(Thread* thread, Arguments args) { 1184 HandleScope scope(thread); 1185 Object self(&scope, args.get(0)); 1186 if (!self.isSetIterator()) { 1187 return thread->raiseRequiresType(self, ID(set_iterator)); 1188 } 1189 SetIterator set_iterator(&scope, *self); 1190 Set set(&scope, set_iterator.iterable()); 1191 return SmallInt::fromWord(set.numItems() - set_iterator.consumedCount()); 1192} 1193 1194void initializeSetTypes(Thread* thread) { 1195 addBuiltinType(thread, ID(set), LayoutId::kSet, 1196 /*superclass_id=*/LayoutId::kObject, kSetAttributes, 1197 Set::kSize, /*basetype=*/true); 1198 1199 addBuiltinType(thread, ID(frozenset), LayoutId::kFrozenSet, 1200 /*superclass_id=*/LayoutId::kObject, kFrozenSetAttributes, 1201 FrozenSet::kSize, /*basetype=*/true); 1202 1203 addBuiltinType(thread, ID(set_iterator), LayoutId::kSetIterator, 1204 /*superclass_id=*/LayoutId::kObject, kSetIteratorAttributes, 1205 SetIterator::kSize, /*basetype=*/false); 1206} 1207 1208} // namespace py