diff --git a/include/pocketpy/collections.h b/include/pocketpy/collections.h index 6273cf4e..8b3ff000 100644 --- a/include/pocketpy/collections.h +++ b/include/pocketpy/collections.h @@ -10,157 +10,25 @@ namespace pkpy { - // struct DequeNode - // { - // PyObject *obj; - // DequeNode *prev; - // DequeNode *next; - // DequeNode() - // { - // this->obj = nullptr; // ignored value, sentinnel - // this->prev = nullptr; - // this->next = nullptr; - // } - // DequeNode(PyObject *obj) - // { - // this->obj = obj; - // this->prev = nullptr; - // this->next = nullptr; - // } - - // ~DequeNode() - // { - // } - // }; - - // struct MyDoublyLinkedList - // { - // int len; - // DequeNode *head; - // DequeNode *tail; - - // MyDoublyLinkedList() - // { // creates an empty list - // this->len = 0; - // this->head = new DequeNode(); // dummy - // this->tail = new DequeNode(); // dummy - // this->head->next = this->tail; - // this->tail->prev = this->head; - // } - - // ~MyDoublyLinkedList() - // { - // if (this->head == nullptr) - // return; - // this->makeListEmpty(); - // delete this->head; - // delete this->tail; - // } - - // void push_back(DequeNode *node) - // { - // node->prev = this->tail->prev; - // node->next = this->tail; - // this->tail->prev->next = node; - // this->tail->prev = node; - // this->len++; - // } - // void push_front(DequeNode *node) - // { - // node->prev = this->head; - // node->next = this->head->next; - // this->head->next->prev = node; - // this->head->next = node; - // this->len++; - // } - - // DequeNode *pop_back() - // { - // if (this->empty()) - // throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list"); - // DequeNode *node = this->tail->prev; - // this->tail->prev->prev->next = this->tail; - // this->tail->prev = this->tail->prev->prev; - // this->len--; - // return node; - // } - - // DequeNode *pop_front() - // { - // if (this->empty()) - // throw std::runtime_error("DoubleLinkedList::pop_front() called on empty list"); - // DequeNode *node = this->head->next; - // this->head->next->next->prev = this->head; - // this->head->next = this->head->next->next; - // this->len--; - // return node; - // } - - // bool empty() const - // { - // if (this->len == 0) - // { - // if (this->head->next != this->tail || this->tail->prev != this->head) - // { - // throw std::runtime_error("DoubleLinkedList::size() returned 0 but the list is not empty"); - // } - // return true; - // } - // return false; - // } - - // int size() const - // { - // return this->len; - // } - - // void makeListEmpty() - // { - // while (!this->empty()) - // { - // this->pop_back(); - // } - // } - - // void reverse() - // { - // if (this->empty()) - // return; - // // Go through each node, including the dummy nodes - // // and swap the prev and next pointers - // DequeNode *p = this->head; - // while (p!=nullptr){ - // DequeNode *tmp = p->next; - // p->next = p->prev; - // p->prev = tmp; - // p = tmp; - // } - - // // swap the head and tail pointers - // DequeNode *tmp = this->head; - // this->head = this->tail; - // this->tail = tmp; - // } - - // }; - // STARTING HERE struct PyDeque { PY_CLASS(PyDeque, mycollections, deque); - // some fields can be defined here - std::dequedequeItems; void appendLeft(PyObject *item); void append(PyObject *item); PyObject *popLeft(); PyObject *pop(); + + bool insert(int index, PyObject *item); + bool remove(VM *vm, PyObject *item); + void rotate(int n); + std::stringstream getRepr(VM *vm); void reverse(); int findIndex(VM *vm, PyObject *obj, int startPos, int endPos); // vm is needed for the py_equals - int count(VM *vm, PyObject *obj); // vm is needed for the py_equals void clear(); diff --git a/src/collections.cpp b/src/collections.cpp index c9bd1825..c0db1074 100644 --- a/src/collections.cpp +++ b/src/collections.cpp @@ -5,19 +5,19 @@ namespace pkpy void PyDeque::_register(VM *vm, PyObject *mod, PyObject *type) { vm->bind_default_constructor(type); - - vm->bind(type, "__init__(self) -> None", - [](VM *vm, ArgsView args) - { - PyDeque &self = _CAST(PyDeque &, args[0]); - PyObject *maxlen = args[1]; - if (maxlen != vm->None) - { - // printf("TODO: implement deque.__init__(maxlen) -> None: %d\n", CAST(int, maxlen)); - } - return vm->None; - }); + vm->bind(type, "__init__(self) -> None", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + PyObject *maxlen = args[1]; + if (maxlen != vm->None) + { + // printf("TODO: implement deque.__init__(maxlen) -> None: %d\n", CAST(int, maxlen)); + } + + return vm->None; + }); vm->bind(type, "__len__(self) -> int", [](VM *vm, ArgsView args) @@ -55,17 +55,14 @@ namespace pkpy vm->bind(type, "copy(self) -> deque", [](VM *vm, ArgsView args) { - //TODO: implement and validate - return vm->None; - // PyDeque &self = _CAST(PyDeque &, args[0]); - // PyDeque *newDeque = new PyDeque(); - // DequeNode *p = self.dequeItems->head->next; - // while (p != self.dequeItems->tail) - // { - // newDeque->append(p->obj); - // p = p->next; - // } - // return vm->heap.gcnew(PyDeque::_type(vm), *newDeque); + //TODO: STILL MEMORY LEAKING?? + PyDeque &self = _CAST(PyDeque &, args[0]); + PyDeque *newDeque = new PyDeque(); + for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it) + { + newDeque->append(*it); + } + return vm->heap.gcnew(PyDeque::_type(vm), *newDeque); }); vm->bind(type, "count(self, obj) -> int", @@ -126,10 +123,14 @@ namespace pkpy vm->bind(type, "insert(self, index, obj) -> None", [](VM *vm, ArgsView args) { - // TODO: implement and validate + PyDeque &self = _CAST(PyDeque &, args[0]); + int index = CAST(int, args[1]); + PyObject *obj = args[2]; - printf("TODO: implement deque.insert()"); - return vm->None; + //TODO: HANDLE MAX SIZE CASE LATER -> Throw IndexError + + self.insert(index, obj); + return vm->None; }); vm->bind(type, "__repr__(self) -> str", @@ -157,9 +158,14 @@ namespace pkpy vm->bind(type, "remove(self, obj) -> None", [](VM *vm, ArgsView args) { - // TODO: implement and validate - printf("TODO: implement deque.index()"); - return vm->None; + PyDeque &self = _CAST(PyDeque &, args[0]); + PyObject *obj = args[1]; + bool removed = self.remove(vm, obj); + + if(!removed) + vm->ValueError(_CAST(Str &, vm->py_repr(obj)) + " is not in list"); + + return vm->None; }); vm->bind(type, "reverse(self) -> None", @@ -169,12 +175,15 @@ namespace pkpy self.reverse(); return vm->None; }); + + vm->bind(type, "rotate(self, n=1) -> None", [](VM *vm, ArgsView args) { - // TODO: implement and validate - printf("TODO: implement deque.rotate()"); - return vm->None; + PyDeque &self = _CAST(PyDeque &, args[0]); + int n = CAST(int, args[1]); + self.rotate(n); + return vm->None; }); // vm->bind(type,"maxlen", @@ -184,11 +193,60 @@ namespace pkpy // }); } - void PyDeque::_gc_mark() const + void PyDeque::rotate(int n) { - //TODO: HOW TO IMPLEMENT THIS? + int direction = n > 0 ? 1 : -1; + int sz = this->dequeItems.size(); + + n = abs(n); + n = n % sz; // make sure n is in range + + for (int i = 0; i < n; i++) + { + if (direction == 1) + { + PyObject *tmp = this->dequeItems.back(); + this->dequeItems.pop_back(); + this->dequeItems.push_front(tmp); + } + else + { + PyObject *tmp = this->dequeItems.front(); + this->dequeItems.pop_front(); + this->dequeItems.push_back(tmp); + } + } } + bool PyDeque::remove(VM *vm, PyObject *item) + { + for (auto it = this->dequeItems.begin(); it != this->dequeItems.end(); ++it) + { + if (vm->py_equals((*it), item)) + { + this->dequeItems.erase(it); + return true; + } + } + return false; + } + + bool PyDeque::insert(int index, PyObject *item) + { + if (index < 0) + this->dequeItems.appendLeft(item); + else if(index >= this->dequeItems.size()) + this->dequeItems.append(item); + else + this->dequeItems.insert((this->dequeItems.begin() + index), item); + + return true; + } + + void PyDeque::_gc_mark() const + { + // TODO: HOW TO IMPLEMENT THIS? + } std::stringstream PyDeque::getRepr(VM *vm) { @@ -214,14 +272,14 @@ namespace pkpy startPos = 0; if (endPos == -1) endPos = this->dequeItems.size(); - + if (!(startPos <= endPos)) { throw std::runtime_error("startPos<=endPos"); } int dequeSize = this->dequeItems.size(); - - for (int i = startPos; ipy_equals(this->dequeItems[i], obj)) { @@ -231,7 +289,6 @@ namespace pkpy return -1; } - void PyDeque::reverse() { int sz = this->dequeItems.size();