Mercurial > hgrepos > Python > libs > ConfigMix
view configmix/_speedups.c @ 751:8238e3c22f89 v0.23.1
+++++ v0.23.1
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Tue, 31 Oct 2023 08:35:37 +0100 |
| parents | c17a4e30ebbf |
| children |
line wrap: on
line source
/* -*- coding: utf-8 -*- */ /* * Speedups for configmix. * * :Copyright: (c) 2021-2022, Franz Glasner. All rights reserved. * :License: BSD-3-Clause. See LICENSE.txt for details. */ #define PY_SSIZE_T_CLEAN #include "Python.h" #include "_py_helper.h" const char _configmix_speedups_id[] = "@(#)configmix._speedups $Header$"; static const char release[] = "|VCSRevision|"; static const char date[] = "|VCSJustDate|"; /* * Module state holds some pre-created objects */ struct speedups_state { PyObject *DOT; PyObject *QUOTE; PyObject *NS_SEPARATOR; PyObject *FILTER_SEPARATOR; PyObject *FILTER_SEPARATOR_2; PyObject *EMPTY_FILTER; PyObject *NONE_FILTER; PyObject *EMPTY_STR; PyObject *QUOTE_MAP; PyObject *MISSING; PyObject *MARKER; PyObject *STARTTOK; PyObject *ENDTOK; PyObject *ENDTOK_FILTER; PyObject *REF_NAMESPACE; PyObject *DEL_VALUE; }; static PyObject * _fast_getvar_s(PyObject *config, PyObject *varname, PyObject *default_, struct speedups_state *sstate, int *cacheable); static PyObject * _fast_interpolate_variables(PyObject *self, PyObject *config, PyObject *s, PyObject *cache); static int _hex2ucs4(PyObject *s, Py_ssize_t end, Py_UCS4 *result) { Py_ssize_t i; Py_UCS4 c; Py_UCS4 r = 0; for (i=1; i < end; i++) { r *= 16; c = PyUnicode_ReadChar(s, i); if ((c >= 48) && (c <= 57)) { /* 0 - 9 */ r += (c - 48); } else { if ((c >= 97) && (c <= 102)) { /* a - f */ r += (c - 87); } else { if ((c >= 65) && (c <= 70)) { /* A - F */ r += (c - 55); } else { PyErr_Format(PyExc_ValueError, "invalid base-16 literal: %c", (int)c); return -1; } } } } *result = r; return 0; /* success */ } static int _dec2num(PyObject *s, Py_ssize_t start, Py_ssize_t end, Py_ssize_t *result) { Py_ssize_t i; Py_UCS4 c; Py_ssize_t r = 0; int sign = 0; for (i=start; i<=end; i++) { /* Overflow error check */ if (r > 3275) { PyErr_SetString(PyExc_OverflowError, "index too large"); return -1; } r *= 10; c = PyUnicode_ReadChar(s, i); if ((c >= 48) && (c <= 57)) { /* 0 - 9 */ r += (c - 48); } else { if (i == start) { /* check for number sign (but only at the first index) */ if (c == 0x2d) { sign = -1; continue; } else { if (c == 0x2b) { sign = 1; continue; } } } PyErr_Format(PyExc_ValueError, "invalid base-10 literal: %c", (int)c); return -1; } } if (sign >= 0) { *result = r; } else { *result = -r; } return 0; /* success */ } #if defined(Py_LIMITED_API) static void _raise_utf8_encode_error(PyObject *s, Py_ssize_t start, Py_ssize_t end, const char *reason) { /* * See also: https://docs.python.org/3/c-api/exceptions.html#unicode-exception-objects */ PyObject *errobj = PyObject_CallFunction( PyExc_UnicodeEncodeError, "sOnns", "utf-8", s, start, end, reason); if (errobj == NULL) { /* cannot do anything here */ return; } /* Make PyExc_UnicodeEncodeError owned because PyErr_Restore steals */ //Py_INCREF(PyExc_UnicodeEncodeError); //PyErr_Restore(PyExc_UnicodeEncodeError, errobj, NULL); PyErr_SetObject(PyExc_UnicodeEncodeError, errobj); Py_DECREF(errobj); } /* * Copyright 2001-2004 Unicode, Inc. * * Disclaimer * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine * applicability of information provided. If this file has been * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. * * Limitations on Rights to Redistribute This Code * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. */ #define UNI_MAX_LEGAL_UTF32 (Py_UCS4)0x0010FFFF #define UNI_SUR_HIGH_START (Py_UCS4)0xD800 #define UNI_SUR_HIGH_END (Py_UCS4)0xDBFF #define UNI_SUR_LOW_START (Py_UCS4)0xDC00 #define UNI_SUR_LOW_END (Py_UCS4)0xDFFF /* * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed * into the first byte, depending on how many bytes follow. There are * as many entries in this table as there are UTF-8 sequence types. * (I.e., one byte sequence, two byte... etc.). Remember that sequencs * for *legal* UTF-8 will be 4 or fewer bytes total. */ static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; static Py_ssize_t _convert_ucs4_to_utf8( Py_UCS4 ch, unsigned char *targetStart, unsigned char *targetEnd, int strict, PyObject *ch_obj, /* for error messages: the string where ch comes from */ Py_ssize_t ch_obj_end /* effective length of ch_obj (error reporting) */ ) { const Py_UCS4 byteMask = 0xBF; const Py_UCS4 byteMark = 0x80; Py_ssize_t bytesToWrite = 0; unsigned char *target = targetStart; if (strict) { /* UTF-16 surrogate values are illegal */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { _raise_utf8_encode_error( ch_obj, 1, ch_obj_end, "surrogate values are illegal in UCS4"); return -1; } } /* * Figure out how many bytes the result will require. Turn any * illegally large UTF32 things (> Plane 17) into errors (exceptions). */ if (ch < (Py_UCS4)0x80) { bytesToWrite = 1; } else if (ch < (Py_UCS4)0x800) { bytesToWrite = 2; } else if (ch < (Py_UCS4)0x10000) { bytesToWrite = 3; } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; } else { _raise_utf8_encode_error( ch_obj, 1, ch_obj_end, "max Unicode codepoint value exceeded"); return -1; } target += bytesToWrite; if (target > targetEnd) { _raise_utf8_encode_error( ch_obj, 1, ch_obj_end, "temporary target buffer exhausted"); return -1; } switch (bytesToWrite) { /* note: everything falls through. */ case 4: *--target = (unsigned char)((ch | byteMark) & byteMask); ch >>= 6; case 3: *--target = (unsigned char)((ch | byteMark) & byteMask); ch >>= 6; case 2: *--target = (unsigned char)((ch | byteMark) & byteMask); ch >>= 6; case 1: *--target = (unsigned char) (ch | firstByteMark[bytesToWrite]); } return bytesToWrite; } /* * End of Copyright 2001-2004 Unicode, Inc. */ static PyObject * _hex2string(PyObject *s, Py_ssize_t end) { Py_UCS4 c; unsigned char buf[6]; Py_ssize_t bytes_written; PyObject *u; if (_hex2ucs4(s, end, &c) != 0) return NULL; /* Replace the combination PyUniode_New/PyUnicode_WriteChar */ bytes_written = _convert_ucs4_to_utf8(c, buf, &(buf[6]), 1, s, end+1); if (bytes_written < 0) { return NULL; } u = PyUnicode_FromStringAndSize((const char *)buf, bytes_written); if (u == NULL) { return NULL; } return u; } #else static PyObject * _hex2string(PyObject *s, Py_ssize_t end) { Py_UCS4 c; PyObject *u = NULL; if (_hex2ucs4(s, end, &c) != 0) return NULL; u = PyUnicode_New(1, c); /* ARGH: not in the stable API */ if (u == NULL) return NULL; if (PyUnicode_WriteChar(u, 0, c) != 0) { Py_DECREF(u); return NULL; } return u; } #endif /* Py_LIMITED_API */ static PyObject * _fast_unquote(PyObject *s, Py_ssize_t s_len, PyObject *self, struct speedups_state *sstate) { Py_ssize_t find; Py_ssize_t parts_len; PyObject *res; PyObject *res_parts = NULL; PyObject *parts = NULL; PyObject *o; PyObject *pb; Py_ssize_t pb_len; Py_ssize_t i; Py_UCS4 c; if (s_len < 0) { s_len = PyUnicode_GetLength(s); if (s_len < 0) { return NULL; } } if (s_len == 0) { return Py_NewRef(s); } if (s_len > 2) { /* Check for ~NNN~ syntax */ c = PyUnicode_ReadChar(s, 0); if (c == 0x7e) { c = PyUnicode_ReadChar(s, s_len - 1); if (c == 0x7e) { if (_dec2num(s, 1, s_len - 2, &i) == 0) { return PyLong_FromSsize_t(i); } PyErr_Clear(); } } } find = PyUnicode_FindChar(s, '%', 0, s_len, 1); if (find == -2) { return NULL; } if (find == -1) { return Py_NewRef(s); } if (sstate == NULL) { sstate = PyModule_GetState(self); if (sstate == NULL) { PyErr_SetString(PyExc_RuntimeError, "no module state available"); return NULL; } } parts = PyUnicode_Split(s, sstate->QUOTE, -1); if (parts == NULL) { goto error; } parts_len = PyList_Size(parts); if (parts_len < 0) { goto error; } res_parts = PyTuple_New((parts_len-1)*2 + 1); if (res_parts == NULL) { goto error; } o = PyList_GetItem(parts, 0); /* borrowed */ if (o == NULL) { goto error; } /* * The first item may be also the empty string if `s' starts with * a quoted character. */ PyTuple_SetItem(res_parts, 0, Py_NewRef(o)); for (i=1; i<parts_len; i++) { pb = PyList_GetItem(parts, i); /* borrowed */ pb_len = PyUnicode_GetLength(pb); if (pb_len < 1) { PyErr_Format(PyExc_ValueError, "quote syntax: length too small: %U", pb); goto error; } c = PyUnicode_ReadChar(pb, 0); switch (c) { case 0x55: /* U */ if (pb_len < 9) { PyErr_Format(PyExc_ValueError, "quote syntax: length too small: %U", pb); goto error; } o = _hex2string(pb, 9); if (o == NULL) { goto error; } PyTuple_SetItem(res_parts, (i-1)*2 + 1, o); /* steals */ o = PyUnicode_Substring(pb, 9, pb_len); if (o == NULL) { goto error; } PyTuple_SetItem(res_parts, i*2, o); /* steals */ break; case 0x75: /* u */ if (pb_len < 5) { PyErr_Format(PyExc_ValueError, "quote syntax: length too small: %U", pb); goto error; } o = _hex2string(pb, 5); if (o == NULL) { goto error; } PyTuple_SetItem(res_parts, (i-1)*2 + 1, o); /* steals */ o = PyUnicode_Substring(pb, 5, pb_len); if (o == NULL) { goto error; } PyTuple_SetItem(res_parts, i*2, o); /* steals */ break; case 0x78: /* x */ if (pb_len < 3) { PyErr_Format(PyExc_ValueError, "quote syntax: length too small: %U", pb); goto error; } o = _hex2string(pb, 3); if (o == NULL) { goto error; } PyTuple_SetItem(res_parts, (i-1)*2 + 1, o); /* steals */ o = PyUnicode_Substring(pb, 3, pb_len); if (o == NULL) { goto error; } PyTuple_SetItem(res_parts, i*2, o); /* steals */ break; default: PyErr_Format(PyExc_ValueError, "quote syntax: length too small: %U", pb); goto error; } } res = PyUnicode_Join(sstate->EMPTY_STR, res_parts); if (res == NULL) { goto error; } Py_DECREF(parts); Py_DECREF(res_parts); return res; error: Py_XDECREF(res_parts); Py_XDECREF(parts); return NULL; } static PyObject * fast_unquote(PyObject *self, PyObject *s) { return _fast_unquote(s, -1, self, NULL); } static PyObject * fast_quote(PyObject *self, PyObject *s) { Py_ssize_t s_len; Py_ssize_t i; Py_UCS4 c; int need_quoting; struct speedups_state *sstate; s_len = PyUnicode_GetLength(s); if (s_len < 0) { if (PyObject_IsInstance(s, (PyObject *)&PyLong_Type)) { PyErr_Clear(); return PyUnicode_FromFormat("~%S~", s); } PyErr_SetString(PyExc_TypeError, "given object has no len()"); return NULL; } if (s_len == 0) { return Py_NewRef(s); } need_quoting = 0; for (i=0; i<s_len; i++) { c = PyUnicode_ReadChar(s, i); /* type already checked */ switch (c) { case 0x25: case 0x2e: case 0x3a: case 0x23: case 0x7c: case 0x22: case 0x27: case 0x7b: case 0x7d: case 0x5b: case 0x5d: case 0x7e: need_quoting = 1; i = s_len; /* break the for-loop */ break; default: /* VOID */ ; } } if (!need_quoting) { return Py_NewRef(s); } sstate = PyModule_GetState(self); if (sstate == NULL) { PyErr_SetString(PyExc_RuntimeError, "no module state available"); return NULL; } return PyUnicode_Translate(s, sstate->QUOTE_MAP, "strict"); } static PyObject * _fast_pathstr2path(PyObject *varname, PyObject *self, struct speedups_state *sstate) { Py_ssize_t varname_len; PyObject *parts = NULL; Py_ssize_t parts_len; PyObject *res = NULL; Py_ssize_t i; PyObject *o; PyObject *u; varname_len = PyUnicode_GetLength(varname); if (varname_len < 0) { return NULL; } if (varname_len == 0) { return PyTuple_New(0); } if (sstate == NULL) { sstate = PyModule_GetState(self); if (sstate == NULL) { PyErr_SetString(PyExc_RuntimeError, "no module state available"); return NULL; } } parts = PyUnicode_Split(varname, sstate->DOT, -1); if (parts == NULL) { goto error; } parts_len = PyList_Size(parts); if (parts_len < 0) { goto error; } res = PyTuple_New(parts_len); if (res == NULL) { goto error; } for (i=0; i < parts_len; i++) { o = PyList_GetItem(parts, i); /* borrowed */ u = _fast_unquote(o, -1, NULL, sstate); if (u == NULL) { goto error; } PyTuple_SetItem(res, i, u); /* steals */ } Py_DECREF(parts); return res; error: Py_XDECREF(parts); Py_XDECREF(res); return NULL; } static PyObject * fast_pathstr2path(PyObject *self, PyObject *varname) { return _fast_pathstr2path(varname, self, NULL); } static PyObject * _fast_split_filters(PyObject *varname, PyObject *self, Py_ssize_t direction, struct speedups_state *sstate) { Py_ssize_t varname_len; Py_ssize_t sep; PyObject *res = NULL; PyObject *filters = NULL; Py_ssize_t filters_len; PyObject *name = NULL; PyObject *tmp; varname_len = PyUnicode_GetLength(varname); if (varname_len < 0) { return NULL; } if (varname_len == 0) { sep = -1; } else { sep = PyUnicode_FindChar(varname, '|', 0, varname_len, (int)direction); if (sep == -2) { return NULL; } } if (sep == -1) { res = PyTuple_New(2); if (res == NULL) { goto error; } PyTuple_SetItem(res, 0, Py_NewRef(varname)); /* steals */ filters = PyList_New(0); if (filters == NULL) { goto error; } PyTuple_SetItem(res, 1, filters); /* steals */ return res; } name = PyUnicode_Substring(varname, 0, sep); if (name == NULL) { goto error; } filters = PyUnicode_Substring(varname, sep+1, varname_len); if (filters == NULL) { goto error; } tmp = PyObject_CallMethod(filters, "strip", NULL); if (tmp == NULL) { goto error; } py_transfer_owned(&filters, &tmp); filters_len = PyUnicode_GetLength(filters); if (filters_len < 0) { goto error; } if (filters_len == 0) { py_clear_ref(&filters); res = PyTuple_New(2); if (res == NULL) { goto error; } PyTuple_SetItem(res, 0, name); /* steals */ name = NULL; /* no ownership any more */ filters = PyList_New(0); if (filters == NULL) { goto error; } PyTuple_SetItem(res, 1, filters); /* steals */ filters = NULL; return res; } if (sstate == NULL) { sstate = PyModule_GetState(self); if (sstate == NULL) { PyErr_SetString(PyExc_RuntimeError, "no module state available"); goto error; } } if (direction == 1) { if (PyUnicode_FindChar(filters, ',', 0, filters_len, 1) >= 0) { tmp = PyUnicode_Split(filters, sstate->FILTER_SEPARATOR_2, -1); } else { tmp = PyUnicode_Split(filters, sstate->FILTER_SEPARATOR, -1); } } else { tmp = PyUnicode_Split(filters, sstate->FILTER_SEPARATOR_2, -1); } if (tmp == NULL) { goto error; } py_transfer_owned(&filters, &tmp); res = PyTuple_New(2); if (res == NULL) { goto error; } PyTuple_SetItem(res, 0, name); /* steals -- ownership changed */ PyTuple_SetItem(res, 1, filters); /* steals -- ownership changed */ return res; error: Py_XDECREF(res); Py_XDECREF(filters); Py_XDECREF(name); return NULL; } static PyObject * fast_split_filters(PyObject *self, PyObject *args) { PyObject *varname; PyObject *direction_obj; Py_ssize_t direction; if (!PyArg_UnpackTuple(args, "fast_split_filters", 2, 2, &varname, &direction_obj)) { return NULL; } direction = PyNumber_AsSsize_t(direction_obj, PyExc_OverflowError); if (direction == -1) { if (PyErr_Occurred()) { return NULL; } } if ((direction == 1) || (direction == -1)) { return _fast_split_filters(varname, self, direction, NULL); } else { PyErr_SetString(PyExc_ValueError, "`direction' must be -1 or +1"); return NULL; } } static PyObject * _fast_split_ns(PyObject *varname, PyObject *self, struct speedups_state *sstate) { PyObject *res = NULL; Py_ssize_t ns_idx; Py_ssize_t varname_len; PyObject *o1; PyObject *o2; varname_len = PyUnicode_GetLength(varname); if (varname_len < 0) { return NULL; } ns_idx = PyUnicode_FindChar(varname, ':', 0, varname_len, 1); if (ns_idx == -2) { return NULL; } if (ns_idx == -1) { res = PyTuple_New(2); if (res == NULL) { return NULL; } PyTuple_SetItem(res, 0, Py_NewRef(Py_None)); /* steals */ PyTuple_SetItem(res, 1, Py_NewRef(varname)); /* steals */ return res; } res = PyTuple_New(2); if (res == NULL) { return NULL; } o1 = PyUnicode_Substring(varname, 0, ns_idx); if (o1 == NULL) { Py_DECREF(res); return NULL; } o2 = _fast_unquote(o1, ns_idx, self, sstate); if (o2 == NULL) { Py_DECREF(o1); Py_DECREF(res); return NULL; } Py_DECREF(o1); PyTuple_SetItem(res, 0, o2); /* steals */ o1 = PyUnicode_Substring(varname, ns_idx+1, varname_len); if (o1 == NULL) { Py_DECREF(res); return NULL; } PyTuple_SetItem(res, 1, o1); /* steals */ return res; } static PyObject * fast_split_ns(PyObject *self, PyObject *varname) { return _fast_split_ns(varname, self, NULL); } static PyObject * fast_interpolate_variables_old(PyObject *self, PyObject *args) { PyObject *config; PyObject *s; PyObject *cache; int cmp; Py_ssize_t s_len; Py_ssize_t idx; Py_ssize_t i, j; PyObject *parts = NULL; Py_ssize_t parts_len; PyObject *res_parts = NULL; PyObject *res = NULL; PyObject *tmp; PyObject *pb; Py_ssize_t pb_len; PyObject *varname = NULL; PyObject *varvalue = NULL; PyObject *filters = NULL; int cacheable; int use_cache = 1; int first_part_is_empty; PyObject *err_type; PyObject *err_value; PyObject *err_tb; struct speedups_state *sstate; if (!PyArg_UnpackTuple(args, "s", 3, 3, &config, &s, &cache)) { return NULL; } s_len = PyUnicode_GetLength(s); /* also an implicit type check */ if (s_len < 0) { return NULL; } if (s_len < 4) { PyErr_Clear(); return Py_NewRef(s); } sstate = PyModule_GetState(self); if (sstate == NULL) { PyErr_SetString(PyExc_RuntimeError, "no module state available"); return NULL; } cmp = PyUnicode_Compare(s, sstate->DEL_VALUE); if ((cmp < 0) && PyErr_Occurred()) { return NULL; } if (cmp == 0) { return Py_NewRef(s); } idx = PyUnicode_Find(s, sstate->STARTTOK, 0, s_len, 1); if (idx < 0) { PyErr_Clear(); return Py_NewRef(s); } res = PyDict_GetItem(cache, s); /* borrowed */ if (res != NULL) { if (py_object_is(res, sstate->MISSING)) { return PyErr_Format( PyExc_KeyError, "Cannot interpolate variables in string %R (cached)", s); } else { return Py_NewRef(res); } } parts = PyUnicode_Split(s, sstate->STARTTOK, -1); if (parts == NULL) { goto error; } parts_len = PyList_Size(parts); if (parts_len < 0) { goto error; } res_parts = PyList_New(1); if (res_parts == NULL) { goto error; } tmp = PyList_GetItem(parts, 0); /* borrowed */ if (tmp == NULL) { goto error; } /* * The first item may be also the empty string if `s' starts with * an interpolation token. */ first_part_is_empty = PyObject_Not(tmp); /* 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++) { pb = PyList_GetItem(parts, i); /* borrowed */ pb_len = PyUnicode_GetLength(pb); if (pb_len < 0) { goto error; } idx = PyUnicode_Find(pb, sstate->ENDTOK, 0, pb_len, 1); if (idx < 0) { /* * Behave similar to the pure-Python version: copy the complete * rest as-is. Also include the start tokens! */ if (PyList_Append(res_parts, sstate->STARTTOK) < 0) { goto error; } if (PyList_Append(res_parts, pb) < 0) { goto error; } for (j=i+1; j<parts_len; j++) { if (PyList_Append(res_parts, sstate->STARTTOK) < 0) { goto error; } pb = PyList_GetItem(parts, j); /* borrowed */ if (PyList_Append(res_parts, pb) < 0) { goto error; } } break; /* the for-loop */ } varname = PyUnicode_Substring(pb, 0, idx); if (varname == NULL) { goto error; } tmp = _fast_split_filters(varname, NULL, 1, sstate); if (tmp == NULL) { goto error; } if (PyTuple_Size(tmp) != 2) { py_clear_ref(&tmp); PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected"); goto error; } py_clear_ref(&varname); /* Unpack the result tuple */ /* borrowed -- cannot fail -- need ownership */ varname = Py_NewRef(PyTuple_GetItem(tmp, 0)); /* borrowed -- cannot fail -- want ownership */ filters = Py_NewRef(PyTuple_GetItem(tmp, 1)); py_clear_ref(&tmp); varvalue = _fast_getvar_s(config, varname, NULL, sstate, &cacheable); if (varvalue == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyError)) { cacheable = 1; if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) { PyErr_Clear(); varvalue = Py_NewRef(Py_None); } else { if (PySequence_Contains(filters, sstate->EMPTY_FILTER) == 1) { PyErr_Clear(); varvalue = Py_NewRef(sstate->EMPTY_STR); } else { PyErr_Fetch(&err_type, &err_value, &err_tb); /* this does NOT steal */ PyDict_SetItem(cache, s, sstate->MISSING); PyErr_Restore(err_type, err_value, err_tb); goto error; } } } else { /* other exception/error than KeyError */ goto error; } } if (!cacheable) { use_cache = 0; } py_clear_ref(&varname); tmp = PyObject_CallMethod( config, "_apply_filters", "OO", filters, varvalue); if (tmp == NULL) { goto error; } py_clear_ref(&varvalue); py_clear_ref(&filters); /* * Dont apply and type conversions to the variable value if * the whole `s` is just one expansion */ if (first_part_is_empty && (i == 1) && (pb_len == s_len - 2) && (idx == pb_len - 2)) { res = varvalue; varvalue = NULL; goto success; /* break out early */ } if (py_object_isnot(varvalue, Py_None)) { tmp = PyObject_Str(varvalue); if (tmp == NULL) { goto error; } if (PyList_Append(res_parts, tmp) < 0) { py_clear_ref(&tmp); goto error; } py_clear_ref(&tmp); } 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_clear_ref(&tmp); goto error; } py_clear_ref(&tmp); } res = PyUnicode_Join(sstate->EMPTY_STR, res_parts); if (res == NULL) { goto error; } success: Py_DECREF(parts); Py_DECREF(res_parts); if (use_cache) { PyDict_SetItem(cache, s, res); PyErr_Clear(); /* clear any possible cache-related error */ } return res; error: Py_XDECREF(varname); Py_XDECREF(varvalue); Py_XDECREF(filters); Py_XDECREF(parts); Py_XDECREF(res_parts); Py_XDECREF(res); return NULL; } static PyObject * fast_interpolate_variables(PyObject *self, PyObject *args) { PyObject *config; PyObject *s; PyObject *cache = NULL; if (!PyArg_UnpackTuple(args, "s", 2, 3, &config, &s, &cache)) { return NULL; } return _fast_interpolate_variables(self, config, s, cache); } static PyObject * _fast_interpolate_variables(PyObject *self, PyObject *config, PyObject *s, PyObject *cache) { int cmp; Py_ssize_t s_len; Py_ssize_t start, rest, end; PyObject *tmp; PyObject *result = NULL; PyObject *varname = NULL; PyObject *varvalue = NULL; PyObject *filters = NULL; PyObject *err_type; PyObject *err_value; PyObject *err_tb; int use_cache, cacheable; struct speedups_state *sstate; /* Disable caching if the cache param is given as None */ if ((cache != NULL) && py_object_is(cache, Py_None)) { cache = NULL; } s_len = PyUnicode_GetLength(s); /* also an implicit type check */ if (s_len < 0) { return NULL; } if (s_len < 4) { return Py_NewRef(s); } sstate = PyModule_GetState(self); if (sstate == NULL) { PyErr_SetString(PyExc_RuntimeError, "no module state available"); return NULL; } cmp = PyUnicode_Compare(s, sstate->DEL_VALUE); if ((cmp < 0) && PyErr_Occurred()) { return NULL; } if (cmp == 0) { return Py_NewRef(s); } start = PyUnicode_Find(s, sstate->STARTTOK, 0, s_len, 1); if (start == -2) { return NULL; } if (start == -1) { return Py_NewRef(s); } if (cache != NULL) { result = PyDict_GetItem(cache, s); /* borrowed */ if (result != NULL) { if (py_object_is(result, sstate->MISSING)) { return PyErr_Format( PyExc_KeyError, "Cannot interpolate variables in string %R (cached)", s); } else { return Py_NewRef(result); } } } /* Check for {{| ... |}} */ if ((s_len >= 6) && (start == 0) && (PyUnicode_ReadChar(s, 2) == 0x7c /* `|' */)) { end = PyUnicode_Find(s, sstate->ENDTOK_FILTER, start+3, s_len, 1); if (end == -2) { return NULL; } if (end != (s_len - 3)) { PyErr_SetString(PyExc_ValueError, "`{{|' nested filter interpolation must end with `|}}'"); return NULL; } /* * Handle {{| ... |filters, ... |}} : * split and recurse and apply filters */ tmp = PyUnicode_Substring(s, 3, s_len-3); if (tmp == NULL) { return NULL; } filters = _fast_split_filters(tmp, NULL, -1, sstate); if (filters == NULL) { py_clear_ref(&tmp); return NULL; } if (PyTuple_Size(filters) != 2) { py_clear_ref(&tmp); PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected"); goto error; } py_transfer_owned(&tmp, &filters); /* Unpack the result tuple */ /* borrowed -- cannot fail -- need ownership */ varname = Py_NewRef(PyTuple_GetItem(tmp, 0)); /* borrowed -- cannot fail -- need ownership */ filters = Py_NewRef(PyTuple_GetItem(tmp, 1)); py_clear_ref(&tmp); varvalue = _fast_interpolate_variables(self, config, varname, cache); if (varvalue == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyError)) { if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) { PyErr_Clear(); varvalue = Py_NewRef(Py_None); } else { if (PySequence_Contains(filters, sstate->EMPTY_FILTER) == 1) { PyErr_Clear(); varvalue = Py_NewRef(sstate->EMPTY_STR); } else { goto error; } } } else { /* other exception/error than KeyError */ goto error; } } py_clear_ref(&varname); result = PyObject_CallMethod( config, "_apply_filters", "OO", filters, varvalue); if (result == NULL) { goto error; } py_clear_ref(&varvalue); py_clear_ref(&filters); return result; } result = PyList_New(0); if (result == NULL) { return NULL; } rest = 0; use_cache = 1; while (start != -1) { if (rest < start) { tmp = PyUnicode_Substring(s, rest, start); if (tmp == NULL) { goto error; } if (PyList_Append(result, tmp) < 0) { py_clear_ref(&tmp); goto error; } py_clear_ref(&tmp); } end = PyUnicode_Find(s, sstate->ENDTOK, start+2, s_len, 1); if (end == -2) { goto error; } if (end == -1) { rest = start; break; } varname = PyUnicode_Substring(s, start+2, end); /* 2 == len(STARTTOK) */ if (varname == NULL) { goto error; } tmp = _fast_split_filters(varname, NULL, 1, sstate); if (tmp == NULL) { goto error; } if (PyTuple_Size(tmp) != 2) { PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected"); py_clear_ref(&tmp); goto error; } py_clear_ref(&varname); /* Unpack the result tuple */ /* borrowed -- cannot fail -- need ownership */ varname = Py_NewRef(PyTuple_GetItem(tmp, 0)); /* borrowed -- cannot fail -- need ownership */ filters = Py_NewRef(PyTuple_GetItem(tmp, 1)); py_clear_ref(&tmp); varvalue = _fast_getvar_s(config, varname, NULL, sstate, &cacheable); if (varvalue == NULL) { if (PyErr_ExceptionMatches(PyExc_KeyError)) { cacheable = 1; if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) { PyErr_Clear(); varvalue = Py_NewRef(Py_None); } else { if (PySequence_Contains(filters, sstate->EMPTY_FILTER) == 1) { PyErr_Clear(); varvalue = Py_NewRef(sstate->EMPTY_STR); } else { if (cache != NULL) { PyErr_Fetch(&err_type, &err_value, &err_tb); /* this does NOT steal */ PyDict_SetItem(cache, s, sstate->MISSING); PyErr_Restore(err_type, err_value, err_tb); } goto error; } } } else { /* other exception/error than KeyError */ goto error; } } if (!cacheable) { use_cache = 0; } py_clear_ref(&varname); tmp = PyObject_CallMethod( config, "_apply_filters", "OO", filters, varvalue); if (tmp == NULL) { goto error; } py_transfer_owned(&varvalue, &tmp); py_clear_ref(&filters); rest = end + 2; /* 2 == len(ENDTOK) */ /* * Dont apply and type conversions to the variable value if * the whole `s` is just one expansion */ if ((start == 0) && (rest == s_len)) { py_transfer_owned(&result, &varvalue); goto success; /* break out early */ } /* Handle None like the empty string */ if (py_object_isnot(varvalue, Py_None)) { tmp = PyObject_Str(varvalue); if (tmp == NULL) { goto error; } if (PyList_Append(result, tmp) < 0) { py_clear_ref(&tmp); goto error; } py_clear_ref(&tmp); } /* don't re-evaluate because `self.getvar_s()` expands already */ start = PyUnicode_Find(s, sstate->STARTTOK, rest, s_len, 1); if (start == -2) { goto error; } } if (rest < s_len) { tmp = PyUnicode_Substring(s, rest, s_len); if (tmp == NULL) { goto error; } if (PyList_Append(result, tmp) < 0) { py_clear_ref(&tmp); goto error; } py_clear_ref(&tmp); } tmp = PyUnicode_Join(sstate->EMPTY_STR, result); if (tmp == NULL) { goto error; } py_transfer_owned(&result, &tmp); success: if (use_cache && (cache != NULL)) { if (PyDict_SetItem(cache, s, result) < 0) { PyErr_Clear(); /* clear any cache-related error */ } } return result; error: Py_XDECREF(varname); Py_XDECREF(varvalue); Py_XDECREF(filters); Py_XDECREF(result); return NULL; } 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); } static PyObject * fast_getvarl_s(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"config", "path", "namespace", "default", NULL}; PyObject *config; PyObject *path; PyObject *namespace = NULL; PyObject *default_ = NULL; PyObject *res = NULL; PyObject *tmp; 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; } tmp = _fast_getvarl(config, path, namespace, NULL, sstate); if (tmp == NULL) { goto handle_possible_keyerror; } res = PyObject_CallMethod(config, "substitute_variables_in_obj", "O", tmp); if (res == NULL) { py_clear_ref(&tmp); goto handle_possible_keyerror; } py_clear_ref(&tmp); return res; handle_possible_keyerror: if (PyErr_ExceptionMatches(PyExc_KeyError)) { if ((default_ == NULL) || py_object_is(default_, sstate->MARKER)) { /* fall through */ } else { PyErr_Clear(); return Py_NewRef(default_); } } /* fall through */ error: return NULL; } /** * Combination of py_getvar_s and _py_getvar_s_with_cache_info */ static PyObject * _fast_getvar_s(PyObject *config, PyObject *varname, PyObject *default_, struct speedups_state *sstate, int *cacheable) { PyObject *varname_b; /* always borrowed */ PyObject *namespace_b; /* always borrowed */ PyObject *splitted = NULL; PyObject *res; PyObject *tmp1; PyObject *tmp2; splitted = _fast_split_ns(varname, NULL, sstate); 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, 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); /* 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(splitted); return Py_NewRef(default_); } } /* fall through */ error: Py_XDECREF(splitted); return NULL; } static PyObject * fast_getvar(PyObject *self, PyObject *args) { PyObject *config; PyObject *varname; PyObject *default_; PyObject *varname_b; /* always borrowed */ PyObject *namespace_b; /* always borrowed */ PyObject *splitted = NULL; PyObject *res; PyObject *tmp1; 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; } splitted = _fast_split_ns(varname, NULL, sstate); 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; } res = _fast_getvarl(config, tmp1, NULL, default_, sstate); if (res == NULL) { py_clear_ref(&tmp1); goto error; } py_clear_ref(&tmp1); } else { tmp1 = PyTuple_New(1); if (tmp1 == NULL) { goto error; } PyTuple_SetItem(tmp1, 0, Py_NewRef(varname_b)); res = _fast_getvarl(config, tmp1, namespace_b, default_, sstate); if (res == NULL) {tmp1 = _fast_pathstr2path(varname_b, NULL, sstate); if (tmp1 == NULL) { goto error; } py_clear_ref(&tmp1); goto error; } py_clear_ref(&tmp1); } Py_DECREF(splitted); return res; error: 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_, sstate, &cacheable); } static PyObject * sync_MISSING(PyObject *self, PyObject *missing) { struct speedups_state *sstate; sstate = PyModule_GetState(self); if (sstate == NULL) { PyErr_SetString(PyExc_RuntimeError, "no module state available"); return NULL; } if (sstate->MISSING != NULL) { PyErr_SetString(PyExc_RuntimeError, "_MISSING already set"); return NULL; } sstate->MISSING = Py_NewRef(missing); Py_RETURN_NONE; } 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")}, {"fast_pathstr2path", fast_pathstr2path, METH_O, PyDoc_STR("C-implementation of configmix.pathstr2path")}, {"_fast_split_filters", fast_split_filters, METH_VARARGS, 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_getvarl_s", (PyCFunction)fast_getvarl_s, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvarl_s")}, {"_fast_getvar", fast_getvar, METH_VARARGS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvar")}, {"_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} }; #define STRINGIFY(s) #s #define XSTRINGIFY(s) STRINGIFY(s) static int speedups_exec(PyObject *module) { struct speedups_state *sstate = PyModule_GetState(module); if (sstate == NULL) { PyErr_SetString(PyExc_ImportError, "no module state available yet"); return -1; } PyModule_AddStringConstant(module, "__release__", release); PyModule_AddStringConstant(module, "__date__", date); PyModule_AddStringConstant(module, "__author__", "Franz Glasner"); #if defined(Py_LIMITED_API) PyModule_AddStringConstant(module, "Py_LIMITED_API", XSTRINGIFY(Py_LIMITED_API)); #endif sstate->DOT = PyUnicode_FromStringAndSize(".", 1); if (sstate->DOT == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->DOT)); sstate->QUOTE = PyUnicode_FromStringAndSize("%", 1); if (sstate->QUOTE == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->QUOTE)); sstate->NS_SEPARATOR = PyUnicode_FromStringAndSize(":", 1); if (sstate->NS_SEPARATOR == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->NS_SEPARATOR)); sstate->FILTER_SEPARATOR = PyUnicode_FromStringAndSize("|", 1); if (sstate->FILTER_SEPARATOR == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->FILTER_SEPARATOR)); sstate->FILTER_SEPARATOR_2 = PyUnicode_FromStringAndSize(",", 1); if (sstate->FILTER_SEPARATOR_2 == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->FILTER_SEPARATOR_2)); sstate->EMPTY_FILTER = PyUnicode_FromStringAndSize("Empty", 5); if (sstate->EMPTY_FILTER == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->EMPTY_FILTER)); sstate->NONE_FILTER = PyUnicode_FromStringAndSize("None", 4); if (sstate->NONE_FILTER == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->NONE_FILTER)); sstate->EMPTY_STR = PyUnicode_FromStringAndSize("", 0); if (sstate->EMPTY_STR == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->EMPTY_STR)); sstate->QUOTE_MAP = Py_BuildValue( "{IsIsIsIsIsIsIsIsIsIsIsIs}", 0x25, "%x25", /* QUOTE: % */ 0x2e, "%x2e", /* DOT: . */ 0x3a, "%x3a", /* NS_SEPARATOR: : */ 0x23, "%x23", /* COMMENT/anchor: # */ 0x7c, "%x7c", /* FILTER_SEPARATOR: | */ 0x22, "%x22", 0x27, "%x27", 0x7b, "%x7b", 0x7d, "%x7d", 0x5b, "%x5b", 0x5d, "%x5d", 0x7e, "%x7e"); /* tilde ~ */ if (sstate->QUOTE_MAP == NULL) { return -1; } sstate->STARTTOK = PyUnicode_FromStringAndSize("{{", 2); if (sstate->STARTTOK == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->STARTTOK)); sstate->ENDTOK = PyUnicode_FromStringAndSize("}}", 2); if (sstate->ENDTOK == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->ENDTOK)); sstate->ENDTOK_FILTER = PyUnicode_FromStringAndSize("|}}", 3); if (sstate->ENDTOK_FILTER == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->ENDTOK_FILTER)); sstate->REF_NAMESPACE = PyUnicode_FromStringAndSize("ref", 3); if (sstate->REF_NAMESPACE == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->REF_NAMESPACE)); sstate->DEL_VALUE = PyUnicode_FromStringAndSize("{{::DEL::}}", 11); if (sstate->DEL_VALUE == NULL) { return -1; } PyUnicode_InternInPlace(&(sstate->DEL_VALUE)); return 0; } static int speeeupds_traverse(PyObject *module, visitproc visit, void *arg) { struct speedups_state *sstate = PyModule_GetState(module); if (sstate != NULL) { Py_VISIT(sstate->DOT); Py_VISIT(sstate->QUOTE); Py_VISIT(sstate->NS_SEPARATOR); Py_VISIT(sstate->FILTER_SEPARATOR); Py_VISIT(sstate->FILTER_SEPARATOR_2); Py_VISIT(sstate->EMPTY_FILTER); Py_VISIT(sstate->NONE_FILTER); 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->ENDTOK_FILTER); Py_VISIT(sstate->REF_NAMESPACE); Py_VISIT(sstate->DEL_VALUE); } return 0; } static int speedups_clear(PyObject *module) { struct speedups_state *sstate = PyModule_GetState(module); if (sstate != NULL) { Py_CLEAR(sstate->DOT); Py_CLEAR(sstate->QUOTE); Py_CLEAR(sstate->NS_SEPARATOR); Py_CLEAR(sstate->FILTER_SEPARATOR); Py_CLEAR(sstate->FILTER_SEPARATOR_2); Py_CLEAR(sstate->EMPTY_FILTER); Py_CLEAR(sstate->NONE_FILTER); 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->ENDTOK_FILTER); Py_CLEAR(sstate->REF_NAMESPACE); Py_CLEAR(sstate->DEL_VALUE); } return 0; } static struct PyModuleDef_Slot speedups_slots[] = { {Py_mod_exec, speedups_exec}, {0, NULL} }; static struct PyModuleDef speedups_def = { PyModuleDef_HEAD_INIT, /* m_base */ "_speedups", /* m_name (relative) */ PyDoc_STR("Speedups for configmix"), /* m_doc */ sizeof(struct speedups_state), /* m_size */ speedups_methods, /* m_methods */ speedups_slots, /* m_slots */ speeeupds_traverse, /* m_traverse */ speedups_clear, /* m_clear */ NULL /* m_free */ }; PyMODINIT_FUNC PyInit__speedups(void) { /* * Use multi-phase extension module initialization (PEP 489). * This is Python 3.5+. */ return PyModuleDef_Init(&speedups_def); }
