changeset 559:bb160a1e67d7

A simple helper include file with some conveniente functions. Also some "backports" from later Python versions.
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 06 Jan 2022 18:50:09 +0100
parents 7a3c311991d7
children 81238ea2dbe3
files MANIFEST.in configmix/_py_helper.h configmix/_speedups.c
diffstat 3 files changed, 134 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- a/MANIFEST.in	Wed Jan 05 16:02:07 2022 +0100
+++ b/MANIFEST.in	Thu Jan 06 18:50:09 2022 +0100
@@ -1,5 +1,5 @@
 include .hg* *.txt requirement*
-include configmix/*.c
+include configmix/*.c configmix/*.h
 graft docs
 graft tests
 prune docs/_build
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/configmix/_py_helper.h	Thu Jan 06 18:50:09 2022 +0100
@@ -0,0 +1,70 @@
+/* -*- coding: utf-8 -*- */
+/*
+ * Some Python helper for C.
+ *
+ * Also contains some interesting backports from later Python versions.
+ *
+ * :Copyright: (c) 2021, Franz Glasner. All rights reserved.
+ * :License:   BSD-3-Clause. See LICENSE.txt for details.
+ */
+
+#if !defined(_PY_HELPER_H_d9df407295df4884a88e56699f6c6d8d)
+#define _PY_HELPER_H_d9df407295df4884a88e56699f6c6d8d
+
+#if PY_VERSION_HEX < 0x030A0000
+
+static inline
+PyObject *
+Py_NewRef(PyObject *obj)
+{
+    Py_INCREF(obj);
+    return obj;
+}
+
+
+static inline
+PyObject *
+Py_XNewRef(PyObject *obj)
+{
+    Py_XINCREF(obj);
+    return obj;
+}
+
+#endif /* PY_VERSION_HEX < 0x030A0000 */
+
+
+static inline
+void
+py_clear_ref(PyObject **obj)
+{
+    PyObject *tmp;
+
+    if ((tmp = *obj) != NULL) {
+        *obj = NULL;
+        Py_DECREF(tmp);
+    }
+}
+
+
+/*
+ * NOTE: This implementation is valid for CPython only!
+ */
+static inline
+int
+py_object_is(PyObject *obj1, PyObject *obj2)
+{
+    return (obj1 == obj2);
+}
+
+
+/*
+ * NOTE: This implementation is valid for CPython only!
+ */
+static inline
+int
+py_object_isnot(PyObject *obj1, PyObject *obj2)
+{
+    return (obj1 != obj2);
+}
+
+#endif
--- a/configmix/_speedups.c	Wed Jan 05 16:02:07 2022 +0100
+++ b/configmix/_speedups.c	Thu Jan 06 18:50:09 2022 +0100
@@ -9,6 +9,8 @@
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
 
+#include "_py_helper.h"
+
 
 const char _id[] = "@(#)configmix._speedups $Header$";
 static const char release[] = "|VCSRevision|";
@@ -277,16 +279,14 @@
         }
     }
     if (s_len == 0) {
-        Py_INCREF(s);
-        return s;
+        return Py_NewRef(s);
     }
     find = PyUnicode_FindChar(s, '%', 0, s_len, 1);
     if (find == -2) {
         return NULL;
     }
     if (find == -1) {
-        Py_INCREF(s);
-        return s;
+        return Py_NewRef(s);
     }
 
     if (sstate == NULL) {
@@ -317,8 +317,7 @@
      * The first item may be also the empty string if `s' starts with
      * a quoted character.
      */
-    Py_INCREF(o);   /* because PyTuple_SetItem steals -- and o is borrowed */
-    PyTuple_SetItem(res_parts, 0, o);
+    PyTuple_SetItem(res_parts, 0, Py_NewRef(o));
 
     for (i=1; i<parts_len; i++) {
         pb = PyList_GetItem(parts, i);   /* borrowed */
@@ -422,8 +421,7 @@
         return NULL;
     }
     if (s_len == 0) {
-        Py_INCREF(s);
-        return s;
+        return Py_NewRef(s);
     }
     need_quoting = 0;
     for (i=0; i<s_len; i++) {
@@ -449,8 +447,7 @@
         }
     }
     if (!need_quoting) {
-        Py_INCREF(s);
-        return s;
+        return Py_NewRef(s);
     }
     sstate = PyModule_GetState(self);
     if (sstate == NULL) {
@@ -551,8 +548,7 @@
         if (res == NULL) {
             goto error;
         }
-        Py_INCREF(varname);                /* because PyTuple_SetItem steals */
-        PyTuple_SetItem(res, 0, varname);  /* steals */
+        PyTuple_SetItem(res, 0, Py_NewRef(varname));  /* steals */
         filters = PyList_New(0);
         if (filters == NULL) {
             goto error;
@@ -574,10 +570,10 @@
         goto error;
     }
     Py_DECREF(filters);
-    filters = tmp;
+    filters = tmp; tmp = NULL;
 
     if (PyObject_Not(filters)) {
-        Py_DECREF(filters); filters = NULL;
+        py_clear_ref(&filters);
 
         res = PyTuple_New(2);
         if (res == NULL) {
@@ -606,7 +602,7 @@
         goto error;
     }
     Py_DECREF(filters);
-    filters = tmp;
+    filters = tmp; tmp = NULL;
 
     res = PyTuple_New(2);
     if (res == NULL) {
@@ -655,10 +651,8 @@
         if (res == NULL) {
             return NULL;
         }
-        Py_INCREF(Py_None);
-        PyTuple_SetItem(res, 0, Py_None);  /* steals */
-        Py_INCREF(varname);
-        PyTuple_SetItem(res, 1, varname);  /* steals */
+        PyTuple_SetItem(res, 0, Py_NewRef(Py_None));  /* steals */
+        PyTuple_SetItem(res, 1, Py_NewRef(varname));  /* steals */
         return res;
     }
 
@@ -728,8 +722,7 @@
     }
     if (s_len < 4) {
         PyErr_Clear();
-        Py_INCREF(s);
-        return s;
+        return Py_NewRef(s);
     }
     sstate = PyModule_GetState(self);
     if (sstate == NULL) {
@@ -740,8 +733,7 @@
     idx = PyUnicode_Find(s, sstate->STARTTOK, 0, s_len, 1);
     if (idx < 0) {
         PyErr_Clear();
-        Py_INCREF(s);
-        return s;
+        return Py_NewRef(s);
     }
 
     res = PyDict_GetItem(cache, s);      /* borrowed */
@@ -753,8 +745,7 @@
                 s);
         }
         else {
-            Py_INCREF(res);
-            return res;
+            return Py_NewRef(res);
         }
     }
 
@@ -780,8 +771,8 @@
      * an interpolation token.
      */
     first_part_is_empty = PyObject_Not(tmp);
-    Py_INCREF(tmp);  /* because PyList_SetItem steals -- and tmp is borrowed */
-    PyList_SetItem(res_parts, 0, tmp);    /* steals -- cannot fail here */
+    /* steals -- cannot fail here -- NOTE: tmp is currently borrowed */
+    PyList_SetItem(res_parts, 0, Py_NewRef(tmp));
     tmp = NULL;
 
     for (i=1; i<parts_len; i++) {
@@ -825,19 +816,16 @@
         }
         if (PyTuple_Size(tmp) != 2) {
             PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected");
-            Py_DECREF(tmp);
+            py_clear_ref(&tmp);
             goto error;
         }
         /* Unpack the result tuple */
         tmp2 = PyTuple_GetItem(tmp, 0);   /* borrowed -- cannot fail */
         Py_DECREF(varname);
-        Py_INCREF(tmp2);
-        varname = tmp2;
-        tmp2 = NULL;
-        filters = PyTuple_GetItem(tmp, 1);   /* borrowed -- cannot fail */
-        Py_INCREF(filters);
-        Py_DECREF(tmp);
-        tmp = NULL;
+        varname = Py_NewRef(tmp2); tmp2 = NULL;
+        /* borrowed -- cannot fail -- want own */
+        filters = Py_NewRef(PyTuple_GetItem(tmp, 1));
+        py_clear_ref(&tmp);
 
         tmp = PyObject_CallMethod(
             config, "_getvar_s_with_cache_info", "O", varname);
@@ -847,14 +835,12 @@
                 cacheable = 1;
                 if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) {
                     PyErr_Clear();
-                    Py_INCREF(Py_None);
-                    varvalue = Py_None;
+                    varvalue = Py_NewRef(Py_None);
                 }
                 else {
                     if (PySequence_Contains(filters, sstate->EMPTY_FILTER) == 1) {
                         PyErr_Clear();
-                        Py_INCREF(sstate->EMPTY_STR);
-                        varvalue = sstate->EMPTY_STR;
+                        varvalue = Py_NewRef(sstate->EMPTY_STR);
                     }
                     else {
                         PyErr_Fetch(&err_type, &err_value, &err_tb);
@@ -872,33 +858,31 @@
         }
         else {
             if (PyTuple_Size(tmp) != 2) {
-                Py_DECREF(tmp); tmp = NULL;
+                py_clear_ref(&tmp);
                 PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected");
                 goto error;
             }
             /* unpack the result */
-            varvalue = PyTuple_GetItem(tmp, 0); /* borrowed -- but want own */
-            Py_INCREF(varvalue);
+            /* borrowed -- but want own */
+            varvalue = Py_NewRef(PyTuple_GetItem(tmp, 0));
             cacheable = PyObject_IsTrue(PyTuple_GetItem(tmp, 1));
-            Py_DECREF(tmp); tmp = NULL;
+            py_clear_ref(&tmp);
         }
 
         if (!cacheable) {
             use_cache = 0;
         }
 
-        Py_DECREF(varname); varname = NULL;
+        py_clear_ref(&varname);
 
         tmp = PyObject_CallMethod(
             config, "_apply_filters", "OO", filters, varvalue);
         if (tmp == NULL) {
             goto error;
         }
-        Py_DECREF(varvalue);
-        varvalue = tmp;
-        tmp = NULL;
+        py_clear_ref(&varvalue);
 
-        Py_DECREF(filters); filters = NULL;
+        py_clear_ref(&filters);
 
         /*
          * Dont apply and type conversions to the variable value if
@@ -908,28 +892,28 @@
             res = varvalue; varvalue = NULL;
             goto success;     /* break out early */
         }
-        if (varvalue != Py_None) {
+        if (py_object_isnot(varvalue, Py_None)) {
             tmp = PyObject_Str(varvalue);
             if (tmp == NULL) {
                 goto error;
             }
             if (PyList_Append(res_parts, tmp) < 0) {
-                Py_DECREF(tmp); tmp = NULL;
+                py_clear_ref(&tmp);
                 goto error;
             }
-            Py_DECREF(tmp);
+            py_clear_ref(&tmp);
         }
-        Py_DECREF(varvalue); varvalue = NULL;
+        py_clear_ref(&varvalue);
         /* append the rest of the string */
         tmp = PyUnicode_Substring(pb, idx+2, pb_len);
         if (tmp == NULL) {
             goto error;
         }
         if (PyList_Append(res_parts, tmp) < 0) {
-            Py_DECREF(tmp); tmp = NULL;
+            py_clear_ref(&tmp);
             goto error;
         }
-        Py_DECREF(tmp); tmp = NULL;
+        py_clear_ref(&tmp);
     }
 
     res = PyUnicode_Join(sstate->EMPTY_STR, res_parts);
@@ -950,10 +934,10 @@
 error:
     Py_XDECREF(varname);
     Py_XDECREF(varvalue);
+    Py_XDECREF(filters);
     Py_XDECREF(parts);
     Py_XDECREF(res_parts);
     Py_XDECREF(res);
-    Py_XDECREF(filters);
     return NULL;
 }
 
@@ -988,8 +972,7 @@
         return NULL;
     }
     if (s_len < 4) {
-        Py_INCREF(s);
-        return s;
+        return Py_NewRef(s);
     }
 
     sstate = PyModule_GetState(self);
@@ -1003,8 +986,7 @@
         return NULL;
     }
     if (start == -1) {
-        Py_INCREF(s);
-        return s;
+        return Py_NewRef(s);
     }
 
     result = PyDict_GetItem(cache, s);    /* borrowed */
@@ -1016,8 +998,7 @@
                 s);
         }
         else {
-            Py_INCREF(result);   /* need ownership */
-            return result;
+            return Py_NewRef(result);
         }
     }
 
@@ -1036,10 +1017,10 @@
                 goto error;
             }
             if (PyList_Append(result, tmp) < 0) {
-                Py_DECREF(tmp);
+                py_clear_ref(&tmp);
                 goto error;
             }
-            Py_DECREF(tmp); tmp = NULL;
+            py_clear_ref(&tmp);            
         }
         end = PyUnicode_Find(s, sstate->ENDTOK, start+2, s_len, 1);
         if (end == -2) {
@@ -1061,17 +1042,16 @@
         }
         if (PyTuple_Size(tmp) != 2) {
             PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected");
-            Py_DECREF(tmp);
+            py_clear_ref(&tmp);
             goto error;
         }
         /* Unpack the result tuple */
         tmp2 = PyTuple_GetItem(tmp, 0);   /* borrowed -- cannot fail */
         Py_DECREF(varname);
-        Py_INCREF(tmp2);
-        varname = tmp2; tmp2 = NULL;
-        filters = PyTuple_GetItem(tmp, 1);   /* borrowed -- cannot fail */
-        Py_INCREF(filters);
-        Py_DECREF(tmp); tmp = NULL;
+        varname = Py_NewRef(tmp2); tmp2 = NULL;
+        /* borrowed -- cannot fail -- need ownership */        
+        filters = Py_NewRef(PyTuple_GetItem(tmp, 1));
+        py_clear_ref(&tmp);
 
         tmp = PyObject_CallMethod(
             config, "_getvar_s_with_cache_info", "O", varname);
@@ -1080,14 +1060,12 @@
                 cacheable = 1;
                 if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) {
                     PyErr_Clear();
-                    Py_INCREF(Py_None);
-                    varvalue = Py_None;
+                    varvalue = Py_NewRef(Py_None);
                 }
                 else {
                     if (PySequence_Contains(filters, sstate->EMPTY_FILTER) == 1) {
                         PyErr_Clear();
-                        Py_INCREF(sstate->EMPTY_STR);
-                        varvalue = sstate->EMPTY_STR;
+                        varvalue = Py_NewRef(sstate->EMPTY_STR);
                     }
                     else {
                         PyErr_Fetch(&err_type, &err_value, &err_tb);
@@ -1105,22 +1083,22 @@
         }
         else {
             if (PyTuple_Size(tmp) != 2) {
-                Py_DECREF(tmp);
+                py_clear_ref(&tmp);
                 PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected");
                 goto error;
             }
             /* unpack the result */
-            varvalue = PyTuple_GetItem(tmp, 0); /* borrowed -- but want own */
-            Py_INCREF(varvalue);
+            /* borrowed -- but want own */            
+            varvalue = Py_NewRef(PyTuple_GetItem(tmp, 0));
             cacheable = PyObject_IsTrue(PyTuple_GetItem(tmp, 1));
-            Py_DECREF(tmp); tmp = NULL;
+            py_clear_ref(&tmp);
         }
 
         if (!cacheable) {
             use_cache = 0;
         }
 
-        Py_DECREF(varname); varname = NULL;
+        py_clear_ref(&varname);
 
         tmp = PyObject_CallMethod(
             config, "_apply_filters", "OO", filters, varvalue);
@@ -1130,7 +1108,7 @@
         Py_DECREF(varvalue);
         varvalue = tmp; tmp = NULL;
 
-        Py_DECREF(filters); filters = NULL;
+        py_clear_ref(&filters);
 
         rest = end + 2;  /* 2 == len(ENDTOK) */
 
@@ -1145,16 +1123,16 @@
         }
 
         /* Handle None like the empty string */
-        if (varvalue != Py_None) {
+        if (py_object_isnot(varvalue, Py_None)) {
             tmp = PyObject_Str(varvalue);
             if (tmp == NULL) {
                 goto error;
             }
             if (PyList_Append(result, tmp) < 0) {
-                Py_DECREF(tmp);
+                py_clear_ref(&tmp);
                 goto error;
             }
-            Py_DECREF(tmp); tmp = NULL;
+            py_clear_ref(&tmp);
         }
 
         /* don't re-evaluate because `self.getvar_s()` expands already */
@@ -1170,10 +1148,10 @@
             goto error;
         }
         if (PyList_Append(result, tmp) < 0) {
-            Py_DECREF(tmp);
+            py_clear_ref(&tmp);
             goto error;
         }
-        Py_DECREF(tmp); tmp = NULL;
+        py_clear_ref(&tmp);        
     }
 
     tmp = PyUnicode_Join(sstate->EMPTY_STR, result);
@@ -1215,8 +1193,7 @@
         PyErr_SetString(PyExc_RuntimeError, "_MISSING already set");
         return NULL;
     }
-    Py_INCREF(missing);
-    sstate->MISSING = missing;
+    sstate->MISSING = Py_NewRef(missing);
     Py_RETURN_NONE;
 }