Mercurial > hgrepos > Python > libs > ConfigMix
comparison configmix/_speedups.c @ 558:7a3c311991d7
An alternate C-implementation of fast_interpolate_variables() that uses the algorithm of the pure-Python implementation
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Wed, 05 Jan 2022 16:02:07 +0100 |
| parents | ba8f1295e1e2 |
| children | bb160a1e67d7 |
comparison
equal
deleted
inserted
replaced
| 557:ba8f1295e1e2 | 558:7a3c311991d7 |
|---|---|
| 689 } | 689 } |
| 690 | 690 |
| 691 | 691 |
| 692 static | 692 static |
| 693 PyObject * | 693 PyObject * |
| 694 fast_interpolate_variables(PyObject *self, PyObject *args) | 694 fast_interpolate_variables_old(PyObject *self, PyObject *args) |
| 695 { | 695 { |
| 696 PyObject *config; | 696 PyObject *config; |
| 697 PyObject *s; | 697 PyObject *s; |
| 698 PyObject *cache; | 698 PyObject *cache; |
| 699 | 699 |
| 958 } | 958 } |
| 959 | 959 |
| 960 | 960 |
| 961 static | 961 static |
| 962 PyObject * | 962 PyObject * |
| 963 fast_interpolate_variables(PyObject *self, PyObject *args) | |
| 964 { | |
| 965 PyObject *config; | |
| 966 PyObject *s; | |
| 967 PyObject *cache; | |
| 968 | |
| 969 Py_ssize_t s_len; | |
| 970 Py_ssize_t start, rest, end; | |
| 971 PyObject *tmp; | |
| 972 PyObject *tmp2; | |
| 973 PyObject *result = NULL; | |
| 974 PyObject *varname = NULL; | |
| 975 PyObject *varvalue = NULL; | |
| 976 PyObject *filters = NULL; | |
| 977 PyObject *err_type; | |
| 978 PyObject *err_value; | |
| 979 PyObject *err_tb; | |
| 980 int use_cache, cacheable; | |
| 981 struct speedups_state *sstate; | |
| 982 | |
| 983 if (!PyArg_UnpackTuple(args, "s", 3, 3, &config, &s, &cache)) { | |
| 984 return NULL; | |
| 985 } | |
| 986 s_len = PyUnicode_GetLength(s); /* also an implicit type check */ | |
| 987 if (s_len < 0) { | |
| 988 return NULL; | |
| 989 } | |
| 990 if (s_len < 4) { | |
| 991 Py_INCREF(s); | |
| 992 return s; | |
| 993 } | |
| 994 | |
| 995 sstate = PyModule_GetState(self); | |
| 996 if (sstate == NULL) { | |
| 997 PyErr_SetString(PyExc_RuntimeError, "no module state available"); | |
| 998 return NULL; | |
| 999 } | |
| 1000 | |
| 1001 start = PyUnicode_Find(s, sstate->STARTTOK, 0, s_len, 1); | |
| 1002 if (start == -2) { | |
| 1003 return NULL; | |
| 1004 } | |
| 1005 if (start == -1) { | |
| 1006 Py_INCREF(s); | |
| 1007 return s; | |
| 1008 } | |
| 1009 | |
| 1010 result = PyDict_GetItem(cache, s); /* borrowed */ | |
| 1011 if (result != NULL) { | |
| 1012 if (result == sstate->MISSING) { | |
| 1013 return PyErr_Format( | |
| 1014 PyExc_KeyError, | |
| 1015 "Cannot interpolate variables in string %R (cached)", | |
| 1016 s); | |
| 1017 } | |
| 1018 else { | |
| 1019 Py_INCREF(result); /* need ownership */ | |
| 1020 return result; | |
| 1021 } | |
| 1022 } | |
| 1023 | |
| 1024 result = PyList_New(0); | |
| 1025 if (result == 0) { | |
| 1026 return NULL; | |
| 1027 } | |
| 1028 | |
| 1029 rest = 0; | |
| 1030 use_cache = 1; | |
| 1031 | |
| 1032 while (start != -1) { | |
| 1033 if (rest < start) { | |
| 1034 tmp = PyUnicode_Substring(s, rest, start); | |
| 1035 if (tmp == NULL) { | |
| 1036 goto error; | |
| 1037 } | |
| 1038 if (PyList_Append(result, tmp) < 0) { | |
| 1039 Py_DECREF(tmp); | |
| 1040 goto error; | |
| 1041 } | |
| 1042 Py_DECREF(tmp); tmp = NULL; | |
| 1043 } | |
| 1044 end = PyUnicode_Find(s, sstate->ENDTOK, start+2, s_len, 1); | |
| 1045 if (end == -2) { | |
| 1046 goto error; | |
| 1047 } | |
| 1048 if (end == -1) { | |
| 1049 rest = start; | |
| 1050 break; | |
| 1051 } | |
| 1052 | |
| 1053 varname = PyUnicode_Substring(s, start+2, end); /* 2 == len(STARTTOK) */ | |
| 1054 if (varname == NULL) { | |
| 1055 goto error; | |
| 1056 } | |
| 1057 | |
| 1058 tmp = _fast_split_filters(varname, NULL, sstate); | |
| 1059 if (tmp == NULL) { | |
| 1060 goto error; | |
| 1061 } | |
| 1062 if (PyTuple_Size(tmp) != 2) { | |
| 1063 PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected"); | |
| 1064 Py_DECREF(tmp); | |
| 1065 goto error; | |
| 1066 } | |
| 1067 /* Unpack the result tuple */ | |
| 1068 tmp2 = PyTuple_GetItem(tmp, 0); /* borrowed -- cannot fail */ | |
| 1069 Py_DECREF(varname); | |
| 1070 Py_INCREF(tmp2); | |
| 1071 varname = tmp2; tmp2 = NULL; | |
| 1072 filters = PyTuple_GetItem(tmp, 1); /* borrowed -- cannot fail */ | |
| 1073 Py_INCREF(filters); | |
| 1074 Py_DECREF(tmp); tmp = NULL; | |
| 1075 | |
| 1076 tmp = PyObject_CallMethod( | |
| 1077 config, "_getvar_s_with_cache_info", "O", varname); | |
| 1078 if (tmp == NULL) { | |
| 1079 if (PyErr_ExceptionMatches(PyExc_KeyError)) { | |
| 1080 cacheable = 1; | |
| 1081 if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) { | |
| 1082 PyErr_Clear(); | |
| 1083 Py_INCREF(Py_None); | |
| 1084 varvalue = Py_None; | |
| 1085 } | |
| 1086 else { | |
| 1087 if (PySequence_Contains(filters, sstate->EMPTY_FILTER) == 1) { | |
| 1088 PyErr_Clear(); | |
| 1089 Py_INCREF(sstate->EMPTY_STR); | |
| 1090 varvalue = sstate->EMPTY_STR; | |
| 1091 } | |
| 1092 else { | |
| 1093 PyErr_Fetch(&err_type, &err_value, &err_tb); | |
| 1094 /* this does NOT steal */ | |
| 1095 PyDict_SetItem(cache, s, sstate->MISSING); | |
| 1096 PyErr_Restore(err_type, err_value, err_tb); | |
| 1097 goto error; | |
| 1098 } | |
| 1099 } | |
| 1100 } | |
| 1101 else { | |
| 1102 /* other exception/error than KeyError */ | |
| 1103 goto error; | |
| 1104 } | |
| 1105 } | |
| 1106 else { | |
| 1107 if (PyTuple_Size(tmp) != 2) { | |
| 1108 Py_DECREF(tmp); | |
| 1109 PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected"); | |
| 1110 goto error; | |
| 1111 } | |
| 1112 /* unpack the result */ | |
| 1113 varvalue = PyTuple_GetItem(tmp, 0); /* borrowed -- but want own */ | |
| 1114 Py_INCREF(varvalue); | |
| 1115 cacheable = PyObject_IsTrue(PyTuple_GetItem(tmp, 1)); | |
| 1116 Py_DECREF(tmp); tmp = NULL; | |
| 1117 } | |
| 1118 | |
| 1119 if (!cacheable) { | |
| 1120 use_cache = 0; | |
| 1121 } | |
| 1122 | |
| 1123 Py_DECREF(varname); varname = NULL; | |
| 1124 | |
| 1125 tmp = PyObject_CallMethod( | |
| 1126 config, "_apply_filters", "OO", filters, varvalue); | |
| 1127 if (tmp == NULL) { | |
| 1128 goto error; | |
| 1129 } | |
| 1130 Py_DECREF(varvalue); | |
| 1131 varvalue = tmp; tmp = NULL; | |
| 1132 | |
| 1133 Py_DECREF(filters); filters = NULL; | |
| 1134 | |
| 1135 rest = end + 2; /* 2 == len(ENDTOK) */ | |
| 1136 | |
| 1137 /* | |
| 1138 * Dont apply and type conversions to the variable value if | |
| 1139 * the whole `s` is just one expansion | |
| 1140 */ | |
| 1141 if ((start == 0) && (rest == s_len)) { | |
| 1142 Py_DECREF(result); | |
| 1143 result = varvalue; varvalue = NULL; | |
| 1144 goto success; /* break out early */ | |
| 1145 } | |
| 1146 | |
| 1147 /* Handle None like the empty string */ | |
| 1148 if (varvalue != Py_None) { | |
| 1149 tmp = PyObject_Str(varvalue); | |
| 1150 if (tmp == NULL) { | |
| 1151 goto error; | |
| 1152 } | |
| 1153 if (PyList_Append(result, tmp) < 0) { | |
| 1154 Py_DECREF(tmp); | |
| 1155 goto error; | |
| 1156 } | |
| 1157 Py_DECREF(tmp); tmp = NULL; | |
| 1158 } | |
| 1159 | |
| 1160 /* don't re-evaluate because `self.getvar_s()` expands already */ | |
| 1161 start = PyUnicode_Find(s, sstate->STARTTOK, rest, s_len, 1); | |
| 1162 if (start == -2) { | |
| 1163 goto error; | |
| 1164 } | |
| 1165 } | |
| 1166 | |
| 1167 if (rest < s_len) { | |
| 1168 tmp = PyUnicode_Substring(s, rest, s_len); | |
| 1169 if (tmp == NULL) { | |
| 1170 goto error; | |
| 1171 } | |
| 1172 if (PyList_Append(result, tmp) < 0) { | |
| 1173 Py_DECREF(tmp); | |
| 1174 goto error; | |
| 1175 } | |
| 1176 Py_DECREF(tmp); tmp = NULL; | |
| 1177 } | |
| 1178 | |
| 1179 tmp = PyUnicode_Join(sstate->EMPTY_STR, result); | |
| 1180 if (tmp == NULL) { | |
| 1181 goto error; | |
| 1182 } | |
| 1183 Py_DECREF(result); | |
| 1184 result = tmp; tmp = NULL; | |
| 1185 | |
| 1186 success: | |
| 1187 if (use_cache) { | |
| 1188 if (PyDict_SetItem(cache, s, result) < 0) { | |
| 1189 PyErr_Clear(); /* clear any cache-related error */ | |
| 1190 } | |
| 1191 } | |
| 1192 return result; | |
| 1193 | |
| 1194 error: | |
| 1195 Py_XDECREF(varname); | |
| 1196 Py_XDECREF(varvalue); | |
| 1197 Py_XDECREF(filters); | |
| 1198 Py_XDECREF(result); | |
| 1199 return NULL; | |
| 1200 } | |
| 1201 | |
| 1202 | |
| 1203 static | |
| 1204 PyObject * | |
| 963 sync_MISSING(PyObject *self, PyObject *missing) | 1205 sync_MISSING(PyObject *self, PyObject *missing) |
| 964 { | 1206 { |
| 965 struct speedups_state *sstate; | 1207 struct speedups_state *sstate; |
| 966 | 1208 |
| 967 sstate = PyModule_GetState(self); | 1209 sstate = PyModule_GetState(self); |
