this repo has no description
at trunk 281 lines 10 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "range-builtins.h" 3 4#include "builtins.h" 5#include "frame.h" 6#include "globals.h" 7#include "int-builtins.h" 8#include "runtime.h" 9#include "type-builtins.h" 10 11namespace py { 12 13RawObject rangeLen(Thread* thread, const Object& start_obj, 14 const Object& stop_obj, const Object& step_obj) { 15 HandleScope scope(thread); 16 Int start(&scope, intUnderlying(*start_obj)); 17 Int stop(&scope, intUnderlying(*stop_obj)); 18 Int step(&scope, intUnderlying(*step_obj)); 19 if (!(start.isLargeInt() || stop.isLargeInt() || step.isLargeInt())) { 20 return thread->runtime()->newInt( 21 Slice::length(start.asWord(), stop.asWord(), step.asWord())); 22 } 23 word diff = start.compare(*stop); 24 if (step.isNegative()) { 25 if (diff > 0) { 26 Runtime* runtime = thread->runtime(); 27 Int tmp1(&scope, runtime->intSubtract(thread, start, stop)); 28 Int one(&scope, SmallInt::fromWord(1)); 29 tmp1 = runtime->intSubtract(thread, tmp1, one); 30 Int tmp2(&scope, runtime->intNegate(thread, step)); 31 Object quotient(&scope, NoneType::object()); 32 bool division_succeeded = 33 runtime->intDivideModulo(thread, tmp1, tmp2, &quotient, nullptr); 34 DCHECK(division_succeeded, "step must be nonzero"); 35 tmp1 = *quotient; 36 return runtime->intAdd(thread, tmp1, one); 37 } 38 } else if (diff < 0) { 39 Runtime* runtime = thread->runtime(); 40 Int tmp(&scope, runtime->intSubtract(thread, stop, start)); 41 Int one(&scope, SmallInt::fromWord(1)); 42 tmp = runtime->intSubtract(thread, tmp, one); 43 Object quotient(&scope, NoneType::object()); 44 bool division_succeeded = 45 runtime->intDivideModulo(thread, tmp, step, &quotient, nullptr); 46 DCHECK(division_succeeded, "step must be nonzero"); 47 tmp = *quotient; 48 return runtime->intAdd(thread, tmp, one); 49 } 50 return SmallInt::fromWord(0); 51} 52 53RawObject rangeIteratorNext(const RangeIterator& iter) { 54 word length = iter.length(); 55 if (length == 0) { 56 return Error::noMoreItems(); 57 } 58 iter.setLength(length - 1); 59 word next = iter.next(); 60 if (length > 1) { 61 word step = iter.step(); 62 iter.setNext(next + step); 63 } 64 return SmallInt::fromWord(next); 65} 66 67RawObject METH(longrange_iterator, __iter__)(Thread* thread, Arguments args) { 68 HandleScope scope(thread); 69 Object self(&scope, args.get(0)); 70 if (!self.isLongRangeIterator()) { 71 return thread->raiseRequiresType(self, ID(longrange_iterator)); 72 } 73 return *self; 74} 75 76RawObject METH(longrange_iterator, __length_hint__)(Thread* thread, 77 Arguments args) { 78 HandleScope scope(thread); 79 Object self(&scope, args.get(0)); 80 if (!self.isLongRangeIterator()) { 81 return thread->raiseRequiresType(self, ID(longrange_iterator)); 82 } 83 LongRangeIterator iter(&scope, *self); 84 Object next(&scope, iter.next()); 85 Object stop(&scope, iter.stop()); 86 Object step(&scope, iter.step()); 87 return rangeLen(thread, next, stop, step); 88} 89 90RawObject METH(longrange_iterator, __next__)(Thread* thread, Arguments args) { 91 HandleScope scope(thread); 92 Object self(&scope, args.get(0)); 93 if (!self.isLongRangeIterator()) { 94 return thread->raiseRequiresType(self, ID(longrange_iterator)); 95 } 96 LongRangeIterator iter(&scope, *self); 97 Int next(&scope, iter.next()); 98 Int stop(&scope, iter.stop()); 99 Int step(&scope, iter.step()); 100 word diff = next.compare(*stop); 101 if ((step.isNegative() && diff <= 0) || (step.isPositive() && diff >= 0)) { 102 return thread->raise(LayoutId::kStopIteration, NoneType::object()); 103 } 104 iter.setNext(thread->runtime()->intAdd(thread, next, step)); 105 return *next; 106} 107 108static const BuiltinAttribute kLongRangeIteratorAttributes[] = { 109 {ID(_longrange_iterator__next), RawLongRangeIterator::kNextOffset, 110 AttributeFlags::kHidden}, 111 {ID(_longrange_iterator__stop), RawLongRangeIterator::kStopOffset, 112 AttributeFlags::kHidden}, 113 {ID(_longrange_iterator__step), RawLongRangeIterator::kStepOffset, 114 AttributeFlags::kHidden}, 115}; 116 117static const BuiltinAttribute kRangeAttributes[] = { 118 {ID(start), RawRange::kStartOffset, AttributeFlags::kReadOnly}, 119 {ID(stop), RawRange::kStopOffset, AttributeFlags::kReadOnly}, 120 {ID(step), RawRange::kStepOffset, AttributeFlags::kReadOnly}, 121}; 122 123static const BuiltinAttribute kRangeIteratorAttributes[] = { 124 {ID(_range_iterator__next), RawRangeIterator::kNextOffset, 125 AttributeFlags::kHidden}, 126 {ID(_range_iterator__step), RawRangeIterator::kStepOffset, 127 AttributeFlags::kHidden}, 128 {ID(_range_iterator__length), RawRangeIterator::kLengthOffset, 129 AttributeFlags::kHidden}, 130}; 131 132void initializeRangeTypes(Thread* thread) { 133 addBuiltinType(thread, ID(range), LayoutId::kRange, 134 /*superclass_id=*/LayoutId::kObject, kRangeAttributes, 135 Range::kSize, /*basetype=*/false); 136 137 addBuiltinType(thread, ID(range_iterator), LayoutId::kRangeIterator, 138 /*superclass_id=*/LayoutId::kObject, kRangeIteratorAttributes, 139 RangeIterator::kSize, /*basetype=*/false); 140 141 addBuiltinType(thread, ID(longrange_iterator), LayoutId::kLongRangeIterator, 142 /*superclass_id=*/LayoutId::kObject, 143 kLongRangeIteratorAttributes, LongRangeIterator::kSize, 144 /*basetype=*/false); 145} 146 147RawObject METH(range, __iter__)(Thread* thread, Arguments args) { 148 HandleScope scope(thread); 149 Object self(&scope, args.get(0)); 150 if (!self.isRange()) { 151 return thread->raiseRequiresType(self, ID(range)); 152 } 153 Range range(&scope, *self); 154 Object start_obj(&scope, range.start()); 155 Object stop_obj(&scope, range.stop()); 156 Object step_obj(&scope, range.step()); 157 Int start_int(&scope, intUnderlying(*start_obj)); 158 Int stop_int(&scope, intUnderlying(*stop_obj)); 159 Int step_int(&scope, intUnderlying(*step_obj)); 160 Runtime* runtime = thread->runtime(); 161 if (start_int.isLargeInt() || stop_int.isLargeInt() || 162 step_int.isLargeInt()) { 163 return runtime->newLongRangeIterator(start_int, stop_int, step_int); 164 } 165 word start = start_int.asWord(); 166 word stop = stop_int.asWord(); 167 word step = step_int.asWord(); 168 word length = Slice::length(start, stop, step); 169 if (SmallInt::isValid(length)) { 170 return runtime->newRangeIterator(start, step, length); 171 } 172 return runtime->newLongRangeIterator(start_int, stop_int, step_int); 173} 174 175RawObject METH(range, __len__)(Thread* thread, Arguments args) { 176 HandleScope scope(thread); 177 Object self_obj(&scope, args.get(0)); 178 if (!self_obj.isRange()) { 179 return thread->raiseRequiresType(self_obj, ID(range)); 180 } 181 Range self(&scope, *self_obj); 182 Object start(&scope, self.start()); 183 Object stop(&scope, self.stop()); 184 Object step(&scope, self.step()); 185 Int len(&scope, rangeLen(thread, start, stop, step)); 186 // TODO(T55084422): Streamline int bounds checking in Pyro 187 if (len.isLargeInt() && LargeInt::cast(*len).numDigits() > 1) { 188 return thread->raiseWithFmt(LayoutId::kOverflowError, 189 "Python int too large to convert to C ssize_t"); 190 } 191 return *len; 192} 193 194RawObject METH(range, __new__)(Thread* thread, Arguments args) { 195 HandleScope scope(thread); 196 Object cls(&scope, args.get(0)); 197 Runtime* runtime = thread->runtime(); 198 if (!runtime->isInstanceOfType(*cls)) { 199 return thread->raiseWithFmt(LayoutId::kTypeError, 200 "range.__new__(X): X is not a type object (%T)", 201 &cls); 202 } 203 Type type(&scope, *cls); 204 if (type.builtinBase() != LayoutId::kRange) { 205 Str name(&scope, type.name()); 206 return thread->raiseWithFmt( 207 LayoutId::kTypeError, "range.__new__(%S): %S is not a subtype of range", 208 &name, &name); 209 } 210 211 Object start_or_stop(&scope, args.get(1)); 212 Object maybe_stop(&scope, args.get(2)); 213 Object maybe_step(&scope, args.get(3)); 214 if (maybe_stop.isUnbound()) { 215 DCHECK(maybe_step.isUnbound(), 216 "cannot provide step without providing both start and stop"); 217 Object start(&scope, SmallInt::fromWord(0)); 218 Object stop(&scope, intFromIndex(thread, start_or_stop)); 219 if (stop.isError()) return *stop; 220 Object step(&scope, SmallInt::fromWord(1)); 221 return runtime->newRange(start, stop, step); 222 } 223 224 if (maybe_step.isUnbound()) { 225 Object start(&scope, intFromIndex(thread, start_or_stop)); 226 if (start.isError()) return *start; 227 Object stop(&scope, intFromIndex(thread, maybe_stop)); 228 if (stop.isError()) return *stop; 229 Object step(&scope, SmallInt::fromWord(1)); 230 return runtime->newRange(start, stop, step); 231 } 232 233 Object start(&scope, intFromIndex(thread, start_or_stop)); 234 if (start.isError()) return *start; 235 Object stop(&scope, intFromIndex(thread, maybe_stop)); 236 if (stop.isError()) return *stop; 237 Object step(&scope, intFromIndex(thread, maybe_step)); 238 if (step.isError()) return *step; 239 Int step_int(&scope, intUnderlying(*step)); 240 if (step_int.isZero()) { 241 return thread->raiseWithFmt(LayoutId::kValueError, 242 "range() arg 3 must not be zero"); 243 } 244 return runtime->newRange(start, stop, step); 245} 246 247RawObject METH(range_iterator, __iter__)(Thread* thread, Arguments args) { 248 HandleScope scope(thread); 249 Object self(&scope, args.get(0)); 250 if (!self.isRangeIterator()) { 251 return thread->raiseRequiresType(self, ID(range_iterator)); 252 } 253 return *self; 254} 255 256RawObject METH(range_iterator, __length_hint__)(Thread* thread, 257 Arguments args) { 258 HandleScope scope(thread); 259 Object self(&scope, args.get(0)); 260 if (!self.isRangeIterator()) { 261 return thread->raiseRequiresType(self, ID(range_iterator)); 262 } 263 RangeIterator iter(&scope, *self); 264 return SmallInt::fromWord(iter.length()); 265} 266 267RawObject METH(range_iterator, __next__)(Thread* thread, Arguments args) { 268 HandleScope scope(thread); 269 Object self(&scope, args.get(0)); 270 if (!self.isRangeIterator()) { 271 return thread->raiseRequiresType(self, ID(range_iterator)); 272 } 273 RangeIterator iter(&scope, *self); 274 RawObject result = rangeIteratorNext(iter); 275 if (result.isErrorNoMoreItems()) { 276 return thread->raise(LayoutId::kStopIteration, NoneType::object()); 277 } 278 return result; 279} 280 281} // namespace py