mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-10 13:40:16 +00:00
refactored collections module
This commit is contained in:
parent
1f936063ae
commit
97544eb499
@ -9,47 +9,5 @@
|
|||||||
|
|
||||||
namespace pkpy
|
namespace pkpy
|
||||||
{
|
{
|
||||||
// STARTING HERE
|
|
||||||
struct PyDeque
|
|
||||||
{
|
|
||||||
PY_CLASS(PyDeque, collections, deque);
|
|
||||||
|
|
||||||
PyDeque(VM *vm, PyObject *iterable, PyObject* maxlen);
|
|
||||||
|
|
||||||
// PyDeque members
|
|
||||||
std::deque<PyObject *> dequeItems;
|
|
||||||
int maxlen=-1; // -1 means unbounded
|
|
||||||
bool bounded=false; // if true, maxlen is not -1
|
|
||||||
|
|
||||||
|
|
||||||
// PyDeque methods: add, remove, insert, etc.
|
|
||||||
void appendLeft(PyObject *item); // add to the left
|
|
||||||
void append(PyObject *item); // add to the right
|
|
||||||
PyObject *popLeft(); // remove from the left
|
|
||||||
PyObject *pop(); // remove from the right
|
|
||||||
bool insert(int index, PyObject *item); // insert at index
|
|
||||||
bool remove(VM *vm, PyObject *item); // remove first occurence of item
|
|
||||||
|
|
||||||
|
|
||||||
void rotate(int n); // rotate n steps to the right
|
|
||||||
void reverse();// reverse the deque
|
|
||||||
void clear(); // clear the deque
|
|
||||||
|
|
||||||
|
|
||||||
int count(VM *vm, PyObject *obj); // count the number of occurences of obj
|
|
||||||
int findIndex(VM *vm, PyObject *obj, int startPos, int endPos); // find the index of obj in range starting from startPos and ending at endPos, default range is entire deque
|
|
||||||
|
|
||||||
PyObject* getItem(int index); // get item at index
|
|
||||||
bool setItem(int index, PyObject* item); // set item at index
|
|
||||||
bool eraseItem(int index);// erase item at index
|
|
||||||
|
|
||||||
std::stringstream getRepr(VM *vm); // get the string representation of the deque
|
|
||||||
|
|
||||||
int fixIndex(int index); // for internal use only, returns -1 if index is out of range, handles negative indices
|
|
||||||
// Special methods
|
|
||||||
static void _register(VM *vm, PyObject *mod, PyObject *type); // register the type
|
|
||||||
void _gc_mark() const; // needed for container types, mark all objects in the deque for gc
|
|
||||||
};
|
|
||||||
|
|
||||||
void add_module_collections(VM *vm);
|
void add_module_collections(VM *vm);
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
@ -1,19 +1,33 @@
|
|||||||
#include "pocketpy/collections.h"
|
#include "pocketpy/collections.h"
|
||||||
|
|
||||||
namespace pkpy
|
namespace pkpy
|
||||||
{
|
{
|
||||||
|
// STARTING HERE
|
||||||
|
struct PyDeque
|
||||||
|
{
|
||||||
|
PY_CLASS(PyDeque, collections, deque);
|
||||||
|
PyDeque(VM *vm, PyObject *iterable, PyObject *maxlen); // constructor
|
||||||
|
// PyDeque members
|
||||||
|
std::deque<PyObject *> dequeItems;
|
||||||
|
int maxlen = -1; // -1 means unbounded
|
||||||
|
bool bounded = false; // if true, maxlen is not -1
|
||||||
|
void insertObj(bool front, bool back, int index, PyObject *item); // insert at index, used purely for internal purposes: append, appendleft, insert methods
|
||||||
|
PyObject *popObj(bool front, bool back, PyObject *item, VM *vm); // pop at index, used purely for internal purposes: pop, popleft, remove methods
|
||||||
|
std::stringstream getRepr(VM *vm); // get the string representation of the deque
|
||||||
|
// Special methods
|
||||||
|
static void _register(VM *vm, PyObject *mod, PyObject *type); // register the type
|
||||||
|
void _gc_mark() const; // needed for container types, mark all objects in the deque for gc
|
||||||
|
};
|
||||||
void PyDeque::_register(VM *vm, PyObject *mod, PyObject *type)
|
void PyDeque::_register(VM *vm, PyObject *mod, PyObject *type)
|
||||||
{
|
{
|
||||||
vm->bind(type, "__new__(cls, iterable=None, maxlen=None)",
|
vm->bind(type, "__new__(cls, iterable=None, maxlen=None)",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
|
printf("HELLO WORLD!!");
|
||||||
Type cls_t = PK_OBJ_GET(Type, args[0]);
|
Type cls_t = PK_OBJ_GET(Type, args[0]);
|
||||||
PyObject *iterable = args[1];
|
PyObject *iterable = args[1];
|
||||||
PyObject *maxlen = args[2];
|
PyObject *maxlen = args[2];
|
||||||
|
|
||||||
return vm->heap.gcnew<PyDeque>(cls_t, vm, iterable, maxlen);
|
return vm->heap.gcnew<PyDeque>(cls_t, vm, iterable, maxlen);
|
||||||
});
|
});
|
||||||
|
|
||||||
// gets the item at the given index, if index is negative, it will be treated as index + len(deque)
|
// gets the item at the given index, if index is negative, it will be treated as index + len(deque)
|
||||||
// if the index is out of range, IndexError will be thrown --> required for [] operator
|
// if the index is out of range, IndexError will be thrown --> required for [] operator
|
||||||
vm->bind(type, "__getitem__(self, index) -> PyObject",
|
vm->bind(type, "__getitem__(self, index) -> PyObject",
|
||||||
@ -21,16 +35,9 @@ namespace pkpy
|
|||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
int index = CAST(int, args[1]);
|
int index = CAST(int, args[1]);
|
||||||
|
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
|
||||||
PyObject *item = self.getItem(index);
|
return self.dequeItems.at(index);
|
||||||
if (item == nullptr)
|
|
||||||
{
|
|
||||||
vm->IndexError("deque index out of range");
|
|
||||||
return vm->None;
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// sets the item at the given index, if index is negative, it will be treated as index + len(deque)
|
// sets the item at the given index, if index is negative, it will be treated as index + len(deque)
|
||||||
// if the index is out of range, IndexError will be thrown --> required for [] operator
|
// if the index is out of range, IndexError will be thrown --> required for [] operator
|
||||||
vm->bind(type, "__setitem__(self, index, newValue) -> None",
|
vm->bind(type, "__setitem__(self, index, newValue) -> None",
|
||||||
@ -39,16 +46,10 @@ namespace pkpy
|
|||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
int index = CAST(int, args[1]);
|
int index = CAST(int, args[1]);
|
||||||
PyObject *newValue = args[2];
|
PyObject *newValue = args[2];
|
||||||
|
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
|
||||||
bool success = self.setItem(index, newValue);
|
self.dequeItems.at(index) = newValue;
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
vm->IndexError("deque index out of range");
|
|
||||||
return vm->None;
|
|
||||||
}
|
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// erases the item at the given index, if index is negative, it will be treated as index + len(deque)
|
// erases the item at the given index, if index is negative, it will be treated as index + len(deque)
|
||||||
// if the index is out of range, IndexError will be thrown --> required for [] operator
|
// if the index is out of range, IndexError will be thrown --> required for [] operator
|
||||||
vm->bind(type, "__delitem__(self, index) -> None",
|
vm->bind(type, "__delitem__(self, index) -> None",
|
||||||
@ -56,206 +57,196 @@ namespace pkpy
|
|||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
int index = CAST(int, args[1]);
|
int index = CAST(int, args[1]);
|
||||||
|
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
|
||||||
bool success = self.eraseItem(index);
|
self.dequeItems.erase(self.dequeItems.begin() + index);
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
vm->IndexError("deque index out of range");
|
|
||||||
return vm->None;
|
|
||||||
}
|
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// returns the length of the deque
|
// returns the length of the deque
|
||||||
vm->bind(type, "__len__(self) -> int",
|
vm->bind(type, "__len__(self) -> int",
|
||||||
[](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());
|
||||||
});
|
});
|
||||||
|
|
||||||
// returns an iterator for the deque
|
// returns an iterator for the deque
|
||||||
vm->bind(type, "__iter__(self) -> deque_iterator",
|
vm->bind(type, "__iter__(self) -> deque_iterator",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
|
|
||||||
return vm->heap.gcnew<PyDequeIter>(
|
return vm->heap.gcnew<PyDequeIter>(
|
||||||
PyDequeIter::_type(vm), args[0],
|
PyDequeIter::_type(vm), args[0],
|
||||||
self.dequeItems.begin(), self.dequeItems.end());
|
self.dequeItems.begin(), self.dequeItems.end());
|
||||||
});
|
});
|
||||||
|
|
||||||
// returns a string representation of the deque
|
// returns a string representation of the deque
|
||||||
vm->bind(type, "__repr__(self) -> str",
|
vm->bind(type, "__repr__(self) -> str",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
|
std::stringstream ss;
|
||||||
std::stringstream ss = self.getRepr(vm);
|
ss << "deque([";
|
||||||
|
for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it)
|
||||||
|
{
|
||||||
|
ss << CAST(Str &, vm->py_repr(*it));
|
||||||
|
if (it != self.dequeItems.end() - 1)
|
||||||
|
ss << ", ";
|
||||||
|
}
|
||||||
|
self.bounded ? ss << "], maxlen=" << self.maxlen << ")" : ss << "])";
|
||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
|
|
||||||
// enables comparison between two deques, == and != are supported
|
// enables comparison between two deques, == and != are supported
|
||||||
vm->bind(type, "__eq__(self, other) -> bool",
|
vm->bind(type, "__eq__(self, other) -> bool",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
PyDeque &other = _CAST(PyDeque &, args[1]);
|
PyDeque &other = _CAST(PyDeque &, args[1]);
|
||||||
|
if (self.dequeItems.size() != other.dequeItems.size()) // trivial case
|
||||||
if (self.dequeItems.size() != other.dequeItems.size())
|
|
||||||
return VAR(false);
|
return VAR(false);
|
||||||
for (int i = 0; i < self.dequeItems.size(); i++)
|
for (int i = 0; i < self.dequeItems.size(); i++)
|
||||||
{
|
|
||||||
if (!vm->py_equals(self.dequeItems[i], other.dequeItems[i]))
|
if (!vm->py_equals(self.dequeItems[i], other.dequeItems[i]))
|
||||||
return VAR(false);
|
return VAR(false);
|
||||||
}
|
|
||||||
return VAR(true);
|
return VAR(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// clear the deque
|
// clear the deque
|
||||||
vm->bind(type, "clear(self) -> None",
|
vm->bind(type, "clear(self) -> None",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
|
self.dequeItems.clear();
|
||||||
self.clear();
|
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// extend the deque with the given iterable
|
// extend the deque with the given iterable
|
||||||
vm->bind(type, "extend(self, iterable) -> None",
|
vm->bind(type, "extend(self, iterable) -> None",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
auto _lock = vm->heap.gc_scope_lock(); // locking the heap
|
auto _lock = vm->heap.gc_scope_lock(); // locking the heap
|
||||||
|
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
PyObject *it = vm->py_iter(args[1]); // strong ref
|
PyObject *it = vm->py_iter(args[1]); // strong ref
|
||||||
|
|
||||||
PyObject *obj = vm->py_next(it);
|
PyObject *obj = vm->py_next(it);
|
||||||
while (obj != vm->StopIteration)
|
while (obj != vm->StopIteration)
|
||||||
{
|
{
|
||||||
self.append(obj);
|
self.insertObj(false, true, -1, obj);
|
||||||
obj = vm->py_next(it);
|
obj = vm->py_next(it);
|
||||||
}
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// append at the end of the deque
|
// append at the end of the deque
|
||||||
vm->bind(type, "append(self, item) -> None",
|
vm->bind(type, "append(self, item) -> None",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
PyObject *item = args[1];
|
PyObject *item = args[1];
|
||||||
|
self.insertObj(false, true, -1, item);
|
||||||
self.append(item);
|
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// append at the beginning of the deque
|
// append at the beginning of the deque
|
||||||
vm->bind(type, "appendleft(self, item) -> None",
|
vm->bind(type, "appendleft(self, item) -> None",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
PyObject *item = args[1];
|
PyObject *item = args[1];
|
||||||
|
self.insertObj(true, false, -1, item);
|
||||||
self.appendLeft(item);
|
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// pop from the end of the deque
|
// pop from the end of the deque
|
||||||
vm->bind(type, "pop(self) -> PyObject",
|
vm->bind(type, "pop(self) -> PyObject",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
|
|
||||||
if (self.dequeItems.empty())
|
if (self.dequeItems.empty())
|
||||||
{
|
{
|
||||||
vm->IndexError("pop from an empty deque");
|
vm->IndexError("pop from an empty deque");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}
|
}
|
||||||
return self.pop();
|
return self.popObj(false, true, nullptr, vm);
|
||||||
});
|
});
|
||||||
|
|
||||||
// pop from the beginning of the deque
|
// pop from the beginning of the deque
|
||||||
vm->bind(type, "popleft(self) -> PyObject",
|
vm->bind(type, "popleft(self) -> PyObject",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
|
|
||||||
if (self.dequeItems.empty())
|
if (self.dequeItems.empty())
|
||||||
{
|
{
|
||||||
vm->IndexError("pop from an empty deque");
|
vm->IndexError("pop from an empty deque");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}
|
}
|
||||||
return self.popLeft();
|
return self.popObj(true, false, nullptr, vm);
|
||||||
});
|
});
|
||||||
|
|
||||||
// shallow copy of the deque
|
// shallow copy of the deque
|
||||||
vm->bind(type, "copy(self) -> deque",
|
vm->bind(type, "copy(self) -> deque",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
auto _lock = vm->heap.gc_scope_lock(); // locking the heap
|
auto _lock = vm->heap.gc_scope_lock(); // locking the heap
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
|
|
||||||
// shallow copy
|
|
||||||
PyObject *newDequeObj = vm->heap.gcnew<PyDeque>(PyDeque::_type(vm), vm, vm->None, vm->None); // create the empty deque
|
PyObject *newDequeObj = vm->heap.gcnew<PyDeque>(PyDeque::_type(vm), vm, vm->None, vm->None); // create the empty deque
|
||||||
PyDeque &newDeque = _CAST(PyDeque &, newDequeObj); // cast it to PyDeque so we can use its methods
|
PyDeque &newDeque = _CAST(PyDeque &, newDequeObj); // cast it to PyDeque so we can use its methods
|
||||||
for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it)
|
for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it)
|
||||||
{
|
newDeque.insertObj(false, true, -1, *it);
|
||||||
newDeque.append(*it); // append each item to the new deque
|
|
||||||
}
|
|
||||||
return newDequeObj;
|
return newDequeObj;
|
||||||
});
|
});
|
||||||
|
// NEW: counts the number of occurences of the given object in the deque
|
||||||
//NEW: counts the number of occurences of the given object in the deque
|
|
||||||
vm->bind(type, "count(self, obj) -> int",
|
vm->bind(type, "count(self, obj) -> int",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
PyObject *obj = args[1];
|
PyObject *obj = args[1];
|
||||||
|
int cnt = 0;
|
||||||
return VAR(self.count(vm, obj));
|
for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it)
|
||||||
|
if (vm->py_equals((*it), obj))
|
||||||
|
cnt++;
|
||||||
|
return VAR(cnt);
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: extends the deque from the left
|
// NEW: extends the deque from the left
|
||||||
vm->bind(type, "extendleft(self, iterable) -> None",
|
vm->bind(type, "extendleft(self, iterable) -> None",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
auto _lock = vm->heap.gc_scope_lock();
|
auto _lock = vm->heap.gc_scope_lock();
|
||||||
|
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
PyObject *it = vm->py_iter(args[1]); // strong ref
|
PyObject *it = vm->py_iter(args[1]); // strong ref
|
||||||
|
|
||||||
PyObject *obj = vm->py_next(it);
|
PyObject *obj = vm->py_next(it);
|
||||||
while (obj != vm->StopIteration)
|
while (obj != vm->StopIteration)
|
||||||
{
|
{
|
||||||
self.appendLeft(obj);
|
self.insertObj(true, false, -1, obj);
|
||||||
obj = vm->py_next(it);
|
obj = vm->py_next(it);
|
||||||
}
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: returns the index of the given object in the deque
|
// NEW: returns the index of the given object in the deque
|
||||||
vm->bind(type, "index(self, obj, start=-1, stop=-1) -> int",
|
vm->bind(type, "index(self, obj, start=None, stop=None) -> int",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
// Return the position of x in the deque (at or after index start and before index stop). Returns the first match or raises ValueError if not found.
|
// Return the position of x in the deque (at or after index start and before index stop). Returns the first match or raises ValueError if not found.
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
PyObject *obj = args[1];
|
PyObject *obj = args[1];
|
||||||
|
int start = 0, stop = self.dequeItems.size(); // default values
|
||||||
int start = CAST(int, args[2]);
|
if (!vm->py_equals(args[2], vm->None))
|
||||||
int stop = CAST(int, args[3]);
|
start = CAST(int, args[2]);
|
||||||
int idx = self.findIndex(vm, obj, start, stop);
|
if (!vm->py_equals(args[3], vm->None))
|
||||||
|
stop = CAST(int, args[3]);
|
||||||
if (idx == -1)
|
// the following code is special purpose normalization for this method, taken from CPython: _collectionsmodule.c file
|
||||||
|
if (start < 0)
|
||||||
{
|
{
|
||||||
vm->ValueError(_CAST(Str &, vm->py_repr(obj)) + " is not in deque");
|
start = self.dequeItems.size() + start; // try to fix for negative indices
|
||||||
return vm->None;
|
if (start < 0)
|
||||||
|
start = 0;
|
||||||
}
|
}
|
||||||
return VAR(idx);
|
if (stop < 0)
|
||||||
|
{
|
||||||
|
stop = self.dequeItems.size() + stop; // try to fix for negative indices
|
||||||
|
if (stop < 0)
|
||||||
|
stop = 0;
|
||||||
|
}
|
||||||
|
if (stop > self.dequeItems.size())
|
||||||
|
stop = self.dequeItems.size();
|
||||||
|
if (start > stop)
|
||||||
|
start = stop; // end of normalization
|
||||||
|
PK_ASSERT(start >= 0 && start <= self.dequeItems.size() && stop >= 0 && stop <= self.dequeItems.size() && start <= stop); // sanity check
|
||||||
|
int loopSize = std::min((int)self.dequeItems.size(), stop);
|
||||||
|
for (int i = start; i < loopSize; i++)
|
||||||
|
if (vm->py_equals(self.dequeItems[i], obj))
|
||||||
|
return VAR(i);
|
||||||
|
vm->ValueError(_CAST(Str &, vm->py_repr(obj)) + " is not in deque");
|
||||||
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: inserts the given object at the given index
|
// NEW: inserts the given object at the given index
|
||||||
vm->bind(type, "insert(self, index, obj) -> None",
|
vm->bind(type, "insert(self, index, obj) -> None",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
@ -263,50 +254,69 @@ namespace pkpy
|
|||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
int index = CAST(int, args[1]);
|
int index = CAST(int, args[1]);
|
||||||
PyObject *obj = args[2];
|
PyObject *obj = args[2];
|
||||||
|
|
||||||
if (self.bounded && self.dequeItems.size() == self.maxlen)
|
if (self.bounded && self.dequeItems.size() == self.maxlen)
|
||||||
{
|
|
||||||
vm->ValueError("deque already at its maximum size");
|
vm->ValueError("deque already at its maximum size");
|
||||||
return vm->None;
|
else
|
||||||
}
|
self.insertObj(false, false, index, obj); // this index shouldn't be fixed using vm->normalized_index, pass as is
|
||||||
self.insert(index, obj);
|
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: removes the first occurence of the given object from the deque
|
// NEW: removes the first occurence of the given object from the deque
|
||||||
vm->bind(type, "remove(self, obj) -> None",
|
vm->bind(type, "remove(self, obj) -> None",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
PyObject *obj = args[1];
|
PyObject *obj = args[1];
|
||||||
|
PyObject *removed = self.popObj(false, false, obj, vm);
|
||||||
bool removed = self.remove(vm, obj);
|
if (removed == nullptr)
|
||||||
if (!removed)
|
|
||||||
vm->ValueError(_CAST(Str &, vm->py_repr(obj)) + " is not in list");
|
vm->ValueError(_CAST(Str &, vm->py_repr(obj)) + " is not in list");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: reverses the deque
|
// NEW: reverses the deque
|
||||||
vm->bind(type, "reverse(self) -> None",
|
vm->bind(type, "reverse(self) -> None",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
|
if (self.dequeItems.empty() || self.dequeItems.size() == 1)
|
||||||
self.reverse();
|
return vm->None; // handle trivial cases
|
||||||
|
int sz = self.dequeItems.size();
|
||||||
|
for (int i = 0; i < sz / 2; i++)
|
||||||
|
{
|
||||||
|
PyObject *tmp = self.dequeItems[i];
|
||||||
|
self.dequeItems[i] = self.dequeItems[sz - i - 1]; // swapping
|
||||||
|
self.dequeItems[sz - i - 1] = tmp;
|
||||||
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: rotates the deque by n steps
|
// NEW: rotates the deque by n steps
|
||||||
vm->bind(type, "rotate(self, n=1) -> None",
|
vm->bind(type, "rotate(self, n=1) -> None",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
int n = CAST(int, args[1]);
|
int n = CAST(int, args[1]);
|
||||||
if (n!=0) // handle trivial case
|
if (n != 0) // trivial case
|
||||||
self.rotate(n);
|
{
|
||||||
|
PyObject *tmp; // holds the object to be rotated
|
||||||
|
int direction = n > 0 ? 1 : -1;
|
||||||
|
n = abs(n);
|
||||||
|
n = n % self.dequeItems.size(); // make sure n is in range
|
||||||
|
while (n--)
|
||||||
|
{
|
||||||
|
if (direction == 1)
|
||||||
|
{
|
||||||
|
tmp = self.dequeItems.back();
|
||||||
|
self.dequeItems.pop_back();
|
||||||
|
self.dequeItems.push_front(tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmp = self.dequeItems.front();
|
||||||
|
self.dequeItems.pop_front();
|
||||||
|
self.dequeItems.push_back(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: getter and setter of property `maxlen`
|
// NEW: getter and setter of property `maxlen`
|
||||||
vm->bind_property(
|
vm->bind_property(
|
||||||
type, "maxlen: int",
|
type, "maxlen: int",
|
||||||
@ -315,284 +325,163 @@ namespace pkpy
|
|||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
if (self.bounded)
|
if (self.bounded)
|
||||||
return VAR(self.maxlen);
|
return VAR(self.maxlen);
|
||||||
else
|
return vm->None;
|
||||||
return vm->None;
|
|
||||||
},
|
},
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
vm->AttributeError("attribute 'maxlen' of 'collections.deque' objects is not writable");
|
vm->AttributeError("attribute 'maxlen' of 'collections.deque' objects is not writable");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
// NEW: support pickle
|
// NEW: support pickle
|
||||||
vm->bind(type, "__getnewargs__(self) -> tuple[list, int]",
|
vm->bind(type, "__getnewargs__(self) -> tuple[list, int]",
|
||||||
[](VM *vm, ArgsView args)
|
[](VM *vm, ArgsView args)
|
||||||
{
|
{
|
||||||
PyDeque &self = _CAST(PyDeque &, args[0]);
|
PyDeque &self = _CAST(PyDeque &, args[0]);
|
||||||
Tuple ret(2);
|
Tuple ret(2);
|
||||||
List list;
|
List list;
|
||||||
for(PyObject* obj: self.dequeItems){
|
for (PyObject *obj : self.dequeItems)
|
||||||
list.push_back(obj);
|
{
|
||||||
}
|
list.push_back(obj);
|
||||||
ret[0] = VAR(std::move(list));
|
}
|
||||||
if(self.bounded) ret[1] = VAR(self.maxlen);
|
ret[0] = VAR(std::move(list));
|
||||||
else ret[1] = vm->None;
|
if (self.bounded)
|
||||||
return VAR(ret);
|
ret[1] = VAR(self.maxlen);
|
||||||
});
|
else
|
||||||
|
ret[1] = vm->None;
|
||||||
|
return VAR(ret);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief initializes a new PyDeque object
|
/// @brief initializes a new PyDeque object
|
||||||
/// @param vm required for the py_iter and max_len casting
|
/// @param vm required for the py_iter and max_len casting
|
||||||
/// @param iterable a list-like object to initialize the deque with
|
/// @param iterable a list-like object to initialize the deque with
|
||||||
/// @param maxlen the maximum length of the deque, makes the deque bounded
|
/// @param maxlen the maximum length of the deque, makes the deque bounded
|
||||||
PyDeque::PyDeque(VM *vm, PyObject *iterable, PyObject *maxlen)
|
PyDeque::PyDeque(VM *vm, PyObject *iterable, PyObject *maxlen)
|
||||||
{
|
{
|
||||||
if (maxlen != vm->None)
|
if (!vm->py_equals(maxlen, vm->None))
|
||||||
{
|
{
|
||||||
this->maxlen = CAST(int, maxlen);
|
int tmp = CAST(int, maxlen);
|
||||||
if (this->maxlen < 0)
|
if (tmp < 0)
|
||||||
vm->ValueError("maxlen must be non-negative");
|
vm->ValueError("maxlen must be non-negative");
|
||||||
this->bounded = true;
|
else
|
||||||
|
{
|
||||||
|
this->maxlen = tmp;
|
||||||
|
this->bounded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->bounded = false;
|
this->bounded = false;
|
||||||
this->maxlen = -1;
|
this->maxlen = -1;
|
||||||
}
|
}
|
||||||
|
if (!vm->py_equals(iterable, vm->None))
|
||||||
if (iterable != vm->None)
|
|
||||||
{
|
{
|
||||||
auto _lock = vm->heap.gc_scope_lock(); // locking the heap
|
auto _lock = vm->heap.gc_scope_lock(); // locking the heap
|
||||||
PyObject *it = vm->py_iter(iterable); // strong ref
|
PyObject *it = vm->py_iter(iterable); // strong ref
|
||||||
PyObject *obj = vm->py_next(it);
|
PyObject *obj = vm->py_next(it);
|
||||||
while (obj != vm->StopIteration)
|
while (obj != vm->StopIteration)
|
||||||
{
|
{
|
||||||
this->append(obj);
|
this->insertObj(false, true, -1, obj);
|
||||||
obj = vm->py_next(it);
|
obj = vm->py_next(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// @brief returns the item at the given index, if index is negative, it will be treated as index + len(deque)
|
/// @brief pops or removes an item from the deque
|
||||||
/// @param index the index of the item to get
|
/// @param front if true, pop from the front of the deque
|
||||||
/// @return PyObject* the item at the given index, nullptr if the index is out of range
|
/// @param back if true, pop from the back of the deque
|
||||||
PyObject *PyDeque::getItem(int index)
|
/// @param item if front and back is not set, remove the first occurence of item from the deque
|
||||||
|
/// @param vm is needed for the py_equals
|
||||||
|
/// @return PyObject* if front or back is set, this is a pop operation and we return a PyObject*, if front and back are not set, this is a remove operation and we return the removed item or nullptr
|
||||||
|
PyObject *PyDeque::popObj(bool front, bool back, PyObject *item, VM *vm)
|
||||||
{
|
{
|
||||||
index = this->fixIndex(index);
|
// error handling
|
||||||
if (index == -1) return nullptr;
|
if (front && back)
|
||||||
return this->dequeItems.at(index);
|
throw std::runtime_error("both front and back are set"); // this should never happen
|
||||||
}
|
if (front || back)
|
||||||
/// @brief sets the item at the given index, if index is negative, it will be treated as index + len(deque)
|
|
||||||
/// @param index the index of the item to set
|
|
||||||
/// @param item the newValue for the item at the given index
|
|
||||||
/// @return true if the item was set successfully, false if the index is out of range
|
|
||||||
bool PyDeque::setItem(int index, PyObject *item)
|
|
||||||
{
|
|
||||||
index = this->fixIndex(index);
|
|
||||||
if (index == -1) return false;
|
|
||||||
this->dequeItems.at(index) = item;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/// @brief erases the item at the given index, if index is negative, it will be treated as index + len(deque)
|
|
||||||
/// @param index the index of the item to erase
|
|
||||||
/// @return true if the item was erased successfully, false if the index is out of range
|
|
||||||
bool PyDeque::eraseItem(int index)
|
|
||||||
{
|
|
||||||
index = this->fixIndex(index);
|
|
||||||
if (index == -1) return false;
|
|
||||||
this->dequeItems.erase(this->dequeItems.begin() + index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/// @brief rotates the deque by n steps
|
|
||||||
/// @param n the number of steps to rotate the deque by, can be -ve for left rotation, +ve for right rotation, can be out of range
|
|
||||||
void PyDeque::rotate(int n)
|
|
||||||
{
|
|
||||||
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)
|
// front or back is set, we don't care about item, this is a pop operation and we return a PyObject*
|
||||||
|
if (this->dequeItems.empty())
|
||||||
|
throw std::runtime_error("pop from an empty deque"); // shouldn't happen
|
||||||
|
PyObject *obj;
|
||||||
|
if (front)
|
||||||
{
|
{
|
||||||
PyObject *tmp = this->dequeItems.back();
|
obj = this->dequeItems.front();
|
||||||
this->dequeItems.pop_back();
|
this->dequeItems.pop_front();
|
||||||
this->dequeItems.push_front(tmp);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PyObject *tmp = this->dequeItems.front();
|
obj = this->dequeItems.back();
|
||||||
this->dequeItems.pop_front();
|
this->dequeItems.pop_back();
|
||||||
this->dequeItems.push_back(tmp);
|
|
||||||
}
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// front and back are not set, we care about item, this is a remove operation and we return the removed item or nullptr
|
||||||
|
for (auto it = this->dequeItems.begin(); it != this->dequeItems.end(); ++it)
|
||||||
|
if (vm->py_equals((*it), item))
|
||||||
|
{
|
||||||
|
PyObject *obj = *it; // keep a reference to the object for returning
|
||||||
|
this->dequeItems.erase(it);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
return nullptr; // not found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// @brief removes the first occurence of the given item
|
/// @brief inserts an item into the deque
|
||||||
/// @param vm is needed for the py_equals
|
/// @param front if true, insert at the front of the deque
|
||||||
/// @param item the item to remove
|
/// @param back if true, insert at the back of the deque
|
||||||
/// @return true if the item was removed successfully, false if the item was not found
|
/// @param index if front and back are not set, insert at the given index
|
||||||
bool PyDeque::remove(VM *vm, PyObject *item) // removes the first occurence of the given 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;
|
|
||||||
}
|
|
||||||
/// @brief inserts the given item at the given index, if index is negative, it will be treated as index + len(deque)
|
|
||||||
/// @param index index at which the item will be inserted
|
|
||||||
/// @param item the item to insert
|
/// @param item the item to insert
|
||||||
/// @return true if the item was inserted successfully, false if the index is out of range
|
/// @return true if the item was inserted successfully, false if the deque is bounded and is already at its maximum size
|
||||||
bool PyDeque::insert(int index, PyObject *item)
|
void PyDeque::insertObj(bool front, bool back, int index, PyObject *item) // assume index is not fixed using the vm->normalized_index
|
||||||
{
|
{
|
||||||
if (index < 0)
|
// error handling
|
||||||
index = this->dequeItems.size() + index; // adjust for the -ve indexing
|
if (front && back)
|
||||||
if (index < 0)
|
throw std::runtime_error("both front and back are set"); // this should never happen
|
||||||
this->dequeItems.push_front(item);
|
if (front || back)
|
||||||
else if (index >= this->dequeItems.size())
|
|
||||||
this->dequeItems.push_back(item);
|
|
||||||
else
|
|
||||||
this->dequeItems.insert((this->dequeItems.begin() + index), item);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/// @brief returns a string representation of the deque
|
|
||||||
/// @param vm is needed for the py_repr and String casting
|
|
||||||
/// @return std::stringstream the string representation of the deque
|
|
||||||
std::stringstream PyDeque::getRepr(VM *vm)
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "deque([";
|
|
||||||
for (auto it = this->dequeItems.begin(); it != this->dequeItems.end(); ++it)
|
|
||||||
{
|
{
|
||||||
ss << CAST(Str &, vm->py_repr(*it));
|
// front or back is set, we don't care about index
|
||||||
if (it != this->dequeItems.end() - 1)
|
if (this->bounded)
|
||||||
ss << ", ";
|
{
|
||||||
|
if (this->maxlen == 0)
|
||||||
|
return; // bounded and maxlen is 0, so we can't append
|
||||||
|
else if (this->dequeItems.size() == this->maxlen)
|
||||||
|
{
|
||||||
|
if (front)
|
||||||
|
this->dequeItems.pop_back(); // remove the last item
|
||||||
|
else if (back)
|
||||||
|
this->dequeItems.pop_front(); // remove the first item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (front)
|
||||||
|
this->dequeItems.emplace_front(item);
|
||||||
|
else if (back)
|
||||||
|
this->dequeItems.emplace_back(item);
|
||||||
}
|
}
|
||||||
if (this->bounded)
|
|
||||||
ss << "], maxlen=" << this->maxlen << ")";
|
|
||||||
else
|
else
|
||||||
ss << "])";
|
|
||||||
return ss;
|
|
||||||
}
|
|
||||||
/// @brief returns the index of the given object in the deque, can search in a range
|
|
||||||
/// @param vm is needed for the py_equals
|
|
||||||
/// @param obj the object to search for
|
|
||||||
/// @param startPos start position of the search
|
|
||||||
/// @param endPos end position of the search
|
|
||||||
/// @return int the index of the given object in the deque, -1 if not found
|
|
||||||
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();
|
|
||||||
if (!(startPos <= endPos))
|
|
||||||
return -1; // invalid range
|
|
||||||
int loopSize = std::min((int)this->dequeItems.size(), endPos);
|
|
||||||
for (int i = startPos; i < loopSize; i++)
|
|
||||||
if (vm->py_equals(this->dequeItems[i], obj))
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/// @brief reverses the deque
|
|
||||||
void PyDeque::reverse()
|
|
||||||
{
|
|
||||||
if (this->dequeItems.empty() || this->dequeItems.size() == 1)
|
|
||||||
return; // handle trivial cases
|
|
||||||
int sz = this->dequeItems.size();
|
|
||||||
for (int i = 0; i < sz / 2; i++)
|
|
||||||
{
|
{
|
||||||
PyObject *tmp = this->dequeItems[i];
|
// front and back are not set, we care about index
|
||||||
this->dequeItems[i] = this->dequeItems[sz - i - 1]; // swapping
|
if (index < 0)
|
||||||
this->dequeItems[sz - i - 1] = tmp;
|
index = this->dequeItems.size() + index; // try fixing for negative indices
|
||||||
|
if (index < 0) // still negative means insert at the beginning
|
||||||
|
this->dequeItems.push_front(item);
|
||||||
|
else if (index >= this->dequeItems.size()) // still out of range means insert at the end
|
||||||
|
this->dequeItems.push_back(item);
|
||||||
|
else
|
||||||
|
this->dequeItems.insert((this->dequeItems.begin() + index), item); // insert at the given index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// @brief appends the given item to the beginning of the deque
|
|
||||||
/// @param item the item to append
|
|
||||||
void PyDeque::appendLeft(PyObject *item)
|
|
||||||
{
|
|
||||||
if (this->bounded){ // handle bounded case
|
|
||||||
if(this->maxlen == 0) return; // bounded and maxlen is 0, so we can't append
|
|
||||||
else if (this->dequeItems.size() == this->maxlen)
|
|
||||||
this->dequeItems.pop_back(); // remove the last item
|
|
||||||
}
|
|
||||||
this->dequeItems.emplace_front(item);
|
|
||||||
}
|
|
||||||
/// @brief appends the given item to the end of the deque
|
|
||||||
/// @param item the item to append
|
|
||||||
void PyDeque::append(PyObject *item)
|
|
||||||
{
|
|
||||||
if(this->bounded){ // handle bounded case
|
|
||||||
if(this->maxlen == 0) return; // bounded and maxlen is 0, so we can't append
|
|
||||||
else if (this->dequeItems.size() == this->maxlen)
|
|
||||||
this->dequeItems.pop_front(); // remove the first item
|
|
||||||
}
|
|
||||||
this->dequeItems.emplace_back(item);
|
|
||||||
}
|
|
||||||
/// @brief pops the first item from the deque, i.e. beginning of the deque
|
|
||||||
/// @return PyObject* the popped item
|
|
||||||
PyObject *PyDeque::popLeft()
|
|
||||||
{
|
|
||||||
if (this->dequeItems.empty())
|
|
||||||
throw std::runtime_error("pop from an empty deque");//shouldn't happen
|
|
||||||
|
|
||||||
PyObject *obj = this->dequeItems.front();
|
|
||||||
this->dequeItems.pop_front();
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
/// @brief pops the last item from the deque, i.e. end of the deque
|
|
||||||
/// @return PyObject* the popped item
|
|
||||||
PyObject *PyDeque::pop()
|
|
||||||
{
|
|
||||||
if (this->dequeItems.empty())
|
|
||||||
throw std::runtime_error("pop from an empty deque"); //shouldn't happen
|
|
||||||
|
|
||||||
PyObject *obj = this->dequeItems.back();
|
|
||||||
this->dequeItems.pop_back();
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
/// @brief counts the number of occurences of the given object in the deque
|
|
||||||
/// @param vm is needed for the py_equals
|
|
||||||
/// @param obj the object to search for
|
|
||||||
/// @return int the number of occurences of the given object in the deque
|
|
||||||
int PyDeque::count(VM *vm, PyObject *obj)
|
|
||||||
{
|
|
||||||
int cnt = 0;
|
|
||||||
for (auto it = this->dequeItems.begin(); it != this->dequeItems.end(); ++it)
|
|
||||||
if (vm->py_equals((*it), obj))
|
|
||||||
cnt++;
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
/// @brief clears the deque
|
|
||||||
void PyDeque::clear()
|
|
||||||
{
|
|
||||||
this->dequeItems.clear();
|
|
||||||
}
|
|
||||||
/// @brief fixes the given index, if index is negative, it will be treated as index + len(deque)
|
|
||||||
/// @param index the index to fix
|
|
||||||
/// @return int the fixed index, -1 if the index is out of range
|
|
||||||
int PyDeque::fixIndex(int index)
|
|
||||||
{
|
|
||||||
if (index < 0)
|
|
||||||
index = this->dequeItems.size() + index;
|
|
||||||
if (index < 0 || index >= this->dequeItems.size())
|
|
||||||
return -1;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
/// @brief marks the deque items for garbage collection
|
/// @brief marks the deque items for garbage collection
|
||||||
void PyDeque::_gc_mark() const
|
void PyDeque::_gc_mark() const
|
||||||
{
|
{
|
||||||
for (PyObject *obj : this->dequeItems)
|
for (PyObject *obj : this->dequeItems)
|
||||||
{
|
|
||||||
PK_OBJ_MARK(obj);
|
PK_OBJ_MARK(obj);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/// @brief registers the PyDeque class
|
/// @brief registers the PyDeque class
|
||||||
/// @param vm is needed for the new_module and register_class
|
/// @param vm is needed for the new_module and register_class
|
||||||
void add_module_collections(VM *vm)
|
void add_module_collections(VM *vm)
|
||||||
{
|
{
|
||||||
PyObject* mod = vm->new_module("collections");
|
PyObject *mod = vm->new_module("collections");
|
||||||
PyDeque::register_class(vm, mod);
|
PyDeque::register_class(vm, mod);
|
||||||
CodeObject_ code = vm->compile(kPythonLibs["collections"], "collections.py", EXEC_MODE);
|
CodeObject_ code = vm->compile(kPythonLibs["collections"], "collections.py", EXEC_MODE);
|
||||||
vm->_exec(code, mod);
|
vm->_exec(code, mod);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user