From 795c7b65c66f66550e57806c1fd3b45479b7b96b Mon Sep 17 00:00:00 2001 From: "S. Mahmudul Hasan" Date: Sat, 7 Oct 2023 19:00:54 -0400 Subject: [PATCH] WIP: Implemented a int-only deque with limited capabilities --- include/pocketpy/collections.h | 136 +++++++++++++++++++++++++++++++- src/collections.cpp | 138 ++++++++++++++++++++++++++++++--- 2 files changed, 262 insertions(+), 12 deletions(-) diff --git a/include/pocketpy/collections.h b/include/pocketpy/collections.h index 56d9cb64..a93c6066 100644 --- a/include/pocketpy/collections.h +++ b/include/pocketpy/collections.h @@ -4,22 +4,154 @@ #include "common.h" #include "memory.h" #include "str.h" +#include "iter.h" #include "cffi.h" namespace pkpy { + struct DequeNode{ + int obj; //TODO: change to PyObject* + DequeNode* prev; + DequeNode* next; + DequeNode(){ + this->obj = -1; // ignored value + this->prev = nullptr; + this->next = nullptr; + } + DequeNode(int obj){ + this->obj = obj; + this->prev = nullptr; + this->next = nullptr; + } + + ~DequeNode(){ + } + + void printNode(){ + printf("%d ", this->obj); + } + }; + + 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 count(int obj){ // TODO: change to PyObject* + int cnt = 0; + DequeNode* p = this->head->next; + while(p != this->tail){ + if(p->obj == obj) cnt++; + p = p->next; + } + return cnt; + } + + void makeListEmpty(){ + while(!this->empty()){ + this->pop_back(); + } + } + + void printList(){ + if(this->empty()){ + printf("Empty List\n"); + return; + } + DequeNode* p = this->head->next; + while(p != this->tail){ + p->printNode(); + p = p->next; + } + printf("\n"); + } + + + }; + + // STARTING HERE struct PyDeque { PY_CLASS(PyDeque, collections, deque); // some fields can be defined here int len; + MyDoublyLinkedList *dequeItems; + - PyDeque() = default; + void appendLeft(int item); // TODO: change to PyObject* + void append(int item); // TODO: change to PyObject* + int popLeft(); // TODO: change to PyObject* + int pop(); // TODO: change to PyObject* + int count(int obj); // TODO: change to PyObject* + + void clear(); + void print(VM *vm); + + PyDeque(): len(0), dequeItems(new MyDoublyLinkedList()){} + PyDeque(VM *vm) : len(0), dequeItems(new MyDoublyLinkedList()){} void printHelloWorld(); static void _register(VM *vm, PyObject *mod, PyObject *type); - void _gc_mark() const; // needed for container types + void _gc_mark() const; // needed for container types }; void add_module_mycollections(VM *vm); diff --git a/src/collections.cpp b/src/collections.cpp index 7fa02824..3171730d 100644 --- a/src/collections.cpp +++ b/src/collections.cpp @@ -7,24 +7,142 @@ namespace pkpy vm->bind_default_constructor(type); vm->bind(type, "__len__(self) -> int", - [](VM *vm, ArgsView args){ - PyDeque& self = _CAST(PyDeque&, args[0]); - return VAR(self.len); - }); + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + return VAR(self.len); + }); vm->bind(type, "printHelloWorld(self) -> None", - [](VM *vm, ArgsView args){ - PyDeque& self = _CAST(PyDeque&, args[0]); - self.printHelloWorld(); - return vm->None; - }); + [](VM *vm, ArgsView args) + { + printf("TESTING HELLO WORLD!!\n"); + + PyDeque &self = _CAST(PyDeque &, args[0]); + self.printHelloWorld(); + + printf("TESTED HELLO WORLD!!\n"); + return vm->None; + }); + + vm->bind(type, "appendleft(self, item) -> None", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + int item = _CAST(int, args[1]); // TODO: change to PyObject* + self.appendLeft(item); + return vm->None; + }); + + vm->bind(type, "append(self, item) -> None", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + int item = _CAST(int, args[1]); // TODO: change to PyObject* + self.append(item); + return vm->None; + }); + + vm->bind(type, "popleft(self) -> PyObject", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + int tmp = self.popLeft(); // TODO: change to PyObject* + return py_var(vm, tmp); + }); + + vm->bind(type,"pop(self) -> PyObject", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + int tmp = self.pop(); // TODO: change to PyObject* + return py_var(vm, tmp); + }); + + + vm->bind(type, "count(self, obj) -> int", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + int obj = _CAST(int, args[1]); // TODO: change to PyObject* + int cnt = self.count(obj); + return VAR(cnt); + }); + + + vm->bind(type, "print(self) -> None", // TODO: remove this later + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + self.print(vm); + return vm->None; + }); + + vm->bind(type, "clear(self) -> None", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + self.clear(); + return vm->None; + }); + } + + void PyDeque::_gc_mark() const + { + // TODO: implement + } + void PyDeque::appendLeft(int item) // TODO: change to PyObject* + { + DequeNode *node = new DequeNode(item); + this->dequeItems->push_front(node); + } + void PyDeque::append(int item) // TODO: change to PyObject* + { + // int val = _CAST(int, item); + DequeNode *node = new DequeNode(item); + this->dequeItems->push_back(node); + } + + int PyDeque::popLeft() // TODO: change to PyObject* + { + if (this->dequeItems->empty()) + { + throw std::runtime_error("pop from an empty deque"); + } + DequeNode *node = this->dequeItems->pop_front(); + return node->obj; + } + + int PyDeque::pop() // TODO: change to PyObject* + { + if (this->dequeItems->empty()) + { + throw std::runtime_error("pop from an empty deque"); + } + DequeNode *node = this->dequeItems->pop_back(); + return node->obj; + } + + int PyDeque::count(int obj) // TODO: change to PyObject* + { + return this->dequeItems->count(obj); + } + void PyDeque::clear() + { + this->dequeItems->makeListEmpty(); + } + void PyDeque::print(VM *vm) + { + // TODO: Helper function to print the deque, will be removed later + this->dequeItems->printList(); } void PyDeque::printHelloWorld() { printf("Hello World!\n"); + return; } - + void add_module_mycollections(VM *vm) { PyObject *mycollections = vm->new_module("collections");