summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2020-12-01 04:42:54 (GMT)
committerGitHub <noreply@github.com>2020-12-01 04:42:54 (GMT)
commitcc061d0e6fb2569efa91531686f75b89e94ec865 (patch)
treec4c2a24657c2437ff04b6f32677cc70ec8756478 /Modules
parent427613f005f0f412d12f0d775d2b609bae0ae1ad (diff)
downloadcpython-cc061d0e6fb2569efa91531686f75b89e94ec865.zip
cpython-cc061d0e6fb2569efa91531686f75b89e94ec865.tar.gz
cpython-cc061d0e6fb2569efa91531686f75b89e94ec865.tar.bz2
bpo-38200: Add itertools.pairwise() (GH-23549)
Diffstat (limited to 'Modules')
-rw-r--r--Modules/clinic/itertoolsmodule.c.h33
-rw-r--r--Modules/itertoolsmodule.c137
2 files changed, 168 insertions, 2 deletions
diff --git a/Modules/clinic/itertoolsmodule.c.h b/Modules/clinic/itertoolsmodule.c.h
index c1192bb..82729ee 100644
--- a/Modules/clinic/itertoolsmodule.c.h
+++ b/Modules/clinic/itertoolsmodule.c.h
@@ -2,6 +2,37 @@
preserve
[clinic start generated code]*/
+PyDoc_STRVAR(pairwise_new__doc__,
+"pairwise(iterable, /)\n"
+"--\n"
+"\n"
+"Return an iterator of overlapping pairs taken from the input iterator.\n"
+"\n"
+" s -> (s0,s1), (s1,s2), (s2, s3), ...");
+
+static PyObject *
+pairwise_new_impl(PyTypeObject *type, PyObject *iterable);
+
+static PyObject *
+pairwise_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+ PyObject *return_value = NULL;
+ PyObject *iterable;
+
+ if ((type == &pairwise_type) &&
+ !_PyArg_NoKeywords("pairwise", kwargs)) {
+ goto exit;
+ }
+ if (!_PyArg_CheckPositional("pairwise", PyTuple_GET_SIZE(args), 1, 1)) {
+ goto exit;
+ }
+ iterable = PyTuple_GET_ITEM(args, 0);
+ return_value = pairwise_new_impl(type, iterable);
+
+exit:
+ return return_value;
+}
+
PyDoc_STRVAR(itertools_groupby__doc__,
"groupby(iterable, key=None)\n"
"--\n"
@@ -627,4 +658,4 @@ skip_optional_pos:
exit:
return return_value;
}
-/*[clinic end generated code: output=d7f58dc477814b45 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=889c4afc3b13574f input=a9049054013a1b77]*/
diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c
index ce8b434..7144856 100644
--- a/Modules/itertoolsmodule.c
+++ b/Modules/itertoolsmodule.c
@@ -1,4 +1,5 @@
+
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "pycore_long.h" // _PyLong_GetZero()
@@ -27,8 +28,9 @@ class itertools.accumulate "accumulateobject *" "&accumulate_type"
class itertools.compress "compressobject *" "&compress_type"
class itertools.filterfalse "filterfalseobject *" "&filterfalse_type"
class itertools.count "countobject *" "&count_type"
+class itertools.pairwise "pairwiseobject *" "&pairwise_type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ea05c93c6d94726a]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6498ed21fbe1bf94]*/
static PyTypeObject groupby_type;
static PyTypeObject _grouper_type;
@@ -45,9 +47,140 @@ static PyTypeObject accumulate_type;
static PyTypeObject compress_type;
static PyTypeObject filterfalse_type;
static PyTypeObject count_type;
+static PyTypeObject pairwise_type;
#include "clinic/itertoolsmodule.c.h"
+/* pairwise object ***********************************************************/
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *it;
+ PyObject *old;
+} pairwiseobject;
+
+/*[clinic input]
+@classmethod
+itertools.pairwise.__new__ as pairwise_new
+ iterable: object
+ /
+Return an iterator of overlapping pairs taken from the input iterator.
+
+ s -> (s0,s1), (s1,s2), (s2, s3), ...
+
+[clinic start generated code]*/
+
+static PyObject *
+pairwise_new_impl(PyTypeObject *type, PyObject *iterable)
+/*[clinic end generated code: output=9f0267062d384456 input=6e7c3cddb431a8d6]*/
+{
+ PyObject *it;
+ pairwiseobject *po;
+
+ it = PyObject_GetIter(iterable);
+ if (it == NULL) {
+ return NULL;
+ }
+ po = (pairwiseobject *)type->tp_alloc(type, 0);
+ if (po == NULL) {
+ Py_DECREF(it);
+ return NULL;
+ }
+ po->it = it;
+ po->old = NULL;
+ return (PyObject *)po;
+}
+
+static void
+pairwise_dealloc(pairwiseobject *po)
+{
+ PyObject_GC_UnTrack(po);
+ Py_XDECREF(po->it);
+ Py_XDECREF(po->old);
+ Py_TYPE(po)->tp_free(po);
+}
+
+static int
+pairwise_traverse(pairwiseobject *po, visitproc visit, void *arg)
+{
+ Py_VISIT(po->it);
+ Py_VISIT(po->old);
+ return 0;
+}
+
+static PyObject *
+pairwise_next(pairwiseobject *po)
+{
+ PyObject *it = po->it;
+ PyObject *old = po->old;
+ PyObject *new, *result;
+
+ if (it == NULL) {
+ return NULL;
+ }
+ if (old == NULL) {
+ po->old = old = (*Py_TYPE(it)->tp_iternext)(it);
+ if (old == NULL) {
+ Py_CLEAR(po->it);
+ return NULL;
+ }
+ }
+ new = (*Py_TYPE(it)->tp_iternext)(it);
+ if (new == NULL) {
+ Py_CLEAR(po->it);
+ Py_CLEAR(po->old);
+ return NULL;
+ }
+ /* Future optimization: Reuse the result tuple as we do in enumerate() */
+ result = PyTuple_Pack(2, old, new);
+ Py_SETREF(po->old, new);
+ return result;
+}
+
+static PyTypeObject pairwise_type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "itertools.pairwise", /* tp_name */
+ sizeof(pairwiseobject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)pairwise_dealloc, /* tp_dealloc */
+ 0, /* tp_vectorcall_offset */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_as_async */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_BASETYPE, /* tp_flags */
+ pairwise_new__doc__, /* tp_doc */
+ (traverseproc)pairwise_traverse, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ (iternextfunc)pairwise_next, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ PyType_GenericAlloc, /* tp_alloc */
+ pairwise_new, /* tp_new */
+ PyObject_GC_Del, /* tp_free */
+};
+
/* groupby object ************************************************************/
@@ -4666,6 +4799,7 @@ groupby(iterable[, keyfunc]) --> sub-iterators grouped by value of keyfunc(v)\n\
filterfalse(pred, seq) --> elements of seq where pred(elem) is False\n\
islice(seq, [start,] stop [, step]) --> elements from\n\
seq[start:stop:step]\n\
+pairwise(s) --> (s[0],s[1]), (s[1],s[2]), (s[2], s[3]), ...\n\
starmap(fun, seq) --> fun(*seq[0]), fun(*seq[1]), ...\n\
tee(it, n=2) --> (it1, it2 , ... itn) splits one iterator into n\n\
takewhile(pred, seq) --> seq[0], seq[1], until pred fails\n\
@@ -4695,6 +4829,7 @@ itertoolsmodule_exec(PyObject *m)
&filterfalse_type,
&count_type,
&ziplongest_type,
+ &pairwise_type,
&permutations_type,
&product_type,
&repeat_type,