Cleaned up and added __str__() support

This commit is contained in:
S. Mahmudul Hasan 2023-10-19 23:38:30 -04:00
parent a5a18154f4
commit 385e9492c8
2 changed files with 73 additions and 110 deletions

View File

@ -1,19 +1,13 @@
#include "pocketpy/collections.h" #include "pocketpy/collections.h"
namespace pkpy namespace pkpy
{ {
struct PyDequeIter struct PyDequeIter // Iterator for the deque type
{ {
// Iterator for the deque type
PY_CLASS(PyDequeIter, builtins, "_deque_iterator") PY_CLASS(PyDequeIter, builtins, "_deque_iterator")
PyObject *ref; PyObject *ref;
bool is_reversed; bool is_reversed;
std::deque<PyObject *>::iterator begin; std::deque<PyObject *>::iterator begin, end, current;
std::deque<PyObject *>::iterator end; std::deque<PyObject *>::reverse_iterator rbegin, rend, rcurrent;
std::deque<PyObject *>::iterator current;
std::deque<PyObject *>::reverse_iterator rbegin;
std::deque<PyObject *>::reverse_iterator rend;
std::deque<PyObject *>::reverse_iterator rcurrent;
PyDequeIter(PyObject *ref, std::deque<PyObject *>::iterator begin, std::deque<PyObject *>::iterator end) PyDequeIter(PyObject *ref, std::deque<PyObject *>::iterator begin, std::deque<PyObject *>::iterator end)
: ref(ref), begin(begin), end(end), current(begin) : ref(ref), begin(begin), end(end), current(begin)
{ {
@ -24,7 +18,6 @@ namespace pkpy
{ {
this->is_reversed = true; this->is_reversed = true;
} }
void _gc_mark() const { PK_OBJ_MARK(ref); } void _gc_mark() const { PK_OBJ_MARK(ref); }
static void _register(VM *vm, PyObject *mod, PyObject *type); static void _register(VM *vm, PyObject *mod, PyObject *type);
}; };
@ -52,7 +45,6 @@ namespace pkpy
return ret; return ret;
} }); } });
} }
// STARTING HERE
struct PyDeque struct PyDeque
{ {
PY_CLASS(PyDeque, collections, deque); 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 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 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 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 // Special methods
static void _register(VM *vm, PyObject *mod, PyObject *type); // register the type 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 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->bind(type, "__new__(cls, iterable=None, maxlen=None)",
[](VM *vm, ArgsView args) [](VM *vm, ArgsView args)
{ {
// printf("NEW CALLED!!\n");
Type cls_t = PK_OBJ_GET(Type, args[0]); Type cls_t = PK_OBJ_GET(Type, args[0]);
PyObject *iterable = args[1]; PyObject *iterable = args[1];
PyObject *maxlen = args[2]; PyObject *maxlen = args[2];
return vm->heap.gcnew<PyDeque>(cls_t, vm, iterable, maxlen); return vm->heap.gcnew<PyDeque>(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) // 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 // if the index is out of range, IndexError will be thrown --> required for [] operator
vm->bind(type, "__getitem__(self, index) -> PyObject", vm->bind(type, "__getitem__(self, index) -> PyObject",
@ -172,18 +125,15 @@ namespace pkpy
[](VM *vm, ArgsView args) [](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
std::stringstream ss; std::stringstream ss = self.getRepr(vm, args[0]);
ss << "deque(["; return VAR(ss.str());
for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it) });
// returns a string representation of the deque
vm->bind(type, "__str__(self) -> str",
[](VM *vm, ArgsView args)
{ {
if (*it == args[0]) PyDeque &self = _CAST(PyDeque &, args[0]);
ss << "[...]"; std::stringstream ss = self.getRepr(vm, args[0]);
else
ss << CAST(Str &, vm->py_repr(*it));
if (it != self.dequeItems.end() - 1)
ss << ", ";
}
self.bounded ? ss << "], maxlen=" << self.maxlen << ")" : ss << "])";
return VAR(ss.str()); return VAR(ss.str());
}); });
// enables comparison between two deques, == and != are supported // enables comparison between two deques, == and != are supported
@ -288,7 +238,7 @@ namespace pkpy
if (vm->py_equals((*it), obj)) if (vm->py_equals((*it), obj))
cnt++; cnt++;
if (sz != self.dequeItems.size())// mutating the deque during iteration is not allowed if (sz != self.dequeItems.size())// mutating the deque during iteration is not allowed
vm->RuntimeError("deque mutated during iteration"); // TODO replace this with RuntimeError vm->RuntimeError("deque mutated during iteration");
} }
return VAR(cnt); 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) 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 // the following code is special purpose normalization for this method, taken from CPython: _collectionsmodule.c file
@ -505,7 +470,7 @@ namespace pkpy
if (vm->py_equals(this->dequeItems[i], obj)) if (vm->py_equals(this->dequeItems[i], obj))
return i; return i;
if (sz != this->dequeItems.size())// mutating the deque during iteration is not allowed if (sz != this->dequeItems.size())// mutating the deque during iteration is not allowed
vm->RuntimeError("deque mutated during iteration"); // TODO replace this with RuntimeError vm->RuntimeError("deque mutated during iteration");
} }
return -1; return -1;
} }

