diff --git a/include/pocketpy/collections.h b/include/pocketpy/collections.h index a93c6066..7e54f170 100644 --- a/include/pocketpy/collections.h +++ b/include/pocketpy/collections.h @@ -9,35 +9,37 @@ namespace pkpy { - struct DequeNode{ - int obj; //TODO: change to PyObject* - DequeNode* prev; - DequeNode* next; - DequeNode(){ - this->obj = -1; // ignored value + struct DequeNode + { + PyObject *obj; + DequeNode *prev; + DequeNode *next; + DequeNode() + { + this->obj = nullptr; // ignored value, sentinnel this->prev = nullptr; this->next = nullptr; } - DequeNode(int obj){ + DequeNode(PyObject *obj) + { this->obj = obj; this->prev = nullptr; this->next = nullptr; } - - ~DequeNode(){ - } - void printNode(){ - printf("%d ", this->obj); + ~DequeNode() + { } }; - struct MyDoublyLinkedList{ + struct MyDoublyLinkedList + { int len; - DequeNode* head; - DequeNode* tail; + DequeNode *head; + DequeNode *tail; - MyDoublyLinkedList(){ //creates an empty list + MyDoublyLinkedList() + { // creates an empty list this->len = 0; this->head = new DequeNode(); // dummy this->tail = new DequeNode(); // dummy @@ -45,21 +47,25 @@ namespace pkpy this->tail->prev = this->head; } - ~MyDoublyLinkedList(){ - if(this->head == nullptr) return; + ~MyDoublyLinkedList() + { + if (this->head == nullptr) + return; this->makeListEmpty(); delete this->head; delete this->tail; } - void push_back(DequeNode* node){ + 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){ + void push_front(DequeNode *node) + { node->prev = this->head; node->next = this->head->next; this->head->next->prev = node; @@ -67,27 +73,34 @@ namespace pkpy this->len++; } - DequeNode* pop_back(){ - if(this->empty()) throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list"); - DequeNode* node = this->tail->prev; + 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; + 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){ + 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; @@ -95,60 +108,68 @@ namespace pkpy return false; } - int count(int obj){ // TODO: change to PyObject* + int count(VM *vm, PyObject *obj) + { int cnt = 0; - DequeNode* p = this->head->next; - while(p != this->tail){ - if(p->obj == obj) cnt++; + DequeNode *p = this->head->next; + while (p != this->tail) + { + if (vm->py_equals(p->obj, obj)) + cnt++; p = p->next; } return cnt; } - void makeListEmpty(){ - while(!this->empty()){ + int size() const + { + return this->len; + } + + void makeListEmpty() + { + while (!this->empty()) + { this->pop_back(); } } - - void printList(){ - if(this->empty()){ - printf("Empty List\n"); - return; + + void reverse() + { + DequeNode *p = this->head->next; + while (p != this->tail) + { + DequeNode *tmp = p->next; + p->next = p->prev; + p->prev = tmp; + p = tmp; } - DequeNode* p = this->head->next; - while(p != this->tail){ - p->printNode(); - p = p->next; - } - printf("\n"); + DequeNode *tmp = this->head->next; + this->head->next = this->tail->prev; + this->tail->prev = tmp; } - }; // STARTING HERE struct PyDeque { - PY_CLASS(PyDeque, collections, deque); + PY_CLASS(PyDeque, mycollections, deque); // some fields can be defined here - int len; MyDoublyLinkedList *dequeItems; - - 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 appendLeft(PyObject *item); + void append(PyObject *item); + PyObject *popLeft(); + PyObject *pop(); + std::stringstream getRepr(VM *vm); + void reverse(); + + int count(VM *vm, PyObject *obj); // vm is needed for the py_equals void clear(); - void print(VM *vm); - PyDeque(): len(0), dequeItems(new MyDoublyLinkedList()){} - PyDeque(VM *vm) : len(0), dequeItems(new MyDoublyLinkedList()){} - void printHelloWorld(); + PyDeque() : dequeItems(new MyDoublyLinkedList()) {} static void _register(VM *vm, PyObject *mod, PyObject *type); void _gc_mark() const; // needed for container types diff --git a/src/collections.cpp b/src/collections.cpp index 3171730d..87e61955 100644 --- a/src/collections.cpp +++ b/src/collections.cpp @@ -2,150 +2,230 @@ namespace pkpy { - void PyDeque::_register(VM *vm, PyObject *mod, PyObject *type) - { - vm->bind_default_constructor(type); + void PyDeque::_register(VM *vm, PyObject *mod, PyObject *type) + { + 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->bind(type, "__len__(self) -> int", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + return VAR(self.dequeItems->size()); + }); - vm->bind(type, "printHelloWorld(self) -> None", - [](VM *vm, ArgsView args) - { - printf("TESTING HELLO WORLD!!\n"); + vm->bind(type, "append(self, item) -> None", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + PyObject *item = args[1]; + self.append(item); + return vm->None; + }); - PyDeque &self = _CAST(PyDeque &, args[0]); - self.printHelloWorld(); + vm->bind(type, "appendleft(self, item) -> None", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + PyObject *item = args[1]; + self.appendLeft(item); + return vm->None; + }); - printf("TESTED HELLO WORLD!!\n"); - return vm->None; - }); + vm->bind(type, "clear(self) -> None", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + self.clear(); + 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, "copy(self) -> deque", + [](VM *vm, ArgsView args) + { + // followed implementation of dict.copy() + // PyDeque &self = _CAST(PyDeque &, args[0]); + // return VAR(self); + //todo: implement + printf("TODO: implement deque.copy()"); + 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, "count(self, obj) -> int", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + PyObject *obj = args[1]; + int cnt = self.count(vm, obj); + return VAR(cnt); + }); - 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, "extend(self, iterable) -> None", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); - 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); - }); + PyObject *it = vm->py_iter(args[1]); // strong ref + PyObject *obj = vm->py_next(it); + while (obj != vm->StopIteration) + { + self.append(obj); + obj = vm->py_next(it); + } + return vm->None; + }); + vm->bind(type, "extendleft(self, iterable) -> None", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); - 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); - }); + PyObject *it = vm->py_iter(args[1]); // strong ref + PyObject *obj = vm->py_next(it); + while (obj != vm->StopIteration) + { + self.appendLeft(obj); + obj = vm->py_next(it); + } + return vm->None; + }); + vm->bind(type, "index(self, obj, start=0, stop=None) -> int", + [](VM *vm, ArgsView args) + { + // TODO: implement and validate + printf("TODO: implement deque.index()"); + return vm->None; + }); - 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, "insert(self, index, obj) -> None", + [](VM *vm, ArgsView args) + { + // TODO: implement and validate - vm->bind(type, "clear(self) -> None", - [](VM *vm, ArgsView args) - { - PyDeque &self = _CAST(PyDeque &, args[0]); - self.clear(); - return vm->None; - }); - } + printf("TODO: implement deque.insert()"); + 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); - } + vm->bind(type, "__repr__(self) -> str", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + std::stringstream ss = self.getRepr(vm); + return VAR(ss.str()); + }); - 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; - } + vm->bind(type, "pop(self) -> PyObject", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + return self.pop(); + }); - 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; - } + vm->bind(type, "popleft(self) -> PyObject", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + return self.popLeft(); + }); - 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(); - } + vm->bind(type, "remove(self, obj) -> None", + [](VM *vm, ArgsView args) + { + // TODO: implement and validate + printf("TODO: implement deque.index()"); + return vm->None; + }); - void PyDeque::printHelloWorld() - { - printf("Hello World!\n"); - return; - } + vm->bind(type, "reverse(self) -> None", + [](VM *vm, ArgsView args) + { + PyDeque &self = _CAST(PyDeque &, args[0]); + 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; + }); + + // vm->bind(type,"maxlen", + // [](VM *vm, ArgsView args) + // { + // return VAR(-1); + // }); + } - void add_module_mycollections(VM *vm) - { - PyObject *mycollections = vm->new_module("collections"); - PyDeque::register_class(vm, mycollections); - } + void PyDeque::_gc_mark() const + { + // TODO: implement + } + std::stringstream PyDeque::getRepr(VM *vm) + { + std::stringstream ss; + ss << "deque(["; + DequeNode *p = this->dequeItems->head->next; + while (p != this->dequeItems->tail) + { + ss << CAST(Str &, vm->py_repr(p->obj)); + if (p->next != this->dequeItems->tail) + ss << ", "; + p = p->next; + } + ss << "])"; + return ss; + } + + void PyDeque::reverse() + { + this->dequeItems->reverse(); + } + + void PyDeque::appendLeft(PyObject *item) + { + DequeNode *node = new DequeNode(item); + this->dequeItems->push_front(node); + } + void PyDeque::append(PyObject *item) + { + DequeNode *node = new DequeNode(item); + this->dequeItems->push_back(node); + } + + PyObject *PyDeque::popLeft() + { + if (this->dequeItems->empty()) + { + throw std::runtime_error("pop from an empty deque"); + } + DequeNode *node = this->dequeItems->pop_front(); + return node->obj; + } + + PyObject *PyDeque::pop() + { + 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(VM *vm, PyObject *obj) + { + return this->dequeItems->count(vm, obj); + } + void PyDeque::clear() + { + this->dequeItems->makeListEmpty(); + } + + void add_module_mycollections(VM *vm) + { + PyObject *mycollections = vm->new_module("mycollections"); + PyDeque::register_class(vm, mycollections); + } } // namespace pkpypkpy