diff --git a/src/collections.cpp b/src/collections.cpp index 4180f522..d5d1f17c 100644 --- a/src/collections.cpp +++ b/src/collections.cpp @@ -1,19 +1,13 @@ #include "pocketpy/collections.h" namespace pkpy { - struct PyDequeIter + struct PyDequeIter // Iterator for the deque type { - // Iterator for the deque type PY_CLASS(PyDequeIter, builtins, "_deque_iterator") PyObject *ref; bool is_reversed; - std::deque::iterator begin; - std::deque::iterator end; - std::deque::iterator current; - std::deque::reverse_iterator rbegin; - std::deque::reverse_iterator rend; - std::deque::reverse_iterator rcurrent; - + std::deque::iterator begin, end, current; + std::deque::reverse_iterator rbegin, rend, rcurrent; PyDequeIter(PyObject *ref, std::deque::iterator begin, std::deque::iterator end) : ref(ref), begin(begin), end(end), current(begin) { @@ -24,7 +18,6 @@ namespace pkpy { this->is_reversed = true; } - void _gc_mark() const { PK_OBJ_MARK(ref); } static void _register(VM *vm, PyObject *mod, PyObject *type); }; @@ -52,7 +45,6 @@ namespace pkpy return ret; } }); } - // STARTING HERE struct PyDeque { PY_CLASS(PyDeque, collections, deque); @@ -64,7 +56,7 @@ namespace pkpy void insertObj(bool front, bool back, int index, PyObject *item); // insert at index, used purely for internal purposes: append, appendleft, insert methods PyObject *popObj(bool front, bool back, PyObject *item, VM *vm); // pop at index, used purely for internal purposes: pop, popleft, remove methods int findIndex(VM *vm, PyObject *obj, int start, int stop); // find the index of the given object in the deque - std::stringstream getRepr(VM *vm); // get the string representation of the deque + std::stringstream getRepr(VM *vm, PyObject* thisObj); // get the string representation of the deque // Special methods static void _register(VM *vm, PyObject *mod, PyObject *type); // register the type void _gc_mark() const; // needed for container types, mark all objects in the deque for gc @@ -74,50 +66,11 @@ namespace pkpy vm->bind(type, "__new__(cls, iterable=None, maxlen=None)", [](VM *vm, ArgsView args) { - // printf("NEW CALLED!!\n"); Type cls_t = PK_OBJ_GET(Type, args[0]); PyObject *iterable = args[1]; PyObject *maxlen = args[2]; return vm->heap.gcnew(cls_t, vm, iterable, maxlen); }); - // vm->bind(type, "__init__(self, iterable=None, maxlen=None)", - // [](VM *vm, ArgsView args) - // { - // // printf("INIT CALLED!!\n"); - // PyDeque &self = _CAST(PyDeque &, args[0]); - // PyObject *iterable = args[1]; - // PyObject *maxlen = args[2]; - - // if (!vm->py_equals(maxlen, vm->None)) // fix the maxlen first - // { - // int tmp = CAST(int, maxlen); - // if (tmp < 0) - // vm->ValueError("maxlen must be non-negative"); - // else - // { - // self.maxlen = tmp; - // self.bounded = true; - // } - // } - // else - // { - // self.bounded = false; - // self.maxlen = -1; - // } - // if (!vm->py_equals(iterable, vm->None)) - // { - // self.dequeItems.clear(); // clear the deque - // auto _lock = vm->heap.gc_scope_lock(); // locking the heap - // PyObject *it = vm->py_iter(args[1]); // strong ref - // PyObject *obj = vm->py_next(it); - // while (obj != vm->StopIteration) - // { - // self.insertObj(false, true, -1, obj); - // obj = vm->py_next(it); - // } - // } - // return args[0]; - // }); // gets the item at the given index, if index is negative, it will be treated as index + len(deque) // if the index is out of range, IndexError will be thrown --> required for [] operator vm->bind(type, "__getitem__(self, index) -> PyObject", @@ -172,18 +125,15 @@ namespace pkpy [](VM *vm, ArgsView args) { PyDeque &self = _CAST(PyDeque &, args[0]); - std::stringstream ss; - ss << "deque(["; - for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it) - { - if (*it == args[0]) - ss << "[...]"; - else - ss << CAST(Str &, vm->py_repr(*it)); - if (it != self.dequeItems.end() - 1) - ss << ", "; - } - self.bounded ? ss << "], maxlen=" << self.maxlen << ")" : ss << "])"; + std::stringstream ss = self.getRepr(vm, args[0]); + return VAR(ss.str()); + }); + // returns a string representation of the deque + vm->bind(type, "__str__(self) -> str", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + std::stringstream ss = self.getRepr(vm, args[0]); return VAR(ss.str()); }); // enables comparison between two deques, == and != are supported @@ -287,8 +237,8 @@ namespace pkpy { if (vm->py_equals((*it), obj)) cnt++; - if (sz != self.dequeItems.size()) // mutating the deque during iteration is not allowed - vm->RuntimeError("deque mutated during iteration"); // TODO replace this with RuntimeError + if (sz != self.dequeItems.size())// mutating the deque during iteration is not allowed + vm->RuntimeError("deque mutated during iteration"); } return VAR(cnt); }); @@ -477,7 +427,22 @@ namespace pkpy } } } - + std::stringstream PyDeque::getRepr(VM *vm, PyObject *thisObj) + { + std::stringstream ss; + ss << "deque(["; + for (auto it = this->dequeItems.begin(); it != this->dequeItems.end(); ++it) + { + if (*it == thisObj) + ss << "[...]"; + else + ss << CAST(Str &, vm->py_repr(*it)); + if (it != this->dequeItems.end() - 1) + ss << ", "; + } + this->bounded ? ss << "], maxlen=" << this->maxlen << ")" : ss << "])"; + return ss; + } int PyDeque::findIndex(VM *vm, PyObject *obj, int start, int stop) { // the following code is special purpose normalization for this method, taken from CPython: _collectionsmodule.c file @@ -504,8 +469,8 @@ namespace pkpy { if (vm->py_equals(this->dequeItems[i], obj)) return i; - if (sz != this->dequeItems.size()) // mutating the deque during iteration is not allowed - vm->RuntimeError("deque mutated during iteration"); // TODO replace this with RuntimeError + if (sz != this->dequeItems.size())// mutating the deque during iteration is not allowed + vm->RuntimeError("deque mutated during iteration"); } return -1; } diff --git a/tests/70_collections.py b/tests/70_collections.py index f8bc9483..7d967d01 100644 --- a/tests/70_collections.py +++ b/tests/70_collections.py @@ -23,16 +23,10 @@ assert q == deque([1, 2]) def assertEqual(a, b): assert a == b - - def assertNotEqual(a, b): assert a != b - - -def assertRaises(callable, *args, **kwargs): - callable(*args, **kwargs) - print("X Failed Tests for {} for args: {} {}".format( - str(callable), str(args), str(kwargs))) +def printFailed(function_name, *args, **kwargs): + print("X Failed Tests for {} for args: {} {}".format(str(function_name), str(args), str(kwargs))) BIG = 100000 @@ -67,12 +61,16 @@ assertEqual(list(d), list(range(50, 150))) try: dq = deque() dq.maxlen = -1 + printFailed("deque.maxlen", -1) + exit(1) except AttributeError: pass try: dq = deque() dq.maxlen = -2 + printFailed("deque.maxlen", -2) + exit(1) except AttributeError: pass @@ -122,7 +120,7 @@ assertEqual(deque('abc', maxlen=0).maxlen, 0) try: d = deque('abc') d.maxlen = 10 - print("X Failed Tests!!") + printFailed("deque.maxlen", 10) exit(1) except AttributeError: pass @@ -135,14 +133,14 @@ for s in ('', 'abracadabra', 'simsalabim'*500+'abc'): assertEqual(s.count(letter), d.count(letter)) try: d.count() - print("X Failed Tests!!") + printFailed("deque.count") exit(1) except TypeError: pass try: d.count(1, 2) - print("X Failed Tests!!") + printFailed("deque.count", 1, 2) exit(1) except TypeError: pass @@ -157,7 +155,7 @@ d = deque([1, 2, BadCompare(), 3]) try: d.count(2) - print("X Failed Tests!!") + printFailed("deque.count", 2) exit(1) except ArithmeticError: pass @@ -165,7 +163,7 @@ except ArithmeticError: d = deque([1, 2, 3]) try: d.count(BadCompare()) - print("X Failed Tests!!") + printFailed("deque.count", "BadCompare()") exit(1) except ArithmeticError: pass @@ -183,7 +181,7 @@ m.d = d try: d.count(3) - print("X Failed Tests!") + printFailed("deque.count", "MutatingCompare()") exit(1) except RuntimeError: pass @@ -239,7 +237,7 @@ d = deque(range(n)) d[n//2] = MutateCmp(d, False) try: n in d - print("X Failed Tests!") + printFailed("deque.__contains__", n) exit(1) except RuntimeError: pass @@ -255,7 +253,7 @@ d = deque(range(n)) d[n//2] = BadCmp() try: n in d - print("X Failed Tests!") + printFailed("deque.__contains__", n) exit(1) except RuntimeError: pass @@ -273,7 +271,7 @@ d = deque([A(), A()]) try: _ = 3 in d - print("X Failed Tests!") + printFailed("deque.__contains__", 3) exit(1) except RuntimeError: pass @@ -281,7 +279,7 @@ except RuntimeError: d = deque([A(), A()]) try: _ = d.count(3) - print("X Failed Tests!") + printFailed("deque.count", 3) exit(1) except RuntimeError: pass @@ -293,7 +291,7 @@ except RuntimeError: d = deque('a') try: d.extend(1) - print("X Failed Tests!") + printFailed("deque.extend", 1) exit(1) except TypeError: pass @@ -307,7 +305,7 @@ assertEqual(list(d), list('abcdabcd')) d = deque('a') try: d.extendleft(1) - print("X Failed Tests!") + printFailed("deque.extendleft", 1) exit(1) except TypeError: pass @@ -320,7 +318,7 @@ d.extendleft(range(1000)) assertEqual(list(d), list(reversed(range(1000)))) try: d.extendleft(fail()) - print("X Failed Tests!") + printFailed("deque.extendleft", fail()) exit(1) except SyntaxError: pass @@ -345,13 +343,13 @@ assertEqual(d[-1], 'n') d = deque() try: d.__getitem__(0) - print("X Failed Tests!") + printFailed("deque.__getitem__", 0) exit(1) except IndexError: pass try: d.__getitem__(-1) - print("X Failed Tests!") + printFailed("deque.__getitem__", -1) exit(1) except IndexError: pass @@ -366,7 +364,7 @@ for n in 1, 2, 30, 40, 200: try: d.index(n+1) - print("X Failed Tests!") + printFailed("deque.index", n+1) exit(1) except ValueError: pass @@ -377,7 +375,7 @@ for n in 1, 2, 30, 40, 200: try: d.index(n) - print("X Failed Tests!") + printFailed("deque.index", n) exit(1) except RuntimeError: pass @@ -388,7 +386,7 @@ for n in 1, 2, 30, 40, 200: try: d.index(n) - print("X Failed Tests!") + printFailed("deque.index", n) exit(1) except RuntimeError: pass @@ -430,7 +428,7 @@ for step in range(100): d = deque('A' * 3) try: d.index('A', 1, 0) - print("X Failed Tests!") + printFailed("deque.index", 'A', 1, 0) exit(1) except ValueError: pass @@ -451,7 +449,7 @@ data = 'ABC' d = deque(data, maxlen=len(data)) try: d.insert(0, 'Z') - print("X Failed Tests!") + printFailed("deque.insert", 0, 'Z') exit(1) except IndexError: pass @@ -484,14 +482,14 @@ n = 500 # O(n**2) test, don't make this too big d = deque(range(n)) try: d.__delitem__(-n-1) - print("X Failed Tests!") + printFailed("deque.__delitem__", -n-1) exit(1) except IndexError: pass try: d.__delitem__(n) - print("X Failed Tests!") + printFailed("deque.__delitem__", n) exit(1) except IndexError: pass @@ -518,7 +516,7 @@ for i in range(n): assertEqual(list(d), data[:i]) try: d.reverse(1) - print("X Failed Tests!") + printFailed("deque.reverse", 1) exit(1) except TypeError: pass @@ -570,14 +568,14 @@ for i in range(BIG+17): assertEqual(tuple(d), tuple(e)) try: d.rotate(1, 2) - print("X Failed Tests!") + printFailed("deque.rotate", 1, 2) exit(1) except TypeError: pass try: d.rotate(1, 10) - print("X Failed Tests!") + printFailed("deque.rotate", 1, 10) exit(1) except TypeError: pass @@ -596,7 +594,7 @@ d.pop() assertEqual(len(d), 0) try: d.pop() - print("X Failed Tests!") + printFailed("deque.pop") exit(1) except IndexError: pass @@ -613,13 +611,13 @@ assertEqual(len(d), 0) d = deque() try: d.pop() - print("X Failed Tests!") + printFailed("deque.pop") exit(1) except IndexError: pass try: d.popleft() - print("X Failed Tests!") + printFailed("deque.popleft") exit(1) except IndexError: pass @@ -642,7 +640,7 @@ d.remove('c') assertEqual(d, deque('abdefghij')) try: d.remove('c') - print("X Failed Tests!") + printFailed("deque.remove", "c") exit(1) except ValueError: pass @@ -654,7 +652,7 @@ e = deque(d) try: d.remove('c') - print("X Failed Tests!") + printFailed("deque.remove", "c") exit(1) except RuntimeError: pass @@ -668,7 +666,7 @@ for match in (True, False): d.extend([MutateCmp(d, match), 'c']) try: d.remove('c') - print("X Failed Tests!") + printFailed("deque.remove", "c") exit(1) except IndexError: pass @@ -687,13 +685,13 @@ assertEqual(repr(d)[-20:], '7, 198, 199, [...]])') try: deque('abc', 2, 3) - print("X Failed Tests!") + printFailed("deque", 'abc', 2, 3) exit(1) except TypeError: pass try: deque(1) - print("X Failed Tests!") + printFailed("deque", 1) exit(1) except TypeError: pass @@ -701,7 +699,7 @@ except TypeError: ######### test hash ############# try: - assertRaises(hash, deque('abc')) + hash(deque('abcd')) except TypeError: pass