View File

@ -23,16 +23,10 @@ assert q == deque([1, 2])
def assertEqual(a, b): def assertEqual(a, b):
assert a == b assert a == b
def assertNotEqual(a, b): def assertNotEqual(a, b):
assert a != b assert a != b
def printFailed(function_name, *args, **kwargs):
print("X Failed Tests for {} for args: {} {}".format(str(function_name), str(args), str(kwargs)))
def assertRaises(callable, *args, **kwargs):
callable(*args, **kwargs)
print("X Failed Tests for {} for args: {} {}".format(
str(callable), str(args), str(kwargs)))
BIG = 100000 BIG = 100000
@ -67,12 +61,16 @@ assertEqual(list(d), list(range(50, 150)))
try: try:
dq = deque() dq = deque()
dq.maxlen = -1 dq.maxlen = -1
printFailed("deque.maxlen", -1)
exit(1)
except AttributeError: except AttributeError:
pass pass
try: try:
dq = deque() dq = deque()
dq.maxlen = -2 dq.maxlen = -2
printFailed("deque.maxlen", -2)
exit(1)
except AttributeError: except AttributeError:
pass pass
@ -122,7 +120,7 @@ assertEqual(deque('abc', maxlen=0).maxlen, 0)
try: try:
d = deque('abc') d = deque('abc')
d.maxlen = 10 d.maxlen = 10
print("X Failed Tests!!") printFailed("deque.maxlen", 10)
exit(1) exit(1)
except AttributeError: except AttributeError:
pass pass
@ -135,14 +133,14 @@ for s in ('', 'abracadabra', 'simsalabim'*500+'abc'):
assertEqual(s.count(letter), d.count(letter)) assertEqual(s.count(letter), d.count(letter))
try: try:
d.count() d.count()
print("X Failed Tests!!") printFailed("deque.count")
exit(1) exit(1)
except TypeError: except TypeError:
pass pass
try: try:
d.count(1, 2) d.count(1, 2)
print("X Failed Tests!!") printFailed("deque.count", 1, 2)
exit(1) exit(1)
except TypeError: except TypeError:
pass pass
@ -157,7 +155,7 @@ d = deque([1, 2, BadCompare(), 3])
try: try:
d.count(2) d.count(2)
print("X Failed Tests!!") printFailed("deque.count", 2)
exit(1) exit(1)
except ArithmeticError: except ArithmeticError:
pass pass
@ -165,7 +163,7 @@ except ArithmeticError:
d = deque([1, 2, 3]) d = deque([1, 2, 3])
try: try:
d.count(BadCompare()) d.count(BadCompare())
print("X Failed Tests!!") printFailed("deque.count", "BadCompare()")
exit(1) exit(1)
except ArithmeticError: except ArithmeticError:
pass pass
@ -183,7 +181,7 @@ m.d = d
try: try:
d.count(3) d.count(3)
print("X Failed Tests!") printFailed("deque.count", "MutatingCompare()")
exit(1) exit(1)
except RuntimeError: except RuntimeError:
pass pass
@ -239,7 +237,7 @@ d = deque(range(n))
d[n//2] = MutateCmp(d, False) d[n//2] = MutateCmp(d, False)
try: try:
n in d n in d
print("X Failed Tests!") printFailed("deque.__contains__", n)
exit(1) exit(1)
except RuntimeError: except RuntimeError:
pass pass
@ -255,7 +253,7 @@ d = deque(range(n))
d[n//2] = BadCmp() d[n//2] = BadCmp()
try: try:
n in d n in d
print("X Failed Tests!") printFailed("deque.__contains__", n)
exit(1) exit(1)
except RuntimeError: except RuntimeError:
pass pass
@ -273,7 +271,7 @@ d = deque([A(), A()])
try: try:
_ = 3 in d _ = 3 in d
print("X Failed Tests!") printFailed("deque.__contains__", 3)
exit(1) exit(1)
except RuntimeError: except RuntimeError:
pass pass
@ -281,7 +279,7 @@ except RuntimeError:
d = deque([A(), A()]) d = deque([A(), A()])
try: try:
_ = d.count(3) _ = d.count(3)
print("X Failed Tests!") printFailed("deque.count", 3)
exit(1) exit(1)
except RuntimeError: except RuntimeError:
pass pass
@ -293,7 +291,7 @@ except RuntimeError:
d = deque('a') d = deque('a')
try: try:
d.extend(1) d.extend(1)
print("X Failed Tests!") printFailed("deque.extend", 1)
exit(1) exit(1)
except TypeError: except TypeError:
pass pass
@ -307,7 +305,7 @@ assertEqual(list(d), list('abcdabcd'))
d = deque('a') d = deque('a')
try: try:
d.extendleft(1) d.extendleft(1)
print("X Failed Tests!") printFailed("deque.extendleft", 1)
exit(1) exit(1)
except TypeError: except TypeError:
pass pass
@ -320,7 +318,7 @@ d.extendleft(range(1000))
assertEqual(list(d), list(reversed(range(1000)))) assertEqual(list(d), list(reversed(range(1000))))
try: try:
d.extendleft(fail()) d.extendleft(fail())
print("X Failed Tests!") printFailed("deque.extendleft", fail())
exit(1) exit(1)
except SyntaxError: except SyntaxError:
pass pass
@ -345,13 +343,13 @@ assertEqual(d[-1], 'n')
d = deque() d = deque()
try: try:
d.__getitem__(0) d.__getitem__(0)
print("X Failed Tests!") printFailed("deque.__getitem__", 0)
exit(1) exit(1)
except IndexError: except IndexError:
pass pass
try: try:
d.__getitem__(-1) d.__getitem__(-1)
print("X Failed Tests!") printFailed("deque.__getitem__", -1)
exit(1) exit(1)
except IndexError: except IndexError:
pass pass
@ -366,7 +364,7 @@ for n in 1, 2, 30, 40, 200:
try: try:
d.index(n+1) d.index(n+1)
print("X Failed Tests!") printFailed("deque.index", n+1)
exit(1) exit(1)
except ValueError: except ValueError:
pass pass
@ -377,7 +375,7 @@ for n in 1, 2, 30, 40, 200:
try: try:
d.index(n) d.index(n)
print("X Failed Tests!") printFailed("deque.index", n)
exit(1) exit(1)
except RuntimeError: except RuntimeError:
pass pass
@ -388,7 +386,7 @@ for n in 1, 2, 30, 40, 200:
try: try:
d.index(n) d.index(n)
print("X Failed Tests!") printFailed("deque.index", n)
exit(1) exit(1)
except RuntimeError: except RuntimeError:
pass pass
@ -430,7 +428,7 @@ for step in range(100):
d = deque('A' * 3) d = deque('A' * 3)
try: try:
d.index('A', 1, 0) d.index('A', 1, 0)
print("X Failed Tests!") printFailed("deque.index", 'A', 1, 0)
exit(1) exit(1)
except ValueError: except ValueError:
pass pass
@ -451,7 +449,7 @@ data = 'ABC'
d = deque(data, maxlen=len(data)) d = deque(data, maxlen=len(data))
try: try:
d.insert(0, 'Z') d.insert(0, 'Z')
print("X Failed Tests!") printFailed("deque.insert", 0, 'Z')
exit(1) exit(1)
except IndexError: except IndexError:
pass pass
@ -484,14 +482,14 @@ n = 500 # O(n**2) test, don't make this too big
d = deque(range(n)) d = deque(range(n))
try: try:
d.__delitem__(-n-1) d.__delitem__(-n-1)
print("X Failed Tests!") printFailed("deque.__delitem__", -n-1)
exit(1) exit(1)
except IndexError: except IndexError:
pass pass
try: try:
d.__delitem__(n) d.__delitem__(n)
print("X Failed Tests!") printFailed("deque.__delitem__", n)
exit(1) exit(1)
except IndexError: except IndexError:
pass pass
@ -518,7 +516,7 @@ for i in range(n):
assertEqual(list(d), data[:i]) assertEqual(list(d), data[:i])
try: try:
d.reverse(1) d.reverse(1)
print("X Failed Tests!") printFailed("deque.reverse", 1)
exit(1) exit(1)
except TypeError: except TypeError:
pass pass
@ -570,14 +568,14 @@ for i in range(BIG+17):
assertEqual(tuple(d), tuple(e)) assertEqual(tuple(d), tuple(e))
try: try:
d.rotate(1, 2) d.rotate(1, 2)
print("X Failed Tests!") printFailed("deque.rotate", 1, 2)
exit(1) exit(1)
except TypeError: except TypeError:
pass pass
try: try:
d.rotate(1, 10) d.rotate(1, 10)
print("X Failed Tests!") printFailed("deque.rotate", 1, 10)
exit(1) exit(1)
except TypeError: except TypeError:
pass pass
@ -596,7 +594,7 @@ d.pop()
assertEqual(len(d), 0) assertEqual(len(d), 0)
try: try:
d.pop() d.pop()
print("X Failed Tests!") printFailed("deque.pop")
exit(1) exit(1)
except IndexError: except IndexError:
pass pass
@ -613,13 +611,13 @@ assertEqual(len(d), 0)
d = deque() d = deque()
try: try:
d.pop() d.pop()
print("X Failed Tests!") printFailed("deque.pop")
exit(1) exit(1)
except IndexError: except IndexError:
pass pass
try: try:
d.popleft() d.popleft()
print("X Failed Tests!") printFailed("deque.popleft")
exit(1) exit(1)
except IndexError: except IndexError:
pass pass
@ -642,7 +640,7 @@ d.remove('c')
assertEqual(d, deque('abdefghij')) assertEqual(d, deque('abdefghij'))
try: try:
d.remove('c') d.remove('c')
print("X Failed Tests!") printFailed("deque.remove", "c")
exit(1) exit(1)
except ValueError: except ValueError:
pass pass
@ -654,7 +652,7 @@ e = deque(d)
try: try:
d.remove('c') d.remove('c')
print("X Failed Tests!") printFailed("deque.remove", "c")
exit(1) exit(1)
except RuntimeError: except RuntimeError:
pass pass
@ -668,7 +666,7 @@ for match in (True, False):
d.extend([MutateCmp(d, match), 'c']) d.extend([MutateCmp(d, match), 'c'])
try: try:
d.remove('c') d.remove('c')
print("X Failed Tests!") printFailed("deque.remove", "c")
exit(1) exit(1)
except IndexError: except IndexError:
pass pass
@ -687,13 +685,13 @@ assertEqual(repr(d)[-20:], '7, 198, 199, [...]])')
try: try:
deque('abc', 2, 3) deque('abc', 2, 3)
print("X Failed Tests!") printFailed("deque", 'abc', 2, 3)
exit(1) exit(1)
except TypeError: except TypeError:
pass pass
try: try:
deque(1) deque(1)
print("X Failed Tests!") printFailed("deque", 1)
exit(1) exit(1)
except TypeError: except TypeError:
pass pass
@ -701,7 +699,7 @@ except TypeError:
######### test hash ############# ######### test hash #############
try: try:
assertRaises(hash, deque('abc')) hash(deque('abcd'))
except TypeError: except TypeError:
pass pass