Commit b131d40c authored by Chris Toshok's avatar Chris Toshok

add reversed() builtin function, as well as compatible __reversed__ methods on list/xrange.

parent 4afb0656
......@@ -1116,6 +1116,8 @@ void setupBuiltins() {
builtins_module->giveAttr(
"iter", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)getiter, UNKNOWN, 1, 0, false, false)));
builtins_module->giveAttr(
"reversed", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)getreversed, UNKNOWN, 1, 0, false, false)));
builtins_module->giveAttr("divmod", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)divmod, UNKNOWN, 2)));
......
......@@ -20,10 +20,9 @@
namespace pyston {
BoxedListIterator::BoxedListIterator(BoxedList* l) : l(l), pos(0) {
BoxedListIterator::BoxedListIterator(BoxedList* l, int start) : l(l), pos(start) {
}
Box* listIterIter(Box* s) {
return s;
}
......@@ -31,7 +30,7 @@ Box* listIterIter(Box* s) {
Box* listIter(Box* s) {
assert(s->cls == list_cls);
BoxedList* self = static_cast<BoxedList*>(s);
return new BoxedListIterator(self);
return new BoxedListIterator(self, 0);
}
Box* listiterHasnext(Box* s) {
......@@ -61,6 +60,41 @@ Box* listiterNext(Box* s) {
return rtn;
}
Box* listReversed(Box* s) {
assert(s->cls == list_cls);
BoxedList* self = static_cast<BoxedList*>(s);
return new (list_reverse_iterator_cls) BoxedListIterator(self, self->size - 1);
}
Box* listreviterHasnext(Box* s) {
assert(s->cls == list_reverse_iterator_cls);
BoxedListIterator* self = static_cast<BoxedListIterator*>(s);
return boxBool(self->pos >= 0);
}
i1 listreviterHasnextUnboxed(Box* s) {
assert(s->cls == list_reverse_iterator_cls);
BoxedListIterator* self = static_cast<BoxedListIterator*>(s);
return self->pos >= 0;
}
Box* listreviterNext(Box* s) {
assert(s->cls == list_reverse_iterator_cls);
BoxedListIterator* self = static_cast<BoxedListIterator*>(s);
if (!(self->pos >= 0 && self->pos < self->l->size)) {
raiseExcHelper(StopIteration, "");
}
Box* rtn = self->l->elts->elts[self->pos];
self->pos--;
return rtn;
}
const int BoxedList::INITIAL_CAPACITY = 8;
// TODO the inliner doesn't want to inline these; is there any point to having them in the inline section?
void BoxedList::shrink() {
......
......@@ -24,9 +24,40 @@ class BoxedXrangeIterator;
class BoxedXrange : public Box {
private:
const int64_t start, stop, step;
int64_t len;
// from cpython
/* Return number of items in range (lo, hi, step). step != 0
* required. The result always fits in an unsigned long.
*/
static int64_t get_len_of_range(int64_t lo, int64_t hi, int64_t step) {
/* -------------------------------------------------------------
If step > 0 and lo >= hi, or step < 0 and lo <= hi, the range is empty.
Else for step > 0, if n values are in the range, the last one is
lo + (n-1)*step, which must be <= hi-1. Rearranging,
n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so
the RHS is non-negative and so truncation is the same as the
floor. Letting M be the largest positive long, the worst case
for the RHS numerator is hi=M, lo=-M-1, and then
hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
precision to compute the RHS exactly. The analysis for step < 0
is similar.
---------------------------------------------------------------*/
assert(step != 0LL);
if (step > 0LL && lo < hi)
return 1LL + (hi - 1LL - lo) / step;
else if (step < 0 && lo > hi)
return 1LL + (lo - 1LL - hi) / (0LL - step);
else
return 0LL;
}
public:
BoxedXrange(i64 start, i64 stop, i64 step) : start(start), stop(stop), step(step) {}
BoxedXrange(int64_t start, int64_t stop, int64_t step) : start(start), stop(stop), step(step) {
len = get_len_of_range(start, stop, step);
}
friend class BoxedXrangeIterator;
......@@ -37,9 +68,24 @@ class BoxedXrangeIterator : public Box {
private:
BoxedXrange* const xrange;
int64_t cur;
int64_t stop, step;
public:
BoxedXrangeIterator(BoxedXrange* xrange) : xrange(xrange), cur(xrange->start) {}
BoxedXrangeIterator(BoxedXrange* xrange, bool reversed) : xrange(xrange) {
int64_t start = xrange->start;
int64_t len = xrange->len;
stop = xrange->stop;
step = xrange->step;
if (reversed) {
stop = xrange->start - step;
start = xrange->start + (len - 1) * step;
step = -step;
}
cur = start;
}
DEFAULT_CLASS(xrange_iterator_cls);
......@@ -47,10 +93,10 @@ public:
assert(s->cls == xrange_iterator_cls);
BoxedXrangeIterator* self = static_cast<BoxedXrangeIterator*>(s);
if (self->xrange->step > 0) {
return self->cur < self->xrange->stop;
if (self->step > 0) {
return self->cur < self->stop;
} else {
return self->cur > self->xrange->stop;
return self->cur > self->stop;
}
}
......@@ -66,7 +112,7 @@ public:
raiseExcHelper(StopIteration, "");
i64 rtn = self->cur;
self->cur += self->xrange->step;
self->cur += self->step;
return rtn;
}
......@@ -112,10 +158,22 @@ Box* xrange(Box* cls, Box* start, Box* stop, Box** args) {
}
}
Box* xrangeIterIter(Box* self) {
assert(self->cls == xrange_iterator_cls);
return self;
}
Box* xrangeIter(Box* self) {
assert(self->cls == xrange_cls);
Box* rtn = new BoxedXrangeIterator(static_cast<BoxedXrange*>(self));
Box* rtn = new BoxedXrangeIterator(static_cast<BoxedXrange*>(self), false);
return rtn;
}
Box* xrangeReversed(Box* self) {
assert(self->cls == xrange_cls);
Box* rtn = new BoxedXrangeIterator(static_cast<BoxedXrange*>(self), true);
return rtn;
}
......@@ -129,9 +187,13 @@ void setupXrange() {
new BoxedFunction(boxRTFunction((void*)xrange, typeFromClass(xrange_cls), 4, 2, false, false), { NULL, NULL }));
xrange_cls->giveAttr("__iter__",
new BoxedFunction(boxRTFunction((void*)xrangeIter, typeFromClass(xrange_iterator_cls), 1)));
xrange_cls->giveAttr(
"__reversed__", new BoxedFunction(boxRTFunction((void*)xrangeReversed, typeFromClass(xrange_iterator_cls), 1)));
CLFunction* hasnext = boxRTFunction((void*)BoxedXrangeIterator::xrangeIteratorHasnextUnboxed, BOOL, 1);
addRTFunction(hasnext, (void*)BoxedXrangeIterator::xrangeIteratorHasnext, BOXED_BOOL);
xrange_iterator_cls->giveAttr(
"__iter__", new BoxedFunction(boxRTFunction((void*)xrangeIterIter, typeFromClass(xrange_iterator_cls), 1)));
xrange_iterator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext));
CLFunction* next = boxRTFunction((void*)BoxedXrangeIterator::xrangeIteratorNextUnboxed, INT, 1);
......
......@@ -31,10 +31,16 @@
namespace pyston {
BoxedClass* seqiter_cls;
BoxedClass* seqreviter_cls;
BoxedClass* iterwrapper_cls;
Box* seqiterIter(Box* s) {
RELEASE_ASSERT(s->cls == seqiter_cls || s->cls == seqreviter_cls, "");
return s;
}
Box* seqiterHasnext(Box* s) {
RELEASE_ASSERT(s->cls == seqiter_cls, "");
RELEASE_ASSERT(s->cls == seqiter_cls || s->cls == seqreviter_cls, "");
BoxedSeqIter* self = static_cast<BoxedSeqIter*>(s);
Box* next;
......@@ -48,8 +54,25 @@ Box* seqiterHasnext(Box* s) {
return True;
}
Box* seqreviterHasnext(Box* s) {
RELEASE_ASSERT(s->cls == seqiter_cls || s->cls == seqreviter_cls, "");
BoxedSeqIter* self = static_cast<BoxedSeqIter*>(s);
if (self->idx == -1)
return False;
Box* next;
try {
next = getitem(self->b, boxInt(self->idx));
} catch (ExcInfo e) {
return False;
}
self->idx--;
self->next = next;
return True;
}
Box* seqiterNext(Box* s) {
RELEASE_ASSERT(s->cls == seqiter_cls, "");
RELEASE_ASSERT(s->cls == seqiter_cls || s->cls == seqreviter_cls, "");
BoxedSeqIter* self = static_cast<BoxedSeqIter*>(s);
RELEASE_ASSERT(self->next, "");
......@@ -99,7 +122,7 @@ Box* iterwrapperNext(Box* s) {
extern "C" PyObject* PySeqIter_New(PyObject* seq) noexcept {
try {
return new BoxedSeqIter(seq);
return new BoxedSeqIter(seq, 0);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
......@@ -111,9 +134,18 @@ void setupIter() {
seqiter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1)));
seqiter_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqiterHasnext, BOXED_BOOL, 1)));
seqiter_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)seqiterIter, UNKNOWN, 1)));
seqiter_cls->freeze();
seqreviter_cls = new BoxedHeapClass(object_cls, NULL, 0, sizeof(BoxedSeqIter), false, "reversed");
seqreviter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)seqiterNext, UNKNOWN, 1)));
seqreviter_cls->giveAttr("__hasnext__", new BoxedFunction(boxRTFunction((void*)seqreviterHasnext, BOXED_BOOL, 1)));
seqreviter_cls->giveAttr("__iter__", new BoxedFunction(boxRTFunction((void*)seqiterIter, UNKNOWN, 1)));
seqreviter_cls->freeze();
iterwrapper_cls
= new BoxedHeapClass(object_cls, iterwrapperGCVisit, 0, sizeof(BoxedIterWrapper), false, "iterwrapper");
......
......@@ -23,6 +23,7 @@
namespace pyston {
extern BoxedClass* seqiter_cls;
extern BoxedClass* seqreviter_cls;
// Analogue of CPython's PySeqIter: wraps an object that has a __getitem__
// and uses that to iterate.
......@@ -32,7 +33,7 @@ public:
int64_t idx;
Box* next;
BoxedSeqIter(Box* b) : b(b), idx(0), next(NULL) {}
BoxedSeqIter(Box* b, int64_t start) : b(b), idx(start), next(NULL) {}
DEFAULT_CLASS(seqiter_cls);
};
......
......@@ -593,6 +593,8 @@ Box* listRemove(BoxedList* self, Box* elt) {
}
BoxedClass* list_iterator_cls = NULL;
BoxedClass* list_reverse_iterator_cls = NULL;
extern "C" void listIteratorGCHandler(GCVisitor* v, Box* b) {
boxGCHandler(v, b);
BoxedListIterator* it = (BoxedListIterator*)b;
......@@ -741,6 +743,8 @@ extern "C" int PyList_SetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh, P
void setupList() {
list_iterator_cls
= new BoxedHeapClass(object_cls, &listIteratorGCHandler, 0, sizeof(BoxedList), false, "listiterator");
list_reverse_iterator_cls = new BoxedHeapClass(object_cls, &listIteratorGCHandler, 0, sizeof(BoxedListIterator),
false, "listreverseiterator");
list_cls->giveAttr("__len__", new BoxedFunction(boxRTFunction((void*)listLen, BOXED_INT, 1)));
......@@ -753,6 +757,9 @@ void setupList() {
list_cls->giveAttr("__iter__",
new BoxedFunction(boxRTFunction((void*)listIter, typeFromClass(list_iterator_cls), 1)));
list_cls->giveAttr("__reversed__", new BoxedFunction(boxRTFunction((void*)listReversed,
typeFromClass(list_reverse_iterator_cls), 1)));
list_cls->giveAttr("__eq__", new BoxedFunction(boxRTFunction((void*)listEq, UNKNOWN, 2)));
list_cls->giveAttr("__ne__", new BoxedFunction(boxRTFunction((void*)listNe, UNKNOWN, 2)));
......@@ -805,10 +812,22 @@ void setupList() {
list_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)listiterNext, UNKNOWN, 1)));
list_iterator_cls->freeze();
list_reverse_iterator_cls->giveAttr("__name__", boxStrConstant("listreverseiterator"));
hasnext = boxRTFunction((void*)listreviterHasnextUnboxed, BOOL, 1);
addRTFunction(hasnext, (void*)listreviterHasnext, BOXED_BOOL);
list_reverse_iterator_cls->giveAttr("__hasnext__", new BoxedFunction(hasnext));
list_reverse_iterator_cls->giveAttr(
"__iter__", new BoxedFunction(boxRTFunction((void*)listIterIter, typeFromClass(list_reverse_iterator_cls), 1)));
list_reverse_iterator_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)listreviterNext, UNKNOWN, 1)));
list_reverse_iterator_cls->freeze();
}
void teardownList() {
// TODO do clearattrs?
// decref(list_iterator_cls);
// decref(list_reverse_iterator_cls);
}
}
......@@ -21,11 +21,12 @@
namespace pyston {
extern BoxedClass* list_iterator_cls;
extern BoxedClass* list_reverse_iterator_cls;
class BoxedListIterator : public Box {
public:
BoxedList* l;
int pos;
BoxedListIterator(BoxedList* l);
BoxedListIterator(BoxedList* l, int start);
DEFAULT_CLASS(list_iterator_cls);
};
......@@ -35,6 +36,10 @@ Box* listIterIter(Box* self);
Box* listiterHasnext(Box* self);
i1 listiterHasnextUnboxed(Box* self);
Box* listiterNext(Box* self);
Box* listReversed(Box* self);
Box* listreviterHasnext(Box* self);
i1 listreviterHasnextUnboxed(Box* self);
Box* listreviterNext(Box* self);
void listSort(BoxedList* self, Box* cmp, Box* key, Box* reverse);
extern "C" Box* listAppend(Box* self, Box* v);
}
......
......@@ -77,6 +77,7 @@ static const std::string get_str("__get__");
static const std::string hasnext_str("__hasnext__");
static const std::string init_str("__init__");
static const std::string iter_str("__iter__");
static const std::string reversed_str("__reversed__");
static const std::string new_str("__new__");
static const std::string none_str("None");
static const std::string repr_str("__repr__");
......@@ -3437,12 +3438,26 @@ Box* getiter(Box* o) {
return r;
if (typeLookup(o->cls, getitem_str, NULL)) {
return new BoxedSeqIter(o);
return new BoxedSeqIter(o, 0);
}
raiseExcHelper(TypeError, "'%s' object is not iterable", getTypeName(o));
}
Box* getreversed(Box* o) {
// TODO add rewriting to this? probably want to try to avoid this path though
Box* r = callattrInternal0(o, &reversed_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(0));
if (r)
return r;
if (!typeLookup(o->cls, getitem_str, NULL)) {
raiseExcHelper(TypeError, "'%s' object is not iterable", getTypeName(o));
}
int64_t len = unboxedLen(o); // this will throw an exception if __len__ isn't there
return new (seqreviter_cls) BoxedSeqIter(o, len - 1);
}
llvm::iterator_range<BoxIterator> Box::pyElements() {
// TODO: this should probably call getPystonIter
Box* iter = getiter(this);
......
......@@ -89,6 +89,7 @@ extern "C" bool isSubclass(BoxedClass* child, BoxedClass* parent);
extern "C" BoxedClosure* createClosure(BoxedClosure* parent_closure);
Box* getiter(Box* o);
Box* getreversed(Box* o);
extern "C" Box* getPystonIter(Box* o);
extern "C" void dump(void* p);
......
print list(reversed("hello"))
print list(reversed(""))
print list(reversed([1,2,3]))
print list(reversed((1,2,3)))
print list(reversed([]))
class RevIterTest(object):
def __getitem__(self, idx):
if idx >= 3:
raise StopIteration()
return idx
def __len__(self):
return 3
print list(RevIterTest())
print list(reversed(RevIterTest()))
# xrange and list have __reversed__ methods
print list(xrange(0,9).__reversed__())
print list([1,2,3,4,5,6].__reversed__())
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment