]> granicus.if.org Git - python/commitdiff
Add _Py_VaBuildStack() function
authorVictor Stinner <victor.stinner@gmail.com>
Thu, 8 Dec 2016 23:29:49 +0000 (00:29 +0100)
committerVictor Stinner <victor.stinner@gmail.com>
Thu, 8 Dec 2016 23:29:49 +0000 (00:29 +0100)
Issue #28915: Similar to Py_VaBuildValue(), but work on a C array of PyObject*,
instead of creating a tuple.

Include/modsupport.h
Python/modsupport.c

index 39be12864a3b2e3954838b586197039af327cf9a..46f548228e807014ef00fca0222eb94b4193b741 100644 (file)
@@ -21,9 +21,16 @@ extern "C" {
 #endif /* !Py_LIMITED_API */
 #define Py_BuildValue                   _Py_BuildValue_SizeT
 #define Py_VaBuildValue                 _Py_VaBuildValue_SizeT
+#define _Py_VaBuildStack                _Py_VaBuildStack_SizeT
 #else
 #ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list);
+PyAPI_FUNC(PyObject **) _Py_VaBuildStack_SizeT(
+    PyObject **small_stack,
+    Py_ssize_t small_stack_len,
+    const char *format,
+    va_list va,
+    Py_ssize_t *p_nargs);
 #endif /* !Py_LIMITED_API */
 #endif
 
@@ -47,6 +54,12 @@ PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
                                                   const char *, char **, va_list);
 #endif
 PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list);
+PyAPI_FUNC(PyObject **) _Py_VaBuildStack(
+    PyObject **small_stack,
+    Py_ssize_t small_stack_len,
+    const char *format,
+    va_list va,
+    Py_ssize_t *p_nargs);
 
 #ifndef Py_LIMITED_API
 typedef struct _PyArg_Parser {
index eef79c460fab19833097656d96f099c04f8ab16c..01b5dc9dda0e643bf33ca80b6f416511efc6b943 100644 (file)
@@ -7,6 +7,7 @@
 typedef double va_double;
 
 static PyObject *va_build_value(const char *, va_list, int);
+static PyObject **va_build_stack(PyObject **small_stack, Py_ssize_t small_stack_len, const char *, va_list, int, Py_ssize_t*);
 
 /* Package context -- the full module name for package imports */
 const char *_Py_PackageContext = NULL;
@@ -60,6 +61,7 @@ countformat(const char *format, char endchar)
 /* After an original idea and first implementation by Steven Miale */
 
 static PyObject *do_mktuple(const char**, va_list *, char, Py_ssize_t, int);
+static int do_mkstack(PyObject **, const char**, va_list *, char, Py_ssize_t, int);
 static PyObject *do_mklist(const char**, va_list *, char, Py_ssize_t, int);
 static PyObject *do_mkdict(const char**, va_list *, char, Py_ssize_t, int);
 static PyObject *do_mkvalue(const char**, va_list *, int);
@@ -182,6 +184,43 @@ do_mklist(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n, int
     return v;
 }
 
+static int
+do_mkstack(PyObject **stack, const char **p_format, va_list *p_va,
+           char endchar, Py_ssize_t n, int flags)
+{
+    Py_ssize_t i;
+
+    if (n < 0) {
+        return -1;
+    }
+    /* Note that we can't bail immediately on error as this will leak
+       refcounts on any 'N' arguments. */
+    for (i = 0; i < n; i++) {
+        PyObject *w = do_mkvalue(p_format, p_va, flags);
+        if (w == NULL) {
+            do_ignore(p_format, p_va, endchar, n - i - 1, flags);
+            goto error;
+        }
+        stack[i] = w;
+    }
+    if (**p_format != endchar) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unmatched paren in format");
+        goto error;
+    }
+    if (endchar) {
+        ++*p_format;
+    }
+    return 0;
+
+error:
+    n = i;
+    for (i=0; i < n; i++) {
+        Py_DECREF(stack[i]);
+    }
+    return -1;
+}
+
 static PyObject *
 do_mktuple(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n, int flags)
 {
@@ -488,6 +527,65 @@ va_build_value(const char *format, va_list va, int flags)
     return retval;
 }
 
+PyObject **
+_Py_VaBuildStack(PyObject **small_stack, Py_ssize_t small_stack_len,
+                const char *format, va_list va, Py_ssize_t *p_nargs)
+{
+    return va_build_stack(small_stack, small_stack_len, format, va, 0, p_nargs);
+}
+
+PyObject **
+_Py_VaBuildStack_SizeT(PyObject **small_stack, Py_ssize_t small_stack_len,
+                       const char *format, va_list va, Py_ssize_t *p_nargs)
+{
+    return va_build_stack(small_stack, small_stack_len, format, va, FLAG_SIZE_T, p_nargs);
+}
+
+static PyObject **
+va_build_stack(PyObject **small_stack, Py_ssize_t small_stack_len,
+               const char *format, va_list va, int flags, Py_ssize_t *p_nargs)
+{
+    const char *f;
+    Py_ssize_t n;
+    va_list lva;
+    PyObject **stack;
+    int res;
+
+    n = countformat(format, '\0');
+    if (n < 0) {
+        *p_nargs = 0;
+        return NULL;
+    }
+
+    if (n == 0) {
+        *p_nargs = 0;
+        return small_stack;
+    }
+
+    if (n <= small_stack_len) {
+        stack = small_stack;
+    }
+    else {
+        stack = PyMem_Malloc(n * sizeof(stack[0]));
+        if (stack == NULL) {
+            PyErr_NoMemory();
+            return NULL;
+        }
+    }
+
+    va_copy(lva, va);
+    f = format;
+    res = do_mkstack(stack, &f, &lva, '\0', n, flags);
+    va_end(lva);
+
+    if (res < 0) {
+        return NULL;
+    }
+
+    *p_nargs = n;
+    return stack;
+}
+
 
 PyObject *
 PyEval_CallFunction(PyObject *callable, const char *format, ...)