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 "iter.h"
#include "cffi.h"
#include <deque>
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;
}
// 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()
{
}
};
// ~DequeNode()
// {
// }
// };
struct MyDoublyLinkedList
{
int len;
DequeNode *head;
DequeNode *tail;
// 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()
// { // 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;
}
// ~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++;
}
// 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_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;
}
// 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;
}
// 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;
}
// int size() const
// {
// return this->len;
// }
void makeListEmpty()
{
while (!this->empty())
{
this->pop_back();
}
}
// 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;
}
// 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;
}
// // swap the head and tail pointers
// DequeNode *tmp = this->head;
// this->head = this->tail;
// this->tail = tmp;
// }
};
// };
// STARTING HERE
struct PyDeque
@ -149,7 +150,8 @@ namespace pkpy
PY_CLASS(PyDeque, mycollections, deque);
// some fields can be defined here
MyDoublyLinkedList *dequeItems;
std::deque<PyObject*>dequeItems;
void appendLeft(PyObject *item);
void append(PyObject *item);
@ -157,12 +159,12 @@ namespace pkpy
PyObject *pop();
std::stringstream getRepr(VM *vm);
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
void clear();
PyDeque() : dequeItems(new MyDoublyLinkedList()) {}
PyDeque(){}
static void _register(VM *vm, PyObject *mod, PyObject *type);
void _gc_mark() const; // needed for container types

View File

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