Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(172801)

Side by Side Diff: Modules/_functoolsmodule.c

Issue 14373: C implementation of functools.lru_cache
Patch Set: Created 5 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« Lib/test/test_functools.py ('K') | « Lib/test/test_functools.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 #include "Python.h" 2 #include "Python.h"
3 #include "structmember.h" 3 #include "structmember.h"
4
5 #ifdef WITH_THREAD
6 #include "pythread.h"
AntoinePitrou 2013/11/22 20:36:58 You don't seem to need it right now... (but see be
7 #endif
4 8
5 /* _functools module written and maintained 9 /* _functools module written and maintained
6 by Hye-Shik Chang <perky@FreeBSD.org> 10 by Hye-Shik Chang <perky@FreeBSD.org>
7 with adaptations by Raymond Hettinger <python@rcn.com> 11 with adaptations by Raymond Hettinger <python@rcn.com>
8 Copyright (c) 2004, 2005, 2006 Python Software Foundation. 12 Copyright (c) 2004, 2005, 2006 Python Software Foundation.
9 All rights reserved. 13 All rights reserved.
10 */ 14 */
11 15
12 /* partial object **********************************************************/ 16 /* partial object **********************************************************/
13 17
(...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 PyDoc_STRVAR(functools_reduce_doc, 537 PyDoc_STRVAR(functools_reduce_doc,
534 "reduce(function, sequence[, initial]) -> value\n\ 538 "reduce(function, sequence[, initial]) -> value\n\
535 \n\ 539 \n\
536 Apply a function of two arguments cumulatively to the items of a sequence,\n\ 540 Apply a function of two arguments cumulatively to the items of a sequence,\n\
537 from left to right, so as to reduce the sequence to a single value.\n\ 541 from left to right, so as to reduce the sequence to a single value.\n\
538 For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\ 542 For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\
539 ((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\ 543 ((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\
540 of the sequence in the calculation, and serves as a default when the\n\ 544 of the sequence in the calculation, and serves as a default when the\n\
541 sequence is empty."); 545 sequence is empty.");
542 546
547 /* lru_cache object **********************************************************/
548
549 /* this object is used delimit args and keywords in the cache keys */
550 static PyObject *kwd_mark = NULL;
551
552 struct lru_list_elem;
553 struct lru_cache_object;
554
555 typedef struct lru_list_elem {
556 PyObject_HEAD
557 struct lru_list_elem *prev, *next; /* borrowed links */
558 PyObject *key, *result;
559 } lru_list_elem;
560
561 static void
562 lru_list_elem_dealloc(lru_list_elem *link)
563 {
564 Py_DECREF(link->key);
AntoinePitrou 2013/11/22 20:36:58 Py_XDECREF, no? tp_clear could have been called be
storchaka 2013/11/22 21:54:56 Done.
565 Py_DECREF(link->result);
566 PyObject_FREE(link);
AntoinePitrou 2013/11/22 20:36:58 PyObject_GC_Del, no?
storchaka 2013/11/22 21:54:56 Done.
567 }
568
569 static int
570 lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
571 {
572 Py_VISIT(link->key);
573 Py_VISIT(link->result);
574 return 0;
575 }
576
577 static int
578 lru_list_elem_clear(lru_list_elem *link)
579 {
580 Py_CLEAR(link->key);
581 Py_CLEAR(link->result);
582 return 0;
583 }
584
585 static PyTypeObject lru_list_elem_type = {
586 PyVarObject_HEAD_INIT(&PyType_Type, 0)
587 "functools._lru_list_elem", /* tp_name */
588 sizeof(lru_list_elem), /* tp_basicsize */
589 0, /* tp_itemsize */
590 /* methods */
591 (destructor)lru_list_elem_dealloc, /* tp_dealloc */
592 0, /* tp_print */
593 0, /* tp_getattr */
594 0, /* tp_setattr */
595 0, /* tp_reserved */
596 0, /* tp_repr */
597 0, /* tp_as_number */
598 0, /* tp_as_sequence */
599 0, /* tp_as_mapping */
600 0, /* tp_hash */
601 0, /* tp_call */
602 0, /* tp_str */
603 0, /* tp_getattro */
604 0, /* tp_setattro */
605 0, /* tp_as_buffer */
606 Py_TPFLAGS_DEFAULT, /* tp_flags */
AntoinePitrou 2013/11/22 20:36:58 It seems you should add the GC flags here.
storchaka 2013/11/22 21:54:56 Done.
607 0, /* tp_doc */
608 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
609 (inquiry)lru_list_elem_clear, /* tp_clear */
610 };
611
612
613 typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject * , PyObject *);
614
615 typedef struct lru_cache_object {
616 lru_list_elem root; /* includes PyObject_HEAD */
617 Py_ssize_t maxsize;
618 PyObject *maxsize_O;
619 PyObject *func;
620 lru_cache_ternaryfunc wrapper;
621 PyObject *cache;
622 PyObject *cache_info_type;
623 Py_ssize_t misses, hits;
624 int typed;
625 PyObject *dict;
626 int full;
627 } lru_cache_object;
628
629 static PyTypeObject lru_cache_type;
630
631 static PyObject *
632 lru_cache_make_key(PyObject *args, PyObject *kwds, int typed)
AntoinePitrou 2013/11/22 20:36:58 This seems to miss one optimization of functools.p
storchaka 2013/11/22 21:54:56 I will do it later (with other make_key optimizati
633 {
634 PyObject *key, *sorted_items;
635 Py_ssize_t key_size, pos, key_pos;
636
637 /* short path, key will match args anyway, which is a tuple */
638 if (!typed && !kwds) {
639 Py_INCREF(args);
640 return args;
641 }
642
643 if (kwds && PyDict_Size(kwds) > 0) {
644 sorted_items = PyDict_Items(kwds);
645 if (!sorted_items)
646 return NULL;
647 if (PyList_Sort(sorted_items) < 0) {
648 Py_DECREF(sorted_items);
649 return NULL;
650 }
651 } else
652 sorted_items = NULL;
653
654 key_size = PyTuple_GET_SIZE(args);
655 if (sorted_items)
656 key_size += PyList_GET_SIZE(sorted_items);
657 if (typed)
658 key_size *= 2;
659 if (sorted_items)
660 key_size++;
661
662 key = PyTuple_New(key_size);
AntoinePitrou 2013/11/22 20:36:58 You should check for error here.
storchaka 2013/11/22 21:54:56 Done.
663 key_pos = 0;
664
665 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
666 PyObject *item = PyTuple_GET_ITEM(args, pos);
667 Py_INCREF(item);
668 PyTuple_SET_ITEM(key, key_pos++, item);
669 }
670 if (sorted_items) {
671 Py_INCREF(kwd_mark);
672 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
673 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) {
674 PyObject *item = PyList_GET_ITEM(sorted_items, pos);
675 Py_INCREF(item);
676 PyTuple_SET_ITEM(key, key_pos++, item);
677 }
678 }
679 if (typed) {
680 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
681 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(args, pos));
682 Py_INCREF(item);
683 PyTuple_SET_ITEM(key, key_pos++, item);
684 }
685 if (sorted_items) {
686 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) {
687 PyObject *tp_items = PyList_GET_ITEM(sorted_items, pos);
688 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(tp_items, 1));
689 Py_INCREF(item);
690 PyTuple_SET_ITEM(key, key_pos++, item);
691 }
692 }
693 }
694 assert(key_pos == key_size);
695
696 if (sorted_items)
697 Py_DECREF(sorted_items);
698 return key;
699 }
700
701 static PyObject *
702 uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd s)
703 {
704 PyObject *result = PyObject_Call(self->func, args, kwds);
705 if (!result)
706 return NULL;
707 self->misses++;
AntoinePitrou 2013/11/22 20:36:58 Should be moved before the error return, IMO. (it'
storchaka 2013/11/22 21:54:56 It doesn't match functools.py.
708 return result;
709 }
710
711 static PyObject *
712 infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd s)
713 {
714 PyObject *result;
715 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
716 if (!key)
717 return NULL;
718 result = PyDict_GetItemWithError(self->cache, key);
719 if (result) {
720 Py_INCREF(result);
721 self->hits++;
722 Py_DECREF(key);
723 return result;
724 }
725 if (PyErr_Occurred()) {
726 Py_DECREF(key);
727 return NULL;
728 }
729 result = PyObject_Call(self->func, args, kwds);
730 if (!result) {
731 Py_DECREF(key);
732 return NULL;
733 }
734 if (PyDict_SetItem(self->cache, key, result) < 0) {
735 Py_DECREF(result);
736 Py_DECREF(key);
737 return NULL;
738 }
739 Py_DECREF(key);
740 self->misses++;
AntoinePitrou 2013/11/22 20:36:58 Should be moved before "PyErr_Occurred()" above.
storchaka 2013/11/22 21:54:56 It doesn't match functools.py.
741 return result;
742 }
743
744 static void
745 lru_cache_extricate_link(lru_list_elem *link)
746 {
747 link->prev->next = link->next;
748 link->next->prev = link->prev;
749 }
750
751 static void
752 lru_cache_append_link(lru_cache_object *self, lru_list_elem *link)
753 {
754 lru_list_elem *root = &self->root;
755 lru_list_elem *last = root->prev;
756 last->next = root->prev = link;
757 link->prev = last;
758 link->next = root;
759 }
760
761 static PyObject *
762 bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds )
763 {
764 lru_list_elem *link;
765 PyObject *key, *result;
766
767 key = lru_cache_make_key(args, kwds, self->typed);
768 if (!key)
769 return NULL;
770 link = (lru_list_elem *)PyDict_GetItemWithError(self->cache, key);
771 if (link) {
772 lru_cache_extricate_link(link);
773 lru_cache_append_link(self, link);
774 self->hits++;
775 result = link->result;
776 Py_INCREF(result);
777 Py_DECREF(key);
778 return result;
779 }
780 if (PyErr_Occurred()) {
781 Py_DECREF(key);
782 return NULL;
783 }
784 result = PyObject_Call(self->func, args, kwds);
785 if (!result) {
786 Py_DECREF(key);
787 return NULL;
788 }
789 if (self->full && self->root.next != &self->root) {
790 /* Use the oldest item to store the new key and result. */
791 PyObject *oldkey, *oldresult;
792 /* Extricate the oldest item. */
793 link = self->root.next;
794 lru_cache_extricate_link(link);
795 /* Remove it from the cache. */
796 if (PyDict_DelItem(self->cache, link->key) < 0) {
AntoinePitrou 2013/11/22 20:36:58 This destroys link, no? How can link still be vali
storchaka 2013/11/22 21:54:56 Link in a dict has a refcount 2. One for a dict, a
AntoinePitrou 2013/11/22 22:09:29 I think you should explain that in a comment somew
storchaka 2013/11/22 22:44:58 Done.
797 lru_cache_append_link(self, link);
798 Py_DECREF(key);
799 Py_DECREF(result);
800 return NULL;
801 }
802 /* Keep a reference to the old key and old result to
803 prevent their ref counts from going to zero during the
804 update. That will prevent potentially arbitrary object
805 clean-up code (i.e. __del__) from running while we're
806 still adjusting the links. */
807 oldkey = link->key;
808 oldresult = link->result;
809
810 link->key = key;
811 link->result = result;
812 if (PyDict_SetItem(self->cache, key, (PyObject *)link) < 0) {
813 Py_DECREF(link);
814 Py_DECREF(oldkey);
815 Py_DECREF(oldresult);
816 return NULL;
817 }
818 lru_cache_append_link(self, link);
819 Py_INCREF(result); /* for return */
820 Py_DECREF(oldkey);
821 Py_DECREF(oldresult);
822 } else {
823 /* Put result in a new link at the front of the queue. */
824 link = (lru_list_elem *)PyObject_New(lru_list_elem,
AntoinePitrou 2013/11/22 20:36:58 Hmm, PyObject_GenericNew() does a lot more than th
storchaka 2013/11/22 21:54:56 May be PyObject_GC_New()? Done. I haven't found P
AntoinePitrou 2013/11/22 22:09:29 I think you also need PyObject_GC_Track... (the so
storchaka 2013/11/22 22:44:58 Done.
825 &lru_list_elem_type);
826 if (link == NULL) {
827 Py_DECREF(key);
828 Py_DECREF(result);
829 return NULL;
830 }
831
832 link->key = key;
833 link->result = result;
834 if (PyDict_SetItem(self->cache, key, (PyObject *)link) < 0) {
AntoinePitrou 2013/11/22 20:36:58 This can also release the GIL.
storchaka 2013/11/22 21:54:56 This is why lru_cache_append_link() is called afte
835 Py_DECREF(link);
836 return NULL;
837 }
838 lru_cache_append_link(self, link);
AntoinePitrou 2013/11/22 20:36:58 At this point, one reference to link is owned by t
storchaka 2013/11/22 21:54:56 One by all linked list. Memory will no leak when t
839 Py_INCREF(result); /* for return */
840 self->full = (PyDict_Size(self->cache) >= self->maxsize);
841 }
842 self->misses++;
AntoinePitrou 2013/11/22 20:36:58 Should be moved before "PyErr_Occurred()" above.
storchaka 2013/11/22 21:54:56 It doesn't match functools.py.
843 return result;
844 }
845
846 static PyObject *
847 lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
848 {
849 PyObject *func, *maxsize_O, *cache_info_type;
850 int typed;
851 lru_cache_object *obj;
852 Py_ssize_t maxsize;
853 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
854 static char *keywords[] = {"user_function", "maxsize", "typed",
855 "cache_info_type", NULL};
856
857 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
858 &func, &maxsize_O, &typed,
859 &cache_info_type)) {
860 return NULL;
861 }
862
863 if (!PyCallable_Check(func)) {
864 PyErr_SetString(PyExc_TypeError,
865 "the first argument must be callable");
866 return NULL;
867 }
868
869 /* select the caching function, and make/inc maxsize_O */
870 if (maxsize_O == Py_None) {
871 wrapper = infinite_lru_cache_wrapper;
872 /* use this only to initialize lru_cache_object attribute maxsize */
873 maxsize = -1;
874 } else if (PyNumber_Check(maxsize_O)) {
875 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
876 if (maxsize == -1 && PyErr_Occurred())
877 return NULL;
878 if (maxsize == 0)
879 wrapper = uncached_lru_cache_wrapper;
880 else
881 wrapper = bounded_lru_cache_wrapper;
882 } else {
883 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
884 return NULL;
885 }
886
887 obj = (lru_cache_object *)type->tp_alloc(type, 0);
888 if (obj == NULL)
889 return NULL;
890
891 if (!(obj->cache = PyDict_New())) {
892 Py_DECREF(obj);
893 return NULL;
894 }
895
896 obj->root.prev = &obj->root;
897 obj->root.next = &obj->root;
898 obj->maxsize = maxsize;
899 Py_INCREF(maxsize_O);
900 obj->maxsize_O = maxsize_O;
901 Py_INCREF(func);
902 obj->func = func;
903 obj->wrapper = wrapper;
904 obj->misses = obj->hits = 0;
905 obj->typed = typed;
906 Py_INCREF(cache_info_type);
907 obj->cache_info_type = cache_info_type;
908
909 return (PyObject *)obj;
910 }
911
912 static lru_list_elem *
913 lru_cache_unlink_list(lru_cache_object *self)
914 {
915 lru_list_elem *root = &self->root;
916 lru_list_elem *link = root->next;
917 if (link == root)
918 return NULL;
919 root->prev->next = NULL;
920 root->next = root->prev = root;
921 return link;
922 }
923
924 static void
925 lru_cache_clear_list(lru_list_elem *link)
926 {
927 while (link != NULL) {
928 lru_list_elem *next = link->next;
929 Py_DECREF(link);
930 link = next;
931 }
932 }
933
934 static void
935 lru_cache_dealloc(lru_cache_object *obj)
936 {
937 lru_list_elem *list = lru_cache_unlink_list(obj);
938 Py_XDECREF(obj->maxsize_O);
939 Py_XDECREF(obj->func);
940 Py_XDECREF(obj->cache);
941 Py_XDECREF(obj->dict);
942 Py_XDECREF(obj->cache_info_type);
943 lru_cache_clear_list(list);
944 Py_TYPE(obj)->tp_free(obj);
945 }
946
947 static PyObject *
948 lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
949 {
950 return self->wrapper(self, args, kwds);
951 }
952
953 static PyObject *
954 lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
955 {
956 return PyObject_CallFunction(self->cache_info_type, "nnOn",
957 self->hits, self->misses, self->maxsize_O,
958 PyDict_Size(self->cache));
959 }
960
961 static PyObject *
962 lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
963 {
964 lru_list_elem *list = lru_cache_unlink_list(self);
965 self->hits = self->misses = 0;
966 self->full = 0;
967 PyDict_Clear(self->cache);
968 lru_cache_clear_list(list);
969 Py_RETURN_NONE;
970 }
971
972 static int
973 lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
974 {
975 Py_VISIT(self->maxsize_O);
976 Py_VISIT(self->func);
977 Py_VISIT(self->cache);
978 Py_VISIT(self->cache_info_type);
979 Py_VISIT(self->dict);
980 return 0;
981 }
982
983 static int
984 lru_cache_tp_clear(lru_cache_object *self)
985 {
986 lru_list_elem *list = lru_cache_unlink_list(self);
987 Py_CLEAR(self->maxsize_O);
988 Py_CLEAR(self->func);
989 Py_CLEAR(self->cache);
990 Py_CLEAR(self->cache_info_type);
991 Py_CLEAR(self->dict);
992 lru_cache_clear_list(list);
993 return 0;
994 }
995
996
997 PyDoc_STRVAR(lru_cache_doc,
998 "Create a cached callable that wraps another function.\n\
999 \n\
1000 user_function: the function being cached\n\
1001 \n\
1002 maxsize: 0 for no caching\n\
1003 None for unlimited cache size\n\
1004 n for a bounded cache\n\
1005 \n\
1006 typed: False cache f(3) and f(3.0) as identical calls\n\
1007 True cache f(3) and f(3.0) as distinct calls\n\
1008 \n\
1009 cache_info_type: namedtuple class with the fields:\n\
1010 hits misses currsize maxsize\n"
1011 );
1012
1013 static PyMethodDef lru_cache_methods[] = {
1014 {"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1015 {"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
1016 {NULL}
1017 };
1018
1019 static PyGetSetDef lru_cache_getsetlist[] = {
1020 {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},
1021 {NULL}
1022 };
1023
1024 static PyTypeObject lru_cache_type = {
1025 PyVarObject_HEAD_INIT(NULL, 0)
1026 "functools._lru_cache_wrapper", /* tp_name */
1027 sizeof(lru_cache_object), /* tp_basicsize */
1028 0, /* tp_itemsize */
1029 /* methods */
1030 (destructor)lru_cache_dealloc, /* tp_dealloc */
1031 0, /* tp_print */
1032 0, /* tp_getattr */
1033 0, /* tp_setattr */
1034 0, /* tp_reserved */
1035 0, /* tp_repr */
1036 0, /* tp_as_number */
1037 0, /* tp_as_sequence */
1038 0, /* tp_as_mapping */
1039 0, /* tp_hash */
1040 (ternaryfunc)lru_cache_call, /* tp_call */
1041 0, /* tp_str */
1042 0, /* tp_getattro */
1043 0, /* tp_setattro */
1044 0, /* tp_as_buffer */
1045 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC,
1046 /* tp_flags */
1047 lru_cache_doc, /* tp_doc */
1048 (traverseproc)lru_cache_tp_traverse,/* tp_traverse */
1049 (inquiry)lru_cache_tp_clear, /* tp_clear */
1050 0, /* tp_richcompare */
1051 0, /* tp_weaklistoffset */
1052 0, /* tp_iter */
1053 0, /* tp_iternext */
1054 lru_cache_methods, /* tp_methods */
1055 0, /* tp_members */
1056 lru_cache_getsetlist, /* tp_getset */
1057 0, /* tp_base */
1058 0, /* tp_dict */
1059 0, /* tp_descr_get */
1060 0, /* tp_descr_set */
1061 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1062 0, /* tp_init */
1063 0, /* tp_alloc */
1064 lru_cache_new, /* tp_new */
1065 };
1066
543 /* module level code ********************************************************/ 1067 /* module level code ********************************************************/
544 1068
545 PyDoc_STRVAR(module_doc, 1069 PyDoc_STRVAR(module_doc,
546 "Tools that operate on functions."); 1070 "Tools that operate on functions.");
547 1071
548 static PyMethodDef module_methods[] = { 1072 static PyMethodDef module_methods[] = {
549 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc }, 1073 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc },
550 {"cmp_to_key", (PyCFunction)functools_cmp_to_key, 1074 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
551 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc}, 1075 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
552 {NULL, NULL} /* sentinel */ 1076 {NULL, NULL} /* sentinel */
553 }; 1077 };
554 1078
1079 static void
1080 module_free(void *m)
1081 {
1082 Py_XDECREF(kwd_mark);
AntoinePitrou 2013/11/22 20:36:58 Well, this should use Py_CLEAR.
storchaka 2013/11/22 21:54:56 Done.
1083 }
555 1084
556 static struct PyModuleDef _functoolsmodule = { 1085 static struct PyModuleDef _functoolsmodule = {
557 PyModuleDef_HEAD_INIT, 1086 PyModuleDef_HEAD_INIT,
558 "_functools", 1087 "_functools",
559 module_doc, 1088 module_doc,
560 -1, 1089 -1,
AntoinePitrou 2013/11/22 20:36:58 I *think* it never gets freed if you put -1 instea
storchaka 2013/11/22 21:54:56 What if an initialization fail after creating kwd_
AntoinePitrou 2013/11/22 22:09:29 I don't know, I haven't checked that part. Leaving
561 module_methods, 1090 module_methods,
562 NULL, 1091 NULL,
563 NULL, 1092 NULL,
564 NULL, 1093 NULL,
565 NULL 1094 module_free,
566 }; 1095 };
567 1096
568 PyMODINIT_FUNC 1097 PyMODINIT_FUNC
569 PyInit__functools(void) 1098 PyInit__functools(void)
570 { 1099 {
571 int i; 1100 int i;
572 PyObject *m; 1101 PyObject *m;
573 char *name; 1102 char *name;
574 PyTypeObject *typelist[] = { 1103 PyTypeObject *typelist[] = {
575 &partial_type, 1104 &partial_type,
1105 &lru_cache_type,
576 NULL 1106 NULL
577 }; 1107 };
578 1108
579 m = PyModule_Create(&_functoolsmodule); 1109 m = PyModule_Create(&_functoolsmodule);
580 if (m == NULL) 1110 if (m == NULL)
581 return NULL; 1111 return NULL;
1112
1113 kwd_mark = PyObject_CallObject((PyObject *)&PyBaseObject_Type, NULL);
1114 if (!kwd_mark) {
1115 Py_DECREF(m);
1116 return NULL;
1117 }
582 1118
583 for (i=0 ; typelist[i] != NULL ; i++) { 1119 for (i=0 ; typelist[i] != NULL ; i++) {
584 if (PyType_Ready(typelist[i]) < 0) { 1120 if (PyType_Ready(typelist[i]) < 0) {
585 Py_DECREF(m); 1121 Py_DECREF(m);
586 return NULL; 1122 return NULL;
587 } 1123 }
588 name = strchr(typelist[i]->tp_name, '.'); 1124 name = strchr(typelist[i]->tp_name, '.');
589 assert (name != NULL); 1125 assert (name != NULL);
590 Py_INCREF(typelist[i]); 1126 Py_INCREF(typelist[i]);
591 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]); 1127 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
592 } 1128 }
593 return m; 1129 return m;
594 } 1130 }
OLDNEW
« Lib/test/test_functools.py ('K') | « Lib/test/test_functools.py ('k') | no next file » | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+