Mercurial > hgrepos > Python > libs > ConfigMix
diff configmix/_speedups.c @ 603:e55a42144ba9
C-implementations for Configuration.getvarl() and Configuration.getvar_s()
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Tue, 11 Jan 2022 02:50:17 +0100 |
| parents | a2fff0d93d83 |
| children | 776dc94b4ef7 |
line wrap: on
line diff
--- a/configmix/_speedups.c Tue Jan 11 00:52:56 2022 +0100 +++ b/configmix/_speedups.c Tue Jan 11 02:50:17 2022 +0100 @@ -30,11 +30,16 @@ PyObject *EMPTY_STR; PyObject *QUOTE_MAP; PyObject *MISSING; + PyObject *MARKER; PyObject *STARTTOK; PyObject *ENDTOK; + PyObject *REF_NAMESPACE; }; +static PyObject * _fast_getvar_s(PyObject *, PyObject *, PyObject *, PyObject *, struct speedups_state *, int*); + + static int _hex2ucs4(PyObject *s, Py_ssize_t end, Py_UCS4 *result) @@ -835,9 +840,8 @@ filters = Py_NewRef(PyTuple_GetItem(tmp, 1)); py_clear_ref(&tmp); - tmp = PyObject_CallMethod( - config, "_getvar_s_with_cache_info", "O", varname); - if (tmp == NULL) { + varvalue = _fast_getvar_s(config, varname, NULL, self, sstate, &cacheable); + if (varvalue == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyError)) { cacheable = 1; if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) { @@ -863,18 +867,6 @@ goto error; } } - else { - if (PyTuple_Size(tmp) != 2) { - py_clear_ref(&tmp); - PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected"); - goto error; - } - /* unpack the result */ - /* borrowed -- cannot fail -- but want ownership */ - varvalue = Py_NewRef(PyTuple_GetItem(tmp, 0)); - cacheable = PyObject_IsTrue(PyTuple_GetItem(tmp, 1)); - py_clear_ref(&tmp); - } if (!cacheable) { use_cache = 0; @@ -1065,9 +1057,9 @@ filters = Py_NewRef(PyTuple_GetItem(tmp, 1)); py_clear_ref(&tmp); - tmp = PyObject_CallMethod( - config, "_getvar_s_with_cache_info", "O", varname); - if (tmp == NULL) { + varvalue = _fast_getvar_s(config, varname, NULL, self, sstate, &cacheable); + + if (varvalue == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyError)) { cacheable = 1; if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) { @@ -1095,18 +1087,6 @@ goto error; } } - else { - if (PyTuple_Size(tmp) != 2) { - py_clear_ref(&tmp); - PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected"); - goto error; - } - /* unpack the result */ - /* borrowed -- but want own */ - varvalue = Py_NewRef(PyTuple_GetItem(tmp, 0)); - cacheable = PyObject_IsTrue(PyTuple_GetItem(tmp, 1)); - py_clear_ref(&tmp); - } if (!cacheable) { use_cache = 0; @@ -1191,6 +1171,205 @@ static PyObject * +_fast_getvarl(PyObject *config, PyObject *path, PyObject *namespace, PyObject *default_, struct speedups_state *sstate) +{ + PyObject *varvalue; + PyObject *lookupfn = NULL; + + if ((namespace == NULL) || PyObject_Not(namespace)) { + lookupfn = PyObject_GetAttrString(config, "_lookupvar"); + if (lookupfn == NULL) { + goto error; + } + } + else { + int ns_equals_ref = PyUnicode_Compare(namespace, sstate->REF_NAMESPACE); + if ((ns_equals_ref < 0) && PyErr_Occurred()) { + return NULL; + } + if (ns_equals_ref == 0) { + lookupfn = PyObject_GetAttrString(config, "_lookupref"); + if (lookupfn == NULL) { + goto error; + } + } + else { + /* lookup_varns */ + /* this is borrowed */ + PyObject *cfg_vars_mod = PyImport_AddModule("configmix.variables"); + if (cfg_vars_mod == NULL) { + goto error; + } + lookupfn = PyObject_CallMethod(cfg_vars_mod, "lookup_varns", "O", namespace); + if (lookupfn == NULL) { + goto handle_possible_keyerror; + } + } + } + varvalue = PyObject_CallObject(lookupfn, path); + if (varvalue == NULL) { + goto handle_possible_keyerror; + } + Py_DECREF(lookupfn); + return varvalue; + +handle_possible_keyerror: + if (PyErr_ExceptionMatches(PyExc_KeyError)) { + if ((default_ == NULL) || py_object_is(default_, sstate->MARKER)) { + PyErr_Format(PyExc_KeyError, "Variable %R not found", path); + /* fall through */ + } + else { + PyErr_Clear(); + Py_XDECREF(lookupfn); + return Py_NewRef(default_); + } + } + /* fall through */ +error: + Py_XDECREF(lookupfn); + return NULL; +} + + +static +PyObject * +fast_getvarl(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"config", "path", "namespace", "default", NULL}; + PyObject *path; + PyObject *config; + PyObject *namespace = NULL; + PyObject *default_ = NULL; + + struct speedups_state *sstate; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO!|$OO", kwlist, &config, &PyTuple_Type, &path, &namespace, &default_)) { + + return NULL; + } + sstate = PyModule_GetState(self); + if (sstate == NULL) { + PyErr_SetString(PyExc_RuntimeError, "no module state available"); + return NULL; + } + return _fast_getvarl(config, path, namespace, default_, sstate); +} + + +/** + * Mixture of py_getvar_s and _py_getvar_s_with_cache_info + */ +static +PyObject * +_fast_getvar_s(PyObject *config, PyObject *varname, PyObject *default_, PyObject *self, struct speedups_state *sstate, int *cacheable) +{ + PyObject *varname_b; /* always borrowed */ + PyObject *namespace_b; /* always borrowed */ + PyObject *splitted = NULL; + PyObject *res = NULL; + PyObject *tmp1; + PyObject *tmp2; + + splitted = fast_split_ns(self, varname); + if (splitted == NULL) { + goto error; + } + namespace_b = PyTuple_GetItem(splitted, 0); /* borrowed */ + varname_b = PyTuple_GetItem(splitted, 1); /* borrowed */ + + if (PyObject_Not(namespace_b)) { + tmp1 = _fast_pathstr2path(varname_b, NULL, sstate); + if (tmp1 == NULL) { + goto error; + } + tmp2 = _fast_getvarl(config, tmp1, NULL, default_, sstate); + if (tmp2 == NULL) { + py_clear_ref(&tmp1); + goto handle_possible_keyerror; + } + py_clear_ref(&tmp1); + res = PyObject_CallMethod(config, "substitute_variables_in_obj", "O", tmp2); + if (res == NULL) { + py_clear_ref(&tmp2); + goto handle_possible_keyerror; + } + py_clear_ref(&tmp2); + /* no namespace -> cacheable */ + *cacheable = 1; + } + else { + tmp1 = PyTuple_New(1); + if (tmp1 == NULL) { + goto error; + } + PyTuple_SetItem(tmp1, 0, Py_NewRef(varname_b)); + tmp2 = _fast_getvarl(config, tmp1, namespace_b, NULL, sstate); + if (tmp2 == NULL) { + py_clear_ref(&tmp1); + goto handle_possible_keyerror; + } + py_clear_ref(&tmp1); + res = PyObject_CallMethod(config, "substitute_variables_in_obj", "O", tmp2); + if (res == NULL) { + py_clear_ref(&tmp2); + goto handle_possible_keyerror; + } + py_clear_ref(&tmp2); + /* results from namespaced lookups are currently not cacheable */ + *cacheable = 0; + } + + /* free splitted last because of using borrowed refs from it */ + Py_DECREF(splitted); + return res; + +handle_possible_keyerror: + if (PyErr_ExceptionMatches(PyExc_KeyError)) { + if ((default_ == NULL) || py_object_is(default_, sstate->MARKER)) { + /* fall through */ + } + else { + PyErr_Clear(); + Py_XDECREF(res); + Py_XDECREF(splitted); + return Py_NewRef(default_); + } + } + /* fall through */ + +error: + Py_XDECREF(res); + Py_XDECREF(splitted); + return NULL; +} + + +static +PyObject * +fast_getvar_s(PyObject *self, PyObject *args) +{ + PyObject *config; + PyObject *varname; + PyObject *default_; + int cacheable; + struct speedups_state *sstate; + + if (!PyArg_UnpackTuple(args, "config", 3, 3, &config, &varname, &default_)) { + return NULL; + } + + sstate = PyModule_GetState(self); + if (sstate == NULL) { + PyErr_SetString(PyExc_RuntimeError, "no module state available"); + return NULL; + } + return _fast_getvar_s(config, varname, default_, self, sstate, &cacheable); +} + + +static +PyObject * sync_MISSING(PyObject *self, PyObject *missing) { struct speedups_state *sstate; @@ -1209,6 +1388,26 @@ } +static +PyObject * +sync_MARKER(PyObject *self, PyObject *marker) +{ + struct speedups_state *sstate; + + sstate = PyModule_GetState(self); + if (sstate == NULL) { + PyErr_SetString(PyExc_RuntimeError, "no module state available"); + return NULL; + } + if (sstate->MARKER != NULL) { + PyErr_SetString(PyExc_RuntimeError, "_MARKER already set"); + return NULL; + } + sstate->MARKER = Py_NewRef(marker); + Py_RETURN_NONE; +} + + static struct PyMethodDef speedups_methods[] = { {"fast_unquote", fast_unquote, METH_O, PyDoc_STR("C-implementation of configmix.unquote")}, {"fast_quote", fast_quote, METH_O, PyDoc_STR("C-implementation of configmix.quote")}, @@ -1216,8 +1415,10 @@ {"_fast_split_filters", fast_split_filters, METH_O, PyDoc_STR("C-implementation of configmix.config._split_filters")}, {"_fast_split_ns", fast_split_ns, METH_O, PyDoc_STR("C-implementation of configmix.config._split_ns")}, {"_fast_interpolate_variables", fast_interpolate_variables, METH_VARARGS, PyDoc_STR("C-implementation of configmix.config.Configuration.interpolate_variables")}, + {"_fast_getvarl", (PyCFunction)fast_getvarl, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvarl")}, + {"_fast_getvar_s", fast_getvar_s, METH_VARARGS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvar_s")}, {"_sync_MISSING", sync_MISSING, METH_O, PyDoc_STR("Internal function to easily sync the _MISSING object with configmix.config")}, - + {"_sync_MARKER", sync_MARKER, METH_O, PyDoc_STR("Internal function to easily sync the _MARKER object with configmix.config")}, {NULL, NULL, 0, NULL} }; @@ -1314,6 +1515,12 @@ } PyUnicode_InternInPlace(&(sstate->ENDTOK)); + sstate->REF_NAMESPACE = PyUnicode_FromStringAndSize("ref", 3); + if (sstate->REF_NAMESPACE == NULL) { + return -1; + } + PyUnicode_InternInPlace(&(sstate->REF_NAMESPACE)); + return 0; } @@ -1334,8 +1541,10 @@ Py_VISIT(sstate->EMPTY_STR); Py_VISIT(sstate->QUOTE_MAP); Py_VISIT(sstate->MISSING); + Py_VISIT(sstate->MARKER); Py_VISIT(sstate->STARTTOK); Py_VISIT(sstate->ENDTOK); + Py_VISIT(sstate->REF_NAMESPACE); } return 0; } @@ -1357,8 +1566,10 @@ Py_CLEAR(sstate->EMPTY_STR); Py_CLEAR(sstate->QUOTE_MAP); Py_CLEAR(sstate->MISSING); + Py_CLEAR(sstate->MARKER); Py_CLEAR(sstate->STARTTOK); Py_CLEAR(sstate->ENDTOK); + Py_CLEAR(sstate->REF_NAMESPACE); } return 0; }
