summaryrefslogtreecommitdiff
path: root/Modules/_collectionsmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_collectionsmodule.c')
-rw-r--r--Modules/_collectionsmodule.c130
1 files changed, 128 insertions, 2 deletions
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
index 6aadec13e8..ea5f7795dc 100644
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -276,6 +276,23 @@ deque_appendleft(dequeobject *deque, PyObject *item)
PyDoc_STRVAR(appendleft_doc, "Add an element to the left side of the deque.");
+
+/* Run an iterator to exhaustion. Shortcut for
+ the extend/extendleft methods when maxlen == 0. */
+static PyObject*
+consume_iterator(PyObject *it)
+{
+ PyObject *item;
+
+ while ((item = PyIter_Next(it)) != NULL) {
+ Py_DECREF(item);
+ }
+ Py_DECREF(it);
+ if (PyErr_Occurred())
+ return NULL;
+ Py_RETURN_NONE;
+}
+
static PyObject *
deque_extend(dequeobject *deque, PyObject *iterable)
{
@@ -296,6 +313,9 @@ deque_extend(dequeobject *deque, PyObject *iterable)
if (it == NULL)
return NULL;
+ if (deque->maxlen == 0)
+ return consume_iterator(it);
+
while ((item = PyIter_Next(it)) != NULL) {
deque->state++;
if (deque->rightindex == BLOCKLEN-1) {
@@ -345,6 +365,9 @@ deque_extendleft(dequeobject *deque, PyObject *iterable)
if (it == NULL)
return NULL;
+ if (deque->maxlen == 0)
+ return consume_iterator(it);
+
while ((item = PyIter_Next(it)) != NULL) {
deque->state++;
if (deque->leftindex == 0) {
@@ -439,6 +462,91 @@ deque_rotate(dequeobject *deque, PyObject *args)
PyDoc_STRVAR(rotate_doc,
"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left.");
+static PyObject *
+deque_reverse(dequeobject *deque, PyObject *unused)
+{
+ block *leftblock = deque->leftblock;
+ block *rightblock = deque->rightblock;
+ Py_ssize_t leftindex = deque->leftindex;
+ Py_ssize_t rightindex = deque->rightindex;
+ Py_ssize_t n = (deque->len)/2;
+ Py_ssize_t i;
+ PyObject *tmp;
+
+ for (i=0 ; i<n ; i++) {
+ /* Validate that pointers haven't met in the middle */
+ assert(leftblock != rightblock || leftindex < rightindex);
+
+ /* Swap */
+ tmp = leftblock->data[leftindex];
+ leftblock->data[leftindex] = rightblock->data[rightindex];
+ rightblock->data[rightindex] = tmp;
+
+ /* Advance left block/index pair */
+ leftindex++;
+ if (leftindex == BLOCKLEN) {
+ if (leftblock->rightlink == NULL)
+ break;
+ leftblock = leftblock->rightlink;
+ leftindex = 0;
+ }
+
+ /* Step backwards with the right block/index pair */
+ rightindex--;
+ if (rightindex == -1) {
+ if (rightblock->leftlink == NULL)
+ break;
+ rightblock = rightblock->leftlink;
+ rightindex = BLOCKLEN - 1;
+ }
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(reverse_doc,
+"D.reverse() -- reverse *IN PLACE*");
+
+static PyObject *
+deque_count(dequeobject *deque, PyObject *v)
+{
+ block *leftblock = deque->leftblock;
+ Py_ssize_t leftindex = deque->leftindex;
+ Py_ssize_t n = deque->len;
+ Py_ssize_t i;
+ Py_ssize_t count = 0;
+ PyObject *item;
+ long start_state = deque->state;
+ int cmp;
+
+ for (i=0 ; i<n ; i++) {
+ item = leftblock->data[leftindex];
+ cmp = PyObject_RichCompareBool(item, v, Py_EQ);
+ if (cmp > 0)
+ count++;
+ else if (cmp < 0)
+ return NULL;
+
+ if (start_state != deque->state) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "deque mutated during iteration");
+ return NULL;
+ }
+
+ /* Advance left block/index pair */
+ leftindex++;
+ if (leftindex == BLOCKLEN) {
+ if (leftblock->rightlink == NULL) /* can occur when i==n-1 */
+ break;
+ leftblock = leftblock->rightlink;
+ leftindex = 0;
+ }
+ }
+ return PyInt_FromSsize_t(count);
+}
+
+PyDoc_STRVAR(count_doc,
+"D.count(value) -> integer -- return number of occurrences of value");
+
static Py_ssize_t
deque_len(dequeobject *deque)
{
@@ -882,6 +990,20 @@ deque_init(dequeobject *deque, PyObject *args, PyObject *kwdargs)
return 0;
}
+static PyObject *
+deque_get_maxlen(dequeobject *deque)
+{
+ if (deque->maxlen == -1)
+ Py_RETURN_NONE;
+ return PyInt_FromSsize_t(deque->maxlen);
+}
+
+static PyGetSetDef deque_getset[] = {
+ {"maxlen", (getter)deque_get_maxlen, (setter)NULL,
+ "maximum size of a deque or None if unbounded"},
+ {0}
+};
+
static PySequenceMethods deque_as_sequence = {
(lenfunc)deque_len, /* sq_length */
0, /* sq_concat */
@@ -912,6 +1034,8 @@ static PyMethodDef deque_methods[] = {
METH_NOARGS, clear_doc},
{"__copy__", (PyCFunction)deque_copy,
METH_NOARGS, copy_doc},
+ {"count", (PyCFunction)deque_count,
+ METH_O, count_doc},
{"extend", (PyCFunction)deque_extend,
METH_O, extend_doc},
{"extendleft", (PyCFunction)deque_extendleft,
@@ -926,6 +1050,8 @@ static PyMethodDef deque_methods[] = {
METH_O, remove_doc},
{"__reversed__", (PyCFunction)deque_reviter,
METH_NOARGS, reversed_doc},
+ {"reverse", (PyCFunction)deque_reverse,
+ METH_NOARGS, reverse_doc},
{"rotate", (PyCFunction)deque_rotate,
METH_VARARGS, rotate_doc},
{NULL, NULL} /* sentinel */
@@ -934,7 +1060,7 @@ static PyMethodDef deque_methods[] = {
PyDoc_STRVAR(deque_doc,
"deque(iterable[, maxlen]) --> deque object\n\
\n\
-Build an ordered collection accessible from endpoints only.");
+Build an ordered collection with optimized access from its endpoints.");
static PyTypeObject deque_type = {
PyVarObject_HEAD_INIT(NULL, 0)
@@ -968,7 +1094,7 @@ static PyTypeObject deque_type = {
0, /* tp_iternext */
deque_methods, /* tp_methods */
0, /* tp_members */
- 0, /* tp_getset */
+ deque_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */