comparison configmix/_speedups.c @ 552:39e5d07d8dbc

Provide a C implementation of configmix.config._split_filters. This is needed as precondition for implementation interpolate_variables in C also. Currently the speedup is not measurable but it does not hurt also. Also provide some unit-tests for _split_filters().
author Franz Glasner <fzglas.hg@dom66.de>
date Sun, 02 Jan 2022 20:40:09 +0100
parents 79db28e879f8
children 9d2bd411f5c5
comparison
equal deleted inserted replaced
551:4c968c5cfce6 552:39e5d07d8dbc
20 */ 20 */
21 struct speedups_state { 21 struct speedups_state {
22 PyObject *DOT; 22 PyObject *DOT;
23 PyObject *QUOTE; 23 PyObject *QUOTE;
24 PyObject *NS_SEPARATOR; 24 PyObject *NS_SEPARATOR;
25 PyObject *FILTER_SEPARATOR;
25 PyObject *EMPTY_STR; 26 PyObject *EMPTY_STR;
26 PyObject *QUOTE_MAP; 27 PyObject *QUOTE_MAP;
27 }; 28 };
28 29
29 30
249 #endif /* Py_LIMITED_API */ 250 #endif /* Py_LIMITED_API */
250 251
251 252
252 static 253 static
253 PyObject * 254 PyObject *
254 _fast_unquote(PyObject *self, PyObject *s, Py_ssize_t s_len, struct speedups_state *sstate) 255 _fast_unquote(PyObject *s, Py_ssize_t s_len, PyObject *self, struct speedups_state *sstate)
255 { 256 {
256 Py_ssize_t find; 257 Py_ssize_t find;
257 Py_ssize_t parts_len; 258 Py_ssize_t parts_len;
258 PyObject *res; 259 PyObject *res;
259 PyObject *res_parts = NULL; 260 PyObject *res_parts = NULL;
395 396
396 static 397 static
397 PyObject * 398 PyObject *
398 fast_unquote(PyObject *self, PyObject *s) 399 fast_unquote(PyObject *self, PyObject *s)
399 { 400 {
400 return _fast_unquote(self, s, -1, NULL); 401 return _fast_unquote(s, -1, self, NULL);
401 } 402 }
402 403
403 404
404 static 405 static
405 PyObject * 406 PyObject *
497 if (res == NULL) { 498 if (res == NULL) {
498 goto error; 499 goto error;
499 } 500 }
500 for (i=0; i < parts_len; i++) { 501 for (i=0; i < parts_len; i++) {
501 o = PyList_GetItem(parts, i); /* borrowed */ 502 o = PyList_GetItem(parts, i); /* borrowed */
502 u = _fast_unquote(self, o, -1, sstate); 503 u = _fast_unquote(o, -1, NULL, sstate);
503 if (u == NULL) { 504 if (u == NULL) {
504 goto error; 505 goto error;
505 } 506 }
506 PyTuple_SetItem(res, i, u); /* steals */ 507 PyTuple_SetItem(res, i, u); /* steals */
507 } 508 }
511 512
512 error: 513 error:
513 Py_XDECREF(parts); 514 Py_XDECREF(parts);
514 Py_XDECREF(res); 515 Py_XDECREF(res);
515 return NULL; 516 return NULL;
517 }
518
519
520 static
521 PyObject *
522 _fast_split_filters(PyObject *varname, PyObject *self, struct speedups_state *sstate)
523 {
524 Py_ssize_t varname_len;
525 Py_ssize_t sep;
526 PyObject *res = NULL;
527 PyObject *filters = NULL;
528 PyObject *name = NULL;
529 PyObject *tmp;
530
531 varname_len = PyUnicode_GetLength(varname);
532 if (varname_len < 0) {
533 return NULL;
534 }
535 if (varname_len == 0) {
536 sep = -1;
537 }
538 else {
539 sep = PyUnicode_FindChar(varname, '|', 0, varname_len, 1);
540 if (sep == -2) {
541 return NULL;
542 }
543 }
544 if (sep == -1) {
545 res = PyTuple_New(2);
546 if (res == NULL) {
547 goto error;
548 }
549 Py_INCREF(varname); /* because PyTuple_SetItem steals */
550 PyTuple_SetItem(res, 0, varname); /* steals */
551 filters = PyList_New(0);
552 if (filters == NULL) {
553 goto error;
554 }
555 PyTuple_SetItem(res, 1, filters); /* steals */
556 return res;
557 }
558 name = PyUnicode_Substring(varname, 0, sep);
559 if (name == NULL) {
560 goto error;
561 }
562 tmp = PyObject_CallMethod(name, "rstrip", NULL);
563 if (tmp == NULL) {
564 goto error;
565 }
566 Py_DECREF(name);
567 name = tmp;
568
569 filters = PyUnicode_Substring(varname, sep+1, varname_len);
570 if (filters == NULL) {
571 goto error;
572 }
573 tmp = PyObject_CallMethod(filters, "strip", NULL);
574 if (tmp == NULL) {
575 goto error;
576 }
577 Py_DECREF(filters);
578 filters = tmp;
579
580 if (PyObject_Not(filters)) {
581 Py_DECREF(filters); filters = NULL;
582
583 res = PyTuple_New(2);
584 if (res == NULL) {
585 goto error;
586 }
587 PyTuple_SetItem(res, 0, name); /* steals */
588 name = NULL; /* no ownership any more */
589 filters = PyList_New(0);
590 if (filters == NULL) {
591 goto error;
592 }
593 PyTuple_SetItem(res, 1, filters); /* steals */
594 return res;
595 }
596
597 if (sstate == NULL) {
598 sstate = PyModule_GetState(self);
599 if (sstate == NULL) {
600 PyErr_SetString(PyExc_RuntimeError, "no module state available");
601 goto error;
602 }
603 }
604
605 tmp = PyUnicode_Split(filters, sstate->FILTER_SEPARATOR, -1);
606 if (tmp == NULL) {
607 goto error;
608 }
609 Py_DECREF(filters);
610 filters = tmp;
611
612 res = PyTuple_New(2);
613 if (res == NULL) {
614 goto error;
615 }
616 PyTuple_SetItem(res, 0, name); /* steals -- ownership changed */
617 PyTuple_SetItem(res, 1, filters); /* steals -- ownership changed */
618 return res;
619
620 error:
621 Py_XDECREF(res);
622 Py_XDECREF(filters);
623 Py_XDECREF(name);
624 return NULL;
625 }
626
627
628 static
629 PyObject *
630 fast_split_filters(PyObject *self, PyObject *varname)
631 {
632 return _fast_split_filters(varname, self, NULL);
516 } 633 }
517 634
518 635
519 static 636 static
520 PyObject * 637 PyObject *
553 o1 = PyUnicode_Substring(varname, 0, ns_idx); 670 o1 = PyUnicode_Substring(varname, 0, ns_idx);
554 if (o1 == NULL) { 671 if (o1 == NULL) {
555 Py_DECREF(res); 672 Py_DECREF(res);
556 return NULL; 673 return NULL;
557 } 674 }
558 o2 = _fast_unquote(self, o1, ns_idx, NULL); 675 o2 = _fast_unquote(o1, ns_idx, self, NULL);
559 if (o2 == NULL) { 676 if (o2 == NULL) {
560 Py_DECREF(o1); 677 Py_DECREF(o1);
561 Py_DECREF(res); 678 Py_DECREF(res);
562 return NULL; 679 return NULL;
563 } 680 }
575 692
576 static struct PyMethodDef speedups_methods[] = { 693 static struct PyMethodDef speedups_methods[] = {
577 {"fast_unquote", fast_unquote, METH_O, PyDoc_STR("C-implementation of configmix.unquote")}, 694 {"fast_unquote", fast_unquote, METH_O, PyDoc_STR("C-implementation of configmix.unquote")},
578 {"fast_quote", fast_quote, METH_O, PyDoc_STR("C-implementation of configmix.quote")}, 695 {"fast_quote", fast_quote, METH_O, PyDoc_STR("C-implementation of configmix.quote")},
579 {"fast_pathstr2path", fast_pathstr2path, METH_O, PyDoc_STR("C-implementation of configmix.pathstr2path")}, 696 {"fast_pathstr2path", fast_pathstr2path, METH_O, PyDoc_STR("C-implementation of configmix.pathstr2path")},
697 {"_fast_split_filters", fast_split_filters, METH_O, PyDoc_STR("C-implementation of configmix.config._split_filters")},
580 {"_fast_split_ns", fast_split_ns, METH_O, PyDoc_STR("C-implementation of configmix.config._split_ns")}, 698 {"_fast_split_ns", fast_split_ns, METH_O, PyDoc_STR("C-implementation of configmix.config._split_ns")},
581 {NULL, NULL, 0, NULL} 699 {NULL, NULL, 0, NULL}
582 }; 700 };
583 701
584 #define STRINGIFY(s) #s 702 #define STRINGIFY(s) #s
618 sstate->NS_SEPARATOR = PyUnicode_FromStringAndSize(":", 1); 736 sstate->NS_SEPARATOR = PyUnicode_FromStringAndSize(":", 1);
619 if (sstate->NS_SEPARATOR == NULL) { 737 if (sstate->NS_SEPARATOR == NULL) {
620 return -1; 738 return -1;
621 } 739 }
622 PyUnicode_InternInPlace(&(sstate->NS_SEPARATOR)); 740 PyUnicode_InternInPlace(&(sstate->NS_SEPARATOR));
741
742 sstate->FILTER_SEPARATOR = PyUnicode_FromStringAndSize("|", 1);
743 if (sstate->FILTER_SEPARATOR == NULL) {
744 return -1;
745 }
746 PyUnicode_InternInPlace(&(sstate->FILTER_SEPARATOR));
623 747
624 sstate->EMPTY_STR = PyUnicode_FromStringAndSize("", 0); 748 sstate->EMPTY_STR = PyUnicode_FromStringAndSize("", 0);
625 if (sstate->EMPTY_STR == NULL) { 749 if (sstate->EMPTY_STR == NULL) {
626 return -1; 750 return -1;
627 } 751 }
656 780
657 if (sstate != NULL) { 781 if (sstate != NULL) {
658 Py_VISIT(sstate->DOT); 782 Py_VISIT(sstate->DOT);
659 Py_VISIT(sstate->QUOTE); 783 Py_VISIT(sstate->QUOTE);
660 Py_VISIT(sstate->NS_SEPARATOR); 784 Py_VISIT(sstate->NS_SEPARATOR);
785 Py_VISIT(sstate->FILTER_SEPARATOR);
661 Py_VISIT(sstate->EMPTY_STR); 786 Py_VISIT(sstate->EMPTY_STR);
662 Py_VISIT(sstate->QUOTE_MAP); 787 Py_VISIT(sstate->QUOTE_MAP);
663 } 788 }
664 return 0; 789 return 0;
665 } 790 }
673 798
674 if (sstate != NULL) { 799 if (sstate != NULL) {
675 Py_CLEAR(sstate->DOT); 800 Py_CLEAR(sstate->DOT);
676 Py_CLEAR(sstate->QUOTE); 801 Py_CLEAR(sstate->QUOTE);
677 Py_CLEAR(sstate->NS_SEPARATOR); 802 Py_CLEAR(sstate->NS_SEPARATOR);
803 Py_CLEAR(sstate->FILTER_SEPARATOR);
678 Py_CLEAR(sstate->EMPTY_STR); 804 Py_CLEAR(sstate->EMPTY_STR);
679 Py_CLEAR(sstate->QUOTE_MAP); 805 Py_CLEAR(sstate->QUOTE_MAP);
680 } 806 }
681 return 0; 807 return 0;
682 } 808 }