WIP: switched to std::deque

This commit is contained in:
S. Mahmudul Hasan 2023-10-14 12:53:58 -04:00
parent 76e7746d25
commit 2852c1ab7e
2 changed files with 180 additions and 176 deletions

View File

@ -6,142 +6,143 @@
#include "str.h" #include "str.h"
#include "iter.h" #include "iter.h"
#include "cffi.h" #include "cffi.h"
#include <deque>
namespace pkpy namespace pkpy
{ {
struct DequeNode // struct DequeNode
{ // {
PyObject *obj; // PyObject *obj;
DequeNode *prev; // DequeNode *prev;
DequeNode *next; // DequeNode *next;
DequeNode() // DequeNode()
{ // {
this->obj = nullptr; // ignored value, sentinnel // this->obj = nullptr; // ignored value, sentinnel
this->prev = nullptr; // this->prev = nullptr;
this->next = nullptr; // this->next = nullptr;
} // }
DequeNode(PyObject *obj) // DequeNode(PyObject *obj)
{ // {
this->obj = obj; // this->obj = obj;
this->prev = nullptr; // this->prev = nullptr;
this->next = nullptr; // this->next = nullptr;
} // }
~DequeNode() // ~DequeNode()
{ // {
} // }
}; // };
struct MyDoublyLinkedList // struct MyDoublyLinkedList
{ // {
int len; // int len;
DequeNode *head; // DequeNode *head;
DequeNode *tail; // DequeNode *tail;
MyDoublyLinkedList() // MyDoublyLinkedList()
{ // creates an empty list // { // creates an empty list
this->len = 0; // this->len = 0;
this->head = new DequeNode(); // dummy // this->head = new DequeNode(); // dummy
this->tail = new DequeNode(); // dummy // this->tail = new DequeNode(); // dummy
this->head->next = this->tail; // this->head->next = this->tail;
this->tail->prev = this->head; // this->tail->prev = this->head;
} // }
~MyDoublyLinkedList() // ~MyDoublyLinkedList()
{ // {
if (this->head == nullptr) // if (this->head == nullptr)
return; // return;
this->makeListEmpty(); // this->makeListEmpty();
delete this->head; // delete this->head;
delete this->tail; // delete this->tail;
} // }
void push_back(DequeNode *node) // void push_back(DequeNode *node)
{ // {
node->prev = this->tail->prev; // node->prev = this->tail->prev;
node->next = this->tail; // node->next = this->tail;
this->tail->prev->next = node; // this->tail->prev->next = node;
this->tail->prev = node; // this->tail->prev = node;
this->len++; // this->len++;
} // }
void push_front(DequeNode *node) // void push_front(DequeNode *node)
{ // {
node->prev = this->head; // node->prev = this->head;
node->next = this->head->next; // node->next = this->head->next;
this->head->next->prev = node; // this->head->next->prev = node;
this->head->next = node; // this->head->next = node;
this->len++; // this->len++;
} // }
DequeNode *pop_back() // DequeNode *pop_back()
{ // {
if (this->empty()) // if (this->empty())
throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list"); // throw std::runtime_error("DoubleLinkedList::pop_back() called on empty list");
DequeNode *node = this->tail->prev; // DequeNode *node = this->tail->prev;
this->tail->prev->prev->next = this->tail; // this->tail->prev->prev->next = this->tail;
this->tail->prev = this->tail->prev->prev; // this->tail->prev = this->tail->prev->prev;
this->len--; // this->len--;
return node; // return node;
} // }
DequeNode *pop_front() // DequeNode *pop_front()
{ // {
if (this->empty()) // if (this->empty())
throw std::runtime_error("DoubleLinkedList::pop_front() called on empty list"); // throw std::runtime_error("DoubleLinkedList::pop_front() called on empty list");
DequeNode *node = this->head->next; // DequeNode *node = this->head->next;
this->head->next->next->prev = this->head; // this->head->next->next->prev = this->head;
this->head->next = this->head->next->next; // this->head->next = this->head->next->next;
this->len--; // this->len--;
return node; // return node;
} // }
bool empty() const // bool empty() const
{ // {
if (this->len == 0) // if (this->len == 0)
{ // {
if (this->head->next != this->tail || this->tail->prev != this->head) // 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"); // throw std::runtime_error("DoubleLinkedList::size() returned 0 but the list is not empty");
} // }
return true; // return true;
} // }
return false; // return false;
} // }
int size() const // int size() const
{ // {
return this->len; // return this->len;
} // }
void makeListEmpty() // void makeListEmpty()
{ // {
while (!this->empty()) // while (!this->empty())
{ // {
this->pop_back(); // this->pop_back();
} // }
} // }
void reverse() // void reverse()
{ // {
if (this->empty()) // if (this->empty())
return; // return;
// Go through each node, including the dummy nodes // // Go through each node, including the dummy nodes
// and swap the prev and next pointers // // and swap the prev and next pointers
DequeNode *p = this->head; // DequeNode *p = this->head;
while (p!=nullptr){ // while (p!=nullptr){
DequeNode *tmp = p->next; // DequeNode *tmp = p->next;
p->next = p->prev; // p->next = p->prev;
p->prev = tmp; // p->prev = tmp;
p = tmp; // p = tmp;
} // }
// swap the head and tail pointers // // swap the head and tail pointers
DequeNode *tmp = this->head; // DequeNode *tmp = this->head;
this->head = this->tail; // this->head = this->tail;
this->tail = tmp; // this->tail = tmp;
} // }
}; // };
// STARTING HERE // STARTING HERE
struct PyDeque struct PyDeque
@ -149,7 +150,8 @@ namespace pkpy
PY_CLASS(PyDeque, mycollections, deque); PY_CLASS(PyDeque, mycollections, deque);
// some fields can be defined here // some fields can be defined here
MyDoublyLinkedList *dequeItems;
std::deque<PyObject*>dequeItems;
void appendLeft(PyObject *item); void appendLeft(PyObject *item);
void append(PyObject *item); void append(PyObject *item);
@ -157,12 +159,12 @@ namespace pkpy
PyObject *pop(); PyObject *pop();
std::stringstream getRepr(VM *vm); std::stringstream getRepr(VM *vm);
void reverse(); void reverse();
int findIndex(PyObject *obj, int startPos, int endPos); // vm is needed for the py_equals 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 int count(VM *vm, PyObject *obj); // vm is needed for the py_equals
void clear(); void clear();
PyDeque() : dequeItems(new MyDoublyLinkedList()) {} PyDeque(){}
static void _register(VM *vm, PyObject *mod, PyObject *type); 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

View File

@ -23,7 +23,7 @@ namespace pkpy
[](VM *vm, ArgsView args) [](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, args[0]);
return VAR(self.dequeItems->size()); return VAR(self.dequeItems.size());
}); });
vm->bind(type, "append(self, item) -> None", vm->bind(type, "append(self, item) -> None",
@ -55,15 +55,17 @@ namespace pkpy
vm->bind(type, "copy(self) -> deque", vm->bind(type, "copy(self) -> deque",
[](VM *vm, ArgsView args) [](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); //TODO: implement and validate
PyDeque *newDeque = new PyDeque(); return vm->None;
DequeNode *p = self.dequeItems->head->next; // PyDeque &self = _CAST(PyDeque &, args[0]);
while (p != self.dequeItems->tail) // PyDeque *newDeque = new PyDeque();
{ // DequeNode *p = self.dequeItems->head->next;
newDeque->append(p->obj); // while (p != self.dequeItems->tail)
p = p->next; // {
} // newDeque->append(p->obj);
return vm->heap.gcnew<PyDeque>(PyDeque::_type(vm), *newDeque); // p = p->next;
// }
// return vm->heap.gcnew<PyDeque>(PyDeque::_type(vm), *newDeque);
}); });
vm->bind(type, "count(self, obj) -> int", vm->bind(type, "count(self, obj) -> int",
@ -113,7 +115,7 @@ namespace pkpy
PyObject *obj = args[1]; PyObject *obj = args[1];
int start = CAST(int, args[2]); int start = CAST(int, args[2]);
int stop = CAST(int, args[3]); int stop = CAST(int, args[3]);
int idx = self.findIndex(obj, start, stop); int idx = self.findIndex(vm, obj, start, stop);
if (idx == -1) if (idx == -1)
vm->ValueError(_CAST(Str &, vm->py_repr(obj)) + " is not in list"); vm->ValueError(_CAST(Str &, vm->py_repr(obj)) + " is not in list");
@ -184,111 +186,111 @@ namespace pkpy
void PyDeque::_gc_mark() const void PyDeque::_gc_mark() const
{ {
DequeNode *p = this->dequeItems->head->next; //TODO: HOW TO IMPLEMENT THIS?
while (p != this->dequeItems->tail)
{
PK_OBJ_MARK(p->obj); // PK_OBJ_MARK is a macro that calls _gc_mark on the PK_OBJ
p = p->next;
}
} }
std::stringstream PyDeque::getRepr(VM *vm) std::stringstream PyDeque::getRepr(VM *vm)
{ {
std::stringstream ss; std::stringstream ss;
int sz = this->dequeItems.size();
ss << "deque(["; ss << "deque([";
DequeNode *p = this->dequeItems->head->next; for (auto it = this->dequeItems.begin(); it != this->dequeItems.end(); ++it)
while (p != this->dequeItems->tail)
{ {
ss << CAST(Str &, vm->py_repr(p->obj)); ss << CAST(Str &, vm->py_repr(*it));
if (p->next != this->dequeItems->tail) if (it != this->dequeItems.end() - 1)
{
ss << ", "; ss << ", ";
p = p->next; }
} }
ss << "])"; ss << "])";
return ss; return ss;
} }
int PyDeque::findIndex(PyObject *obj, int startPos = -1, int endPos = -1) int PyDeque::findIndex(VM *vm, PyObject *obj, int startPos = -1, int endPos = -1)
{ {
if (startPos == -1) if (startPos == -1)
startPos = 0; startPos = 0;
if (endPos == -1) if (endPos == -1)
endPos = this->dequeItems->size(); endPos = this->dequeItems.size();
if (!(startPos <= endPos)) if (!(startPos <= endPos))
{ {
throw std::runtime_error("startPos<=endPos"); throw std::runtime_error("startPos<=endPos");
} }
int cnt = 0; int dequeSize = this->dequeItems.size();
DequeNode *p = this->dequeItems->head->next;
while (p != this->dequeItems->tail) for (int i = startPos; i<dequeSize && i < endPos; i++)
{ {
if (p->obj == obj) if (vm->py_equals(this->dequeItems[i], obj))
{ {
if (startPos == -1 || cnt >= startPos) return i;
{
if (endPos == -1 || cnt < endPos)
{
return cnt;
}
}
} }
cnt++;
p = p->next;
} }
return -1; return -1;
} }
void PyDeque::reverse() void PyDeque::reverse()
{ {
this->dequeItems->reverse(); int sz = this->dequeItems.size();
for (int i = 0; i < sz / 2; i++)
{
PyObject *tmp = this->dequeItems[i];
this->dequeItems[i] = this->dequeItems[sz - i - 1];
this->dequeItems[sz - i - 1] = tmp;
}
} }
void PyDeque::appendLeft(PyObject *item) void PyDeque::appendLeft(PyObject *item)
{ {
DequeNode *node = new DequeNode(item); this->dequeItems.emplace_front(item);
this->dequeItems->push_front(node);
} }
void PyDeque::append(PyObject *item) void PyDeque::append(PyObject *item)
{ {
DequeNode *node = new DequeNode(item); this->dequeItems.emplace_back(item);
this->dequeItems->push_back(node);
} }
PyObject *PyDeque::popLeft() PyObject *PyDeque::popLeft()
{ {
if (this->dequeItems->empty()) if (this->dequeItems.empty())
{ {
throw std::runtime_error("pop from an empty deque"); throw std::runtime_error("pop from an empty deque");
} }
DequeNode *node = this->dequeItems->pop_front(); PyObject *obj = this->dequeItems.front();
return node->obj; this->dequeItems.pop_front();
return obj;
} }
PyObject *PyDeque::pop() PyObject *PyDeque::pop()
{ {
if (this->dequeItems->empty()) if (this->dequeItems.empty())
{ {
throw std::runtime_error("pop from an empty deque"); throw std::runtime_error("pop from an empty deque");
} }
DequeNode *node = this->dequeItems->pop_back(); PyObject *obj = this->dequeItems.back();
return node->obj; this->dequeItems.pop_back();
return obj;
} }
int PyDeque::count(VM *vm, PyObject *obj) int PyDeque::count(VM *vm, PyObject *obj)
{ {
int cnt = 0; int cnt = 0;
DequeNode *p = this->dequeItems->head->next;
while (p != this->dequeItems->tail) for (auto it = this->dequeItems.begin(); it != this->dequeItems.end(); ++it)
{ {
if (vm->py_equals(p->obj, obj)) if (vm->py_equals((*it), obj))
{
cnt++; cnt++;
p = p->next; }
} }
return cnt; return cnt;
} }
void PyDeque::clear() void PyDeque::clear()
{ {
this->dequeItems->makeListEmpty(); this->dequeItems.clear();
} }
void add_module_mycollections(VM *vm) void add_module_mycollections(VM *vm)