this repo has no description
at trunk 323 lines 11 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "tuple-builtins.h" 3 4#include "builtins.h" 5#include "dict-builtins.h" 6#include "frame.h" 7#include "globals.h" 8#include "int-builtins.h" 9#include "interpreter.h" 10#include "object-builtins.h" 11#include "objects.h" 12#include "runtime.h" 13#include "slice-builtins.h" 14#include "thread.h" 15#include "type-builtins.h" 16 17namespace py { 18 19RawObject tupleIteratorNext(Thread* thread, const TupleIterator& iter) { 20 word idx = iter.index(); 21 if (idx == iter.length()) { 22 return Error::noMoreItems(); 23 } 24 HandleScope scope(thread); 25 Tuple underlying(&scope, iter.iterable()); 26 RawObject item = underlying.at(idx); 27 iter.setIndex(idx + 1); 28 return item; 29} 30 31RawObject tupleSlice(Thread* thread, const Tuple& tuple, word start, word stop, 32 word step) { 33 if (start == 0 && stop >= tuple.length() && step == 1) { 34 return *tuple; 35 } 36 37 HandleScope scope(thread); 38 word length = Slice::length(start, stop, step); 39 Runtime* runtime = thread->runtime(); 40 if (length == 0) { 41 return runtime->emptyTuple(); 42 } 43 MutableTuple items(&scope, runtime->newMutableTuple(length)); 44 for (word i = 0, index = start; i < length; i++, index += step) { 45 items.atPut(i, tuple.at(index)); 46 } 47 return items.becomeImmutable(); 48} 49 50RawObject tupleHash(Thread* thread, const Tuple& tuple) { 51 HandleScope scope(thread); 52 Object elt(&scope, NoneType::object()); 53 Object elt_hash(&scope, NoneType::object()); 54 uword result = 0x345678UL; 55 uword mult = 1000003UL; // 0xf4243 56 word len = tuple.length(); 57 for (word i = len - 1; i >= 0; i--) { 58 elt = tuple.at(i); 59 elt_hash = Interpreter::hash(thread, elt); 60 if (elt_hash.isErrorException()) return *elt_hash; 61 word hash_result = SmallInt::cast(*elt_hash).value(); 62 result = (result ^ hash_result) * mult; 63 mult += word{82520} + len + len; 64 } 65 result += 97531UL; 66 if (result == kMaxUword) { 67 return SmallInt::fromWord(-2); 68 } 69 return SmallInt::fromWordTruncated(result); 70} 71 72static const BuiltinAttribute kUserTupleBaseAttributes[] = { 73 {ID(_UserTuple__value), RawUserTupleBase::kValueOffset, 74 AttributeFlags::kHidden}, 75}; 76 77static const BuiltinAttribute kTupleIteratorAttributes[] = { 78 {ID(_tuple_iterator__iterable), RawTupleIterator::kIterableOffset, 79 AttributeFlags::kHidden}, 80 {ID(_tuple_iterator__index), RawTupleIterator::kIndexOffset, 81 AttributeFlags::kHidden}, 82 {ID(_tuple_iterator__length), RawTupleIterator::kLengthOffset, 83 AttributeFlags::kHidden}, 84}; 85 86void initializeTupleTypes(Thread* thread) { 87 addBuiltinType(thread, ID(tuple), LayoutId::kTuple, 88 /*superclass_id=*/LayoutId::kObject, kUserTupleBaseAttributes, 89 UserTupleBase::kSize, /*basetype=*/true); 90 91 addBuiltinType(thread, ID(tuple_iterator), LayoutId::kTupleIterator, 92 /*superclass_id=*/LayoutId::kObject, kTupleIteratorAttributes, 93 TupleIterator::kSize, /*basetype=*/false); 94} 95 96RawObject METH(tuple, __add__)(Thread* thread, Arguments args) { 97 Runtime* runtime = thread->runtime(); 98 HandleScope scope(thread); 99 Object lhs(&scope, args.get(0)); 100 if (!runtime->isInstanceOfTuple(*lhs)) { 101 return thread->raiseRequiresType(lhs, ID(tuple)); 102 } 103 Tuple left(&scope, tupleUnderlying(*lhs)); 104 Object rhs(&scope, args.get(1)); 105 if (!runtime->isInstanceOfTuple(*rhs)) { 106 return thread->raiseWithFmt(LayoutId::kTypeError, 107 "can only concatenate tuple to tuple, got %T", 108 &rhs); 109 } 110 Tuple right(&scope, tupleUnderlying(*rhs)); 111 word llength = left.length(); 112 word rlength = right.length(); 113 114 word new_length = llength + rlength; 115 if (new_length > SmallInt::kMaxValue) { 116 return thread->raiseWithFmt(LayoutId::kOverflowError, 117 "cannot fit 'int' into an index-sized integer"); 118 } 119 if (new_length == 0) { 120 return runtime->emptyTuple(); 121 } 122 MutableTuple new_tuple(&scope, runtime->newMutableTuple(new_length)); 123 new_tuple.replaceFromWith(0, *left, llength); 124 new_tuple.replaceFromWith(llength, *right, rlength); 125 return new_tuple.becomeImmutable(); 126} 127 128RawObject tupleContains(Thread* thread, const Tuple& tuple, 129 const Object& value) { 130 for (word i = 0, num_items = tuple.length(); i < num_items; ++i) { 131 RawObject eq = Runtime::objectEquals(thread, *value, tuple.at(i)); 132 if (eq != Bool::falseObj()) return eq; 133 } 134 return Bool::falseObj(); 135} 136 137RawObject METH(tuple, __contains__)(Thread* thread, Arguments args) { 138 HandleScope scope(thread); 139 Object self_obj(&scope, args.get(0)); 140 if (!thread->runtime()->isInstanceOfTuple(*self_obj)) { 141 return thread->raiseRequiresType(self_obj, ID(tuple)); 142 } 143 Tuple self(&scope, tupleUnderlying(*self_obj)); 144 Object value(&scope, args.get(1)); 145 return tupleContains(thread, self, value); 146} 147 148RawObject METH(tuple, __hash__)(Thread* thread, Arguments args) { 149 HandleScope scope(thread); 150 Object self_obj(&scope, args.get(0)); 151 Runtime* runtime = thread->runtime(); 152 if (!runtime->isInstanceOfTuple(*self_obj)) { 153 return thread->raiseRequiresType(self_obj, ID(tuple)); 154 } 155 Tuple self(&scope, tupleUnderlying(*self_obj)); 156 return tupleHash(thread, self); 157} 158 159RawObject METH(tuple, __len__)(Thread* thread, Arguments args) { 160 HandleScope scope(thread); 161 Object obj(&scope, args.get(0)); 162 Runtime* runtime = thread->runtime(); 163 if (!runtime->isInstanceOfTuple(*obj)) { 164 return thread->raiseRequiresType(obj, ID(tuple)); 165 } 166 Tuple self(&scope, tupleUnderlying(*obj)); 167 return runtime->newInt(self.length()); 168} 169 170RawObject METH(tuple, __mul__)(Thread* thread, Arguments args) { 171 HandleScope scope(thread); 172 Object self_obj(&scope, args.get(0)); 173 Runtime* runtime = thread->runtime(); 174 if (!runtime->isInstanceOfTuple(*self_obj)) { 175 return thread->raiseRequiresType(self_obj, ID(tuple)); 176 } 177 Tuple self(&scope, tupleUnderlying(*self_obj)); 178 Object rhs(&scope, args.get(1)); 179 Object rhs_index(&scope, intFromIndex(thread, rhs)); 180 if (rhs_index.isError()) return *rhs_index; 181 Int right(&scope, intUnderlying(*rhs_index)); 182 if (right.isLargeInt()) { 183 return thread->raiseWithFmt(LayoutId::kOverflowError, 184 "cannot fit '%T' into an index-sized integer", 185 &rhs); 186 } 187 word length = self.length(); 188 word times = right.asWord(); 189 if (length == 0 || times <= 0) { 190 return runtime->emptyTuple(); 191 } 192 if (times == 1) { 193 return *self; 194 } 195 196 word new_length = length * times; 197 // If the new length overflows, raise an OverflowError. 198 if ((new_length / length) != times) { 199 return thread->raiseWithFmt(LayoutId::kOverflowError, 200 "cannot fit 'int' into an index-sized integer"); 201 } 202 203 MutableTuple new_tuple(&scope, runtime->newMutableTuple(new_length)); 204 if (length == 1) { 205 // Fast path for single-element tuples 206 new_tuple.fill(self.at(0)); 207 return new_tuple.becomeImmutable(); 208 } 209 for (word i = 0; i < times; i++) { 210 new_tuple.replaceFromWith(i * length, *self, length); 211 } 212 return new_tuple.becomeImmutable(); 213} 214 215RawObject METH(tuple, __iter__)(Thread* thread, Arguments args) { 216 HandleScope scope(thread); 217 Object self(&scope, args.get(0)); 218 Runtime* runtime = thread->runtime(); 219 if (!runtime->isInstanceOfTuple(*self)) { 220 return thread->raiseRequiresType(self, ID(tuple)); 221 } 222 Tuple tuple(&scope, tupleUnderlying(*self)); 223 return runtime->newTupleIterator(tuple, tuple.length()); 224} 225 226RawObject METH(tuple_iterator, __iter__)(Thread* thread, Arguments args) { 227 HandleScope scope(thread); 228 Object self(&scope, args.get(0)); 229 if (!self.isTupleIterator()) { 230 return thread->raiseRequiresType(self, ID(tuple_iterator)); 231 } 232 return *self; 233} 234 235RawObject METH(tuple_iterator, __next__)(Thread* thread, Arguments args) { 236 HandleScope scope(thread); 237 Object self_obj(&scope, args.get(0)); 238 if (!self_obj.isTupleIterator()) { 239 return thread->raiseRequiresType(self_obj, ID(tuple_iterator)); 240 } 241 TupleIterator self(&scope, *self_obj); 242 Object value(&scope, tupleIteratorNext(thread, self)); 243 if (value.isError()) { 244 return thread->raise(LayoutId::kStopIteration, NoneType::object()); 245 } 246 return *value; 247} 248 249RawObject METH(tuple_iterator, __length_hint__)(Thread* thread, 250 Arguments args) { 251 HandleScope scope(thread); 252 Object self(&scope, args.get(0)); 253 if (!self.isTupleIterator()) { 254 return thread->raiseRequiresType(self, ID(tuple_iterator)); 255 } 256 TupleIterator tuple_iterator(&scope, *self); 257 Tuple tuple(&scope, tuple_iterator.iterable()); 258 return SmallInt::fromWord(tuple.length() - tuple_iterator.index()); 259} 260 261RawObject METH(tuple_iterator, __reduce__)(Thread* thread, Arguments args) { 262 HandleScope scope(thread); 263 Object self(&scope, args.get(0)); 264 if (!self.isTupleIterator()) { 265 return thread->raiseRequiresType(self, ID(tuple_iterator)); 266 } 267 TupleIterator tuple_iterator(&scope, *self); 268 Tuple tuple(&scope, tuple_iterator.iterable()); 269 270 // __reduce__ returns a 3-tuple 271 // * A callable object to recreate the tuple iterator 272 // * A tuple of arguments to pass to the recreate function 273 // * An argument to be passed to __setstate__ (see below) 274 Runtime* runtime = thread->runtime(); 275 Object iter(&scope, 276 runtime->lookupNameInModule(thread, ID(builtins), ID(iter))); 277 if (iter.isError()) { 278 return thread->raiseWithFmt(LayoutId::kAttributeError, 279 "expected __builtins__.iter to exist"); 280 } 281 Object index(&scope, SmallInt::fromWord(tuple_iterator.index())); 282 Object newargs(&scope, runtime->newTupleWith1(tuple)); 283 return runtime->newTupleWith3(iter, newargs, index); 284} 285 286RawObject METH(tuple_iterator, __setstate__)(Thread* thread, Arguments args) { 287 // tupleiter check 288 HandleScope scope(thread); 289 Object self(&scope, args.get(0)); 290 if (!self.isTupleIterator()) { 291 return thread->raiseRequiresType(self, ID(tuple_iterator)); 292 } 293 TupleIterator tuple_iterator(&scope, *self); 294 295 // Argument must be an integer 296 if (!thread->runtime()->isInstanceOfInt(args.get(1))) { 297 return thread->raiseWithFmt(LayoutId::kTypeError, "an integer is required"); 298 } 299 300 // cpython restricted to ints that fit in ssize_t 301 Int idx(&scope, intUnderlying(args.get(1))); 302 OptInt<ssize_t> idx_opt = idx.asInt<ssize_t>(); 303 if (idx_opt.error != CastError::None) { 304 return thread->raiseWithFmt(LayoutId::kOverflowError, 305 "Python int too large to convert to C ssize_t"); 306 } 307 308 // cpython underflows to 0 and overflows to length 309 if (idx_opt.value <= 0) { 310 tuple_iterator.setIndex(0); 311 } else { 312 Tuple tuple(&scope, tuple_iterator.iterable()); 313 word length = tuple.length(); 314 if (idx_opt.value > length) { 315 tuple_iterator.setIndex(length); 316 } else { 317 tuple_iterator.setIndex(idx_opt.value); 318 } 319 } 320 return NoneType::object(); 321} 322 323} // namespace py