aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Objects/tupleobject.c
diff options
context:
space:
mode:
authorDennis Sweeney <36520290+sweeneyde@users.noreply.github.com>2022-01-07 22:47:58 -0500
committerGitHub <noreply@github.com>2022-01-07 21:47:58 -0600
commitad1d5908ada171eff768291371a80022bfad4f04 (patch)
tree040c1e3391995791c8114ea62c911756ad824c68 /Objects/tupleobject.c
parent6fa8b2ceee38187b0ae96aee12fe4f0a5c8a2ce7 (diff)
downloadcpython-ad1d5908ada171eff768291371a80022bfad4f04.tar.gz
cpython-ad1d5908ada171eff768291371a80022bfad4f04.zip
bpo-46235: Do all ref-counting at once during list/tuple multiplication (GH-30346)
When multiplying lists and tuples by `n`, increment each element's refcount, by `n`, just once. Saves `n-1` increments per element, and allows for a leaner & faster copying loop. Code by sweeneyde (Dennis Sweeney).
Diffstat (limited to 'Objects/tupleobject.c')
-rw-r--r--Objects/tupleobject.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index cb34c5eb15e..2051c1812ef 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -589,10 +589,8 @@ tupleconcat(PyTupleObject *a, PyObject *bb)
static PyObject *
tuplerepeat(PyTupleObject *a, Py_ssize_t n)
{
- Py_ssize_t i, j;
Py_ssize_t size;
PyTupleObject *np;
- PyObject **p, **items;
if (Py_SIZE(a) == 0 || n == 1) {
if (PyTuple_CheckExact(a)) {
/* Since tuples are immutable, we can return a shared
@@ -610,13 +608,32 @@ tuplerepeat(PyTupleObject *a, Py_ssize_t n)
np = tuple_alloc(size);
if (np == NULL)
return NULL;
- p = np->ob_item;
- items = a->ob_item;
- for (i = 0; i < n; i++) {
- for (j = 0; j < Py_SIZE(a); j++) {
- *p = items[j];
- Py_INCREF(*p);
- p++;
+ PyObject **dest = np->ob_item;
+ PyObject **dest_end = dest + size;
+ if (Py_SIZE(a) == 1) {
+ PyObject *elem = a->ob_item[0];
+ Py_SET_REFCNT(elem, Py_REFCNT(elem) + n);
+#ifdef Py_REF_DEBUG
+ _Py_RefTotal += n;
+#endif
+ while (dest < dest_end) {
+ *dest++ = elem;
+ }
+ }
+ else {
+ PyObject **src = a->ob_item;
+ PyObject **src_end = src + Py_SIZE(a);
+ while (src < src_end) {
+ Py_SET_REFCNT(*src, Py_REFCNT(*src) + n);
+#ifdef Py_REF_DEBUG
+ _Py_RefTotal += n;
+#endif
+ *dest++ = *src++;
+ }
+ // Now src chases after dest in the same buffer
+ src = np->ob_item;
+ while (dest < dest_end) {
+ *dest++ = *src++;
}
}
_PyObject_GC_TRACK(np);