Add _Py_VaBuildStack() function

Issue #28915: Similar to Py_VaBuildValue(), but work on a C array of PyObject*,
instead of creating a tuple.
This commit is contained in:
Victor Stinner 2016-12-09 00:29:49 +01:00
parent b551b6c9f0
commit e9abde4642
2 changed files with 111 additions and 0 deletions

View File

@ -21,9 +21,16 @@ extern "C" {
#endif /* !Py_LIMITED_API */ #endif /* !Py_LIMITED_API */
#define Py_BuildValue _Py_BuildValue_SizeT #define Py_BuildValue _Py_BuildValue_SizeT
#define Py_VaBuildValue _Py_VaBuildValue_SizeT #define Py_VaBuildValue _Py_VaBuildValue_SizeT
#define _Py_VaBuildStack _Py_VaBuildStack_SizeT
#else #else
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list); 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 /* !Py_LIMITED_API */
#endif #endif
@ -47,6 +54,12 @@ PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
const char *, char **, va_list); const char *, char **, va_list);
#endif #endif
PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); 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 #ifndef Py_LIMITED_API
typedef struct _PyArg_Parser { typedef struct _PyArg_Parser {

View File

@ -7,6 +7,7 @@
typedef double va_double; typedef double va_double;
static PyObject *va_build_value(const char *, va_list, int); 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 */ /* Package context -- the full module name for package imports */
const char *_Py_PackageContext = NULL; 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 */ /* After an original idea and first implementation by Steven Miale */
static PyObject *do_mktuple(const char**, va_list *, char, Py_ssize_t, int); 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_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_mkdict(const char**, va_list *, char, Py_ssize_t, int);
static PyObject *do_mkvalue(const char**, va_list *, 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; 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 * static PyObject *
do_mktuple(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n, int flags) 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; 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 * PyObject *
PyEval_CallFunction(PyObject *callable, const char *format, ...) PyEval_CallFunction(PyObject *callable, const char *format, ...)