comparison 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
comparison
equal deleted inserted replaced
602:a2fff0d93d83 603:e55a42144ba9
28 PyObject *EMPTY_FILTER; 28 PyObject *EMPTY_FILTER;
29 PyObject *NONE_FILTER; 29 PyObject *NONE_FILTER;
30 PyObject *EMPTY_STR; 30 PyObject *EMPTY_STR;
31 PyObject *QUOTE_MAP; 31 PyObject *QUOTE_MAP;
32 PyObject *MISSING; 32 PyObject *MISSING;
33 PyObject *MARKER;
33 PyObject *STARTTOK; 34 PyObject *STARTTOK;
34 PyObject *ENDTOK; 35 PyObject *ENDTOK;
36 PyObject *REF_NAMESPACE;
35 }; 37 };
38
39
40 static PyObject * _fast_getvar_s(PyObject *, PyObject *, PyObject *, PyObject *, struct speedups_state *, int*);
36 41
37 42
38 static 43 static
39 int 44 int
40 _hex2ucs4(PyObject *s, Py_ssize_t end, Py_UCS4 *result) 45 _hex2ucs4(PyObject *s, Py_ssize_t end, Py_UCS4 *result)
833 varname = Py_NewRef(PyTuple_GetItem(tmp, 0)); 838 varname = Py_NewRef(PyTuple_GetItem(tmp, 0));
834 /* borrowed -- cannot fail -- want ownership */ 839 /* borrowed -- cannot fail -- want ownership */
835 filters = Py_NewRef(PyTuple_GetItem(tmp, 1)); 840 filters = Py_NewRef(PyTuple_GetItem(tmp, 1));
836 py_clear_ref(&tmp); 841 py_clear_ref(&tmp);
837 842
838 tmp = PyObject_CallMethod( 843 varvalue = _fast_getvar_s(config, varname, NULL, self, sstate, &cacheable);
839 config, "_getvar_s_with_cache_info", "O", varname); 844 if (varvalue == NULL) {
840 if (tmp == NULL) {
841 if (PyErr_ExceptionMatches(PyExc_KeyError)) { 845 if (PyErr_ExceptionMatches(PyExc_KeyError)) {
842 cacheable = 1; 846 cacheable = 1;
843 if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) { 847 if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) {
844 PyErr_Clear(); 848 PyErr_Clear();
845 varvalue = Py_NewRef(Py_None); 849 varvalue = Py_NewRef(Py_None);
861 else { 865 else {
862 /* other exception/error than KeyError */ 866 /* other exception/error than KeyError */
863 goto error; 867 goto error;
864 } 868 }
865 } 869 }
866 else {
867 if (PyTuple_Size(tmp) != 2) {
868 py_clear_ref(&tmp);
869 PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected");
870 goto error;
871 }
872 /* unpack the result */
873 /* borrowed -- cannot fail -- but want ownership */
874 varvalue = Py_NewRef(PyTuple_GetItem(tmp, 0));
875 cacheable = PyObject_IsTrue(PyTuple_GetItem(tmp, 1));
876 py_clear_ref(&tmp);
877 }
878 870
879 if (!cacheable) { 871 if (!cacheable) {
880 use_cache = 0; 872 use_cache = 0;
881 } 873 }
882 874
1063 varname = Py_NewRef(PyTuple_GetItem(tmp, 0)); 1055 varname = Py_NewRef(PyTuple_GetItem(tmp, 0));
1064 /* borrowed -- cannot fail -- need ownership */ 1056 /* borrowed -- cannot fail -- need ownership */
1065 filters = Py_NewRef(PyTuple_GetItem(tmp, 1)); 1057 filters = Py_NewRef(PyTuple_GetItem(tmp, 1));
1066 py_clear_ref(&tmp); 1058 py_clear_ref(&tmp);
1067 1059
1068 tmp = PyObject_CallMethod( 1060 varvalue = _fast_getvar_s(config, varname, NULL, self, sstate, &cacheable);
1069 config, "_getvar_s_with_cache_info", "O", varname); 1061
1070 if (tmp == NULL) { 1062 if (varvalue == NULL) {
1071 if (PyErr_ExceptionMatches(PyExc_KeyError)) { 1063 if (PyErr_ExceptionMatches(PyExc_KeyError)) {
1072 cacheable = 1; 1064 cacheable = 1;
1073 if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) { 1065 if (PySequence_Contains(filters, sstate->NONE_FILTER) == 1) {
1074 PyErr_Clear(); 1066 PyErr_Clear();
1075 varvalue = Py_NewRef(Py_None); 1067 varvalue = Py_NewRef(Py_None);
1093 else { 1085 else {
1094 /* other exception/error than KeyError */ 1086 /* other exception/error than KeyError */
1095 goto error; 1087 goto error;
1096 } 1088 }
1097 } 1089 }
1098 else {
1099 if (PyTuple_Size(tmp) != 2) {
1100 py_clear_ref(&tmp);
1101 PyErr_SetString(PyExc_TypeError, "tuple of size 2 expected");
1102 goto error;
1103 }
1104 /* unpack the result */
1105 /* borrowed -- but want own */
1106 varvalue = Py_NewRef(PyTuple_GetItem(tmp, 0));
1107 cacheable = PyObject_IsTrue(PyTuple_GetItem(tmp, 1));
1108 py_clear_ref(&tmp);
1109 }
1110 1090
1111 if (!cacheable) { 1091 if (!cacheable) {
1112 use_cache = 0; 1092 use_cache = 0;
1113 } 1093 }
1114 1094
1189 } 1169 }
1190 1170
1191 1171
1192 static 1172 static
1193 PyObject * 1173 PyObject *
1194 sync_MISSING(PyObject *self, PyObject *missing) 1174 _fast_getvarl(PyObject *config, PyObject *path, PyObject *namespace, PyObject *default_, struct speedups_state *sstate)
1195 { 1175 {
1176 PyObject *varvalue;
1177 PyObject *lookupfn = NULL;
1178
1179 if ((namespace == NULL) || PyObject_Not(namespace)) {
1180 lookupfn = PyObject_GetAttrString(config, "_lookupvar");
1181 if (lookupfn == NULL) {
1182 goto error;
1183 }
1184 }
1185 else {
1186 int ns_equals_ref = PyUnicode_Compare(namespace, sstate->REF_NAMESPACE);
1187 if ((ns_equals_ref < 0) && PyErr_Occurred()) {
1188 return NULL;
1189 }
1190 if (ns_equals_ref == 0) {
1191 lookupfn = PyObject_GetAttrString(config, "_lookupref");
1192 if (lookupfn == NULL) {
1193 goto error;
1194 }
1195 }
1196 else {
1197 /* lookup_varns */
1198 /* this is borrowed */
1199 PyObject *cfg_vars_mod = PyImport_AddModule("configmix.variables");
1200 if (cfg_vars_mod == NULL) {
1201 goto error;
1202 }
1203 lookupfn = PyObject_CallMethod(cfg_vars_mod, "lookup_varns", "O", namespace);
1204 if (lookupfn == NULL) {
1205 goto handle_possible_keyerror;
1206 }
1207 }
1208 }
1209 varvalue = PyObject_CallObject(lookupfn, path);
1210 if (varvalue == NULL) {
1211 goto handle_possible_keyerror;
1212 }
1213 Py_DECREF(lookupfn);
1214 return varvalue;
1215
1216 handle_possible_keyerror:
1217 if (PyErr_ExceptionMatches(PyExc_KeyError)) {
1218 if ((default_ == NULL) || py_object_is(default_, sstate->MARKER)) {
1219 PyErr_Format(PyExc_KeyError, "Variable %R not found", path);
1220 /* fall through */
1221 }
1222 else {
1223 PyErr_Clear();
1224 Py_XDECREF(lookupfn);
1225 return Py_NewRef(default_);
1226 }
1227 }
1228 /* fall through */
1229 error:
1230 Py_XDECREF(lookupfn);
1231 return NULL;
1232 }
1233
1234
1235 static
1236 PyObject *
1237 fast_getvarl(PyObject *self, PyObject *args, PyObject *kwds)
1238 {
1239 static char *kwlist[] = {"config", "path", "namespace", "default", NULL};
1240 PyObject *path;
1241 PyObject *config;
1242 PyObject *namespace = NULL;
1243 PyObject *default_ = NULL;
1244
1196 struct speedups_state *sstate; 1245 struct speedups_state *sstate;
1197 1246
1247 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO!|$OO", kwlist, &config, &PyTuple_Type, &path, &namespace, &default_)) {
1248
1249 return NULL;
1250 }
1198 sstate = PyModule_GetState(self); 1251 sstate = PyModule_GetState(self);
1199 if (sstate == NULL) { 1252 if (sstate == NULL) {
1200 PyErr_SetString(PyExc_RuntimeError, "no module state available"); 1253 PyErr_SetString(PyExc_RuntimeError, "no module state available");
1201 return NULL; 1254 return NULL;
1202 } 1255 }
1256 return _fast_getvarl(config, path, namespace, default_, sstate);
1257 }
1258
1259
1260 /**
1261 * Mixture of py_getvar_s and _py_getvar_s_with_cache_info
1262 */
1263 static
1264 PyObject *
1265 _fast_getvar_s(PyObject *config, PyObject *varname, PyObject *default_, PyObject *self, struct speedups_state *sstate, int *cacheable)
1266 {
1267 PyObject *varname_b; /* always borrowed */
1268 PyObject *namespace_b; /* always borrowed */
1269 PyObject *splitted = NULL;
1270 PyObject *res = NULL;
1271 PyObject *tmp1;
1272 PyObject *tmp2;
1273
1274 splitted = fast_split_ns(self, varname);
1275 if (splitted == NULL) {
1276 goto error;
1277 }
1278 namespace_b = PyTuple_GetItem(splitted, 0); /* borrowed */
1279 varname_b = PyTuple_GetItem(splitted, 1); /* borrowed */
1280
1281 if (PyObject_Not(namespace_b)) {
1282 tmp1 = _fast_pathstr2path(varname_b, NULL, sstate);
1283 if (tmp1 == NULL) {
1284 goto error;
1285 }
1286 tmp2 = _fast_getvarl(config, tmp1, NULL, default_, sstate);
1287 if (tmp2 == NULL) {
1288 py_clear_ref(&tmp1);
1289 goto handle_possible_keyerror;
1290 }
1291 py_clear_ref(&tmp1);
1292 res = PyObject_CallMethod(config, "substitute_variables_in_obj", "O", tmp2);
1293 if (res == NULL) {
1294 py_clear_ref(&tmp2);
1295 goto handle_possible_keyerror;
1296 }
1297 py_clear_ref(&tmp2);
1298 /* no namespace -> cacheable */
1299 *cacheable = 1;
1300 }
1301 else {
1302 tmp1 = PyTuple_New(1);
1303 if (tmp1 == NULL) {
1304 goto error;
1305 }
1306 PyTuple_SetItem(tmp1, 0, Py_NewRef(varname_b));
1307 tmp2 = _fast_getvarl(config, tmp1, namespace_b, NULL, sstate);
1308 if (tmp2 == NULL) {
1309 py_clear_ref(&tmp1);
1310 goto handle_possible_keyerror;
1311 }
1312 py_clear_ref(&tmp1);
1313 res = PyObject_CallMethod(config, "substitute_variables_in_obj", "O", tmp2);
1314 if (res == NULL) {
1315 py_clear_ref(&tmp2);
1316 goto handle_possible_keyerror;
1317 }
1318 py_clear_ref(&tmp2);
1319 /* results from namespaced lookups are currently not cacheable */
1320 *cacheable = 0;
1321 }
1322
1323 /* free splitted last because of using borrowed refs from it */
1324 Py_DECREF(splitted);
1325 return res;
1326
1327 handle_possible_keyerror:
1328 if (PyErr_ExceptionMatches(PyExc_KeyError)) {
1329 if ((default_ == NULL) || py_object_is(default_, sstate->MARKER)) {
1330 /* fall through */
1331 }
1332 else {
1333 PyErr_Clear();
1334 Py_XDECREF(res);
1335 Py_XDECREF(splitted);
1336 return Py_NewRef(default_);
1337 }
1338 }
1339 /* fall through */
1340
1341 error:
1342 Py_XDECREF(res);
1343 Py_XDECREF(splitted);
1344 return NULL;
1345 }
1346
1347
1348 static
1349 PyObject *
1350 fast_getvar_s(PyObject *self, PyObject *args)
1351 {
1352 PyObject *config;
1353 PyObject *varname;
1354 PyObject *default_;
1355 int cacheable;
1356 struct speedups_state *sstate;
1357
1358 if (!PyArg_UnpackTuple(args, "config", 3, 3, &config, &varname, &default_)) {
1359 return NULL;
1360 }
1361
1362 sstate = PyModule_GetState(self);
1363 if (sstate == NULL) {
1364 PyErr_SetString(PyExc_RuntimeError, "no module state available");
1365 return NULL;
1366 }
1367 return _fast_getvar_s(config, varname, default_, self, sstate, &cacheable);
1368 }
1369
1370
1371 static
1372 PyObject *
1373 sync_MISSING(PyObject *self, PyObject *missing)
1374 {
1375 struct speedups_state *sstate;
1376
1377 sstate = PyModule_GetState(self);
1378 if (sstate == NULL) {
1379 PyErr_SetString(PyExc_RuntimeError, "no module state available");
1380 return NULL;
1381 }
1203 if (sstate->MISSING != NULL) { 1382 if (sstate->MISSING != NULL) {
1204 PyErr_SetString(PyExc_RuntimeError, "_MISSING already set"); 1383 PyErr_SetString(PyExc_RuntimeError, "_MISSING already set");
1205 return NULL; 1384 return NULL;
1206 } 1385 }
1207 sstate->MISSING = Py_NewRef(missing); 1386 sstate->MISSING = Py_NewRef(missing);
1387 Py_RETURN_NONE;
1388 }
1389
1390
1391 static
1392 PyObject *
1393 sync_MARKER(PyObject *self, PyObject *marker)
1394 {
1395 struct speedups_state *sstate;
1396
1397 sstate = PyModule_GetState(self);
1398 if (sstate == NULL) {
1399 PyErr_SetString(PyExc_RuntimeError, "no module state available");
1400 return NULL;
1401 }
1402 if (sstate->MARKER != NULL) {
1403 PyErr_SetString(PyExc_RuntimeError, "_MARKER already set");
1404 return NULL;
1405 }
1406 sstate->MARKER = Py_NewRef(marker);
1208 Py_RETURN_NONE; 1407 Py_RETURN_NONE;
1209 } 1408 }
1210 1409
1211 1410
1212 static struct PyMethodDef speedups_methods[] = { 1411 static struct PyMethodDef speedups_methods[] = {
1214 {"fast_quote", fast_quote, METH_O, PyDoc_STR("C-implementation of configmix.quote")}, 1413 {"fast_quote", fast_quote, METH_O, PyDoc_STR("C-implementation of configmix.quote")},
1215 {"fast_pathstr2path", fast_pathstr2path, METH_O, PyDoc_STR("C-implementation of configmix.pathstr2path")}, 1414 {"fast_pathstr2path", fast_pathstr2path, METH_O, PyDoc_STR("C-implementation of configmix.pathstr2path")},
1216 {"_fast_split_filters", fast_split_filters, METH_O, PyDoc_STR("C-implementation of configmix.config._split_filters")}, 1415 {"_fast_split_filters", fast_split_filters, METH_O, PyDoc_STR("C-implementation of configmix.config._split_filters")},
1217 {"_fast_split_ns", fast_split_ns, METH_O, PyDoc_STR("C-implementation of configmix.config._split_ns")}, 1416 {"_fast_split_ns", fast_split_ns, METH_O, PyDoc_STR("C-implementation of configmix.config._split_ns")},
1218 {"_fast_interpolate_variables", fast_interpolate_variables, METH_VARARGS, PyDoc_STR("C-implementation of configmix.config.Configuration.interpolate_variables")}, 1417 {"_fast_interpolate_variables", fast_interpolate_variables, METH_VARARGS, PyDoc_STR("C-implementation of configmix.config.Configuration.interpolate_variables")},
1418 {"_fast_getvarl", (PyCFunction)fast_getvarl, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvarl")},
1419 {"_fast_getvar_s", fast_getvar_s, METH_VARARGS, PyDoc_STR("C-Implementation of configmix.config.Configuration.getvar_s")},
1219 {"_sync_MISSING", sync_MISSING, METH_O, PyDoc_STR("Internal function to easily sync the _MISSING object with configmix.config")}, 1420 {"_sync_MISSING", sync_MISSING, METH_O, PyDoc_STR("Internal function to easily sync the _MISSING object with configmix.config")},
1220 1421 {"_sync_MARKER", sync_MARKER, METH_O, PyDoc_STR("Internal function to easily sync the _MARKER object with configmix.config")},
1221 {NULL, NULL, 0, NULL} 1422 {NULL, NULL, 0, NULL}
1222 }; 1423 };
1223 1424
1224 #define STRINGIFY(s) #s 1425 #define STRINGIFY(s) #s
1225 #define XSTRINGIFY(s) STRINGIFY(s) 1426 #define XSTRINGIFY(s) STRINGIFY(s)
1312 if (sstate->ENDTOK == NULL) { 1513 if (sstate->ENDTOK == NULL) {
1313 return -1; 1514 return -1;
1314 } 1515 }
1315 PyUnicode_InternInPlace(&(sstate->ENDTOK)); 1516 PyUnicode_InternInPlace(&(sstate->ENDTOK));
1316 1517
1518 sstate->REF_NAMESPACE = PyUnicode_FromStringAndSize("ref", 3);
1519 if (sstate->REF_NAMESPACE == NULL) {
1520 return -1;
1521 }
1522 PyUnicode_InternInPlace(&(sstate->REF_NAMESPACE));
1523
1317 return 0; 1524 return 0;
1318 } 1525 }
1319 1526
1320 1527
1321 static 1528 static
1332 Py_VISIT(sstate->EMPTY_FILTER); 1539 Py_VISIT(sstate->EMPTY_FILTER);
1333 Py_VISIT(sstate->NONE_FILTER); 1540 Py_VISIT(sstate->NONE_FILTER);
1334 Py_VISIT(sstate->EMPTY_STR); 1541 Py_VISIT(sstate->EMPTY_STR);
1335 Py_VISIT(sstate->QUOTE_MAP); 1542 Py_VISIT(sstate->QUOTE_MAP);
1336 Py_VISIT(sstate->MISSING); 1543 Py_VISIT(sstate->MISSING);
1544 Py_VISIT(sstate->MARKER);
1337 Py_VISIT(sstate->STARTTOK); 1545 Py_VISIT(sstate->STARTTOK);
1338 Py_VISIT(sstate->ENDTOK); 1546 Py_VISIT(sstate->ENDTOK);
1547 Py_VISIT(sstate->REF_NAMESPACE);
1339 } 1548 }
1340 return 0; 1549 return 0;
1341 } 1550 }
1342 1551
1343 1552
1355 Py_CLEAR(sstate->EMPTY_FILTER); 1564 Py_CLEAR(sstate->EMPTY_FILTER);
1356 Py_CLEAR(sstate->NONE_FILTER); 1565 Py_CLEAR(sstate->NONE_FILTER);
1357 Py_CLEAR(sstate->EMPTY_STR); 1566 Py_CLEAR(sstate->EMPTY_STR);
1358 Py_CLEAR(sstate->QUOTE_MAP); 1567 Py_CLEAR(sstate->QUOTE_MAP);
1359 Py_CLEAR(sstate->MISSING); 1568 Py_CLEAR(sstate->MISSING);
1569 Py_CLEAR(sstate->MARKER);
1360 Py_CLEAR(sstate->STARTTOK); 1570 Py_CLEAR(sstate->STARTTOK);
1361 Py_CLEAR(sstate->ENDTOK); 1571 Py_CLEAR(sstate->ENDTOK);
1572 Py_CLEAR(sstate->REF_NAMESPACE);
1362 } 1573 }
1363 return 0; 1574 return 0;
1364 } 1575 }
1365 1576
1366 1577