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

Delta Between Two Patch Sets: Modules/_functoolsmodule.c

Issue 14373: C implementation of functools.lru_cache
Left Patch Set: Created 5 years, 8 months ago
Right Patch Set: Created 4 years 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:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
8 4
9 /* _functools module written and maintained 5 /* _functools module written and maintained
10 by Hye-Shik Chang <perky@FreeBSD.org> 6 by Hye-Shik Chang <perky@FreeBSD.org>
11 with adaptations by Raymond Hettinger <python@rcn.com> 7 with adaptations by Raymond Hettinger <python@rcn.com>
12 Copyright (c) 2004, 2005, 2006 Python Software Foundation. 8 Copyright (c) 2004, 2005, 2006 Python Software Foundation.
13 All rights reserved. 9 All rights reserved.
14 */ 10 */
15 11
16 /* partial object **********************************************************/ 12 /* partial object **********************************************************/
17 13
18 typedef struct { 14 typedef struct {
19 PyObject_HEAD 15 PyObject_HEAD
20 PyObject *fn; 16 PyObject *fn;
21 PyObject *args; 17 PyObject *args;
22 PyObject *kw; 18 PyObject *kw;
23 PyObject *dict; 19 PyObject *dict;
24 PyObject *weakreflist; /* List of weak references */ 20 PyObject *weakreflist; /* List of weak references */
25 } partialobject; 21 } partialobject;
26 22
27 static PyTypeObject partial_type; 23 static PyTypeObject partial_type;
28 24
29 static PyObject * 25 static PyObject *
30 partial_new(PyTypeObject *type, PyObject *args, PyObject *kw) 26 partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
31 { 27 {
32 PyObject *func; 28 PyObject *func, *pargs, *nargs, *pkw;
33 partialobject *pto; 29 partialobject *pto;
34 30
35 if (PyTuple_GET_SIZE(args) < 1) { 31 if (PyTuple_GET_SIZE(args) < 1) {
36 PyErr_SetString(PyExc_TypeError, 32 PyErr_SetString(PyExc_TypeError,
37 "type 'partial' takes at least one argument"); 33 "type 'partial' takes at least one argument");
38 return NULL; 34 return NULL;
39 } 35 }
40 36
37 pargs = pkw = Py_None;
41 func = PyTuple_GET_ITEM(args, 0); 38 func = PyTuple_GET_ITEM(args, 0);
39 if (Py_TYPE(func) == &partial_type && type == &partial_type) {
40 partialobject *part = (partialobject *)func;
41 if (part->dict == NULL) {
42 pargs = part->args;
43 pkw = part->kw;
44 func = part->fn;
45 }
46 }
42 if (!PyCallable_Check(func)) { 47 if (!PyCallable_Check(func)) {
43 PyErr_SetString(PyExc_TypeError, 48 PyErr_SetString(PyExc_TypeError,
44 "the first argument must be callable"); 49 "the first argument must be callable");
45 return NULL; 50 return NULL;
46 } 51 }
47 52
48 /* create partialobject structure */ 53 /* create partialobject structure */
49 pto = (partialobject *)type->tp_alloc(type, 0); 54 pto = (partialobject *)type->tp_alloc(type, 0);
50 if (pto == NULL) 55 if (pto == NULL)
51 return NULL; 56 return NULL;
52 57
53 pto->fn = func; 58 pto->fn = func;
54 Py_INCREF(func); 59 Py_INCREF(func);
55 pto->args = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX); 60
56 if (pto->args == NULL) { 61 nargs = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX);
62 if (nargs == NULL) {
63 pto->args = NULL;
57 pto->kw = NULL; 64 pto->kw = NULL;
58 Py_DECREF(pto); 65 Py_DECREF(pto);
59 return NULL; 66 return NULL;
60 } 67 }
68 if (pargs == Py_None || PyTuple_GET_SIZE(pargs) == 0) {
69 pto->args = nargs;
70 Py_INCREF(nargs);
71 }
72 else if (PyTuple_GET_SIZE(nargs) == 0) {
73 pto->args = pargs;
74 Py_INCREF(pargs);
75 }
76 else {
77 pto->args = PySequence_Concat(pargs, nargs);
78 if (pto->args == NULL) {
79 pto->kw = NULL;
80 Py_DECREF(pto);
81 return NULL;
82 }
83 }
84 Py_DECREF(nargs);
85
61 if (kw != NULL) { 86 if (kw != NULL) {
62 pto->kw = PyDict_Copy(kw); 87 if (pkw == Py_None) {
88 pto->kw = PyDict_Copy(kw);
89 }
90 else {
91 pto->kw = PyDict_Copy(pkw);
92 if (pto->kw != NULL) {
93 if (PyDict_Merge(pto->kw, kw, 1) != 0) {
94 Py_DECREF(pto);
95 return NULL;
96 }
97 }
98 }
63 if (pto->kw == NULL) { 99 if (pto->kw == NULL) {
64 Py_DECREF(pto); 100 Py_DECREF(pto);
65 return NULL; 101 return NULL;
66 } 102 }
67 } else { 103 }
68 pto->kw = Py_None; 104 else {
69 Py_INCREF(Py_None); 105 if (pkw == Py_None) {
106 pto->kw = PyDict_New();
107 if (pto->kw == NULL) {
108 Py_DECREF(pto);
109 return NULL;
110 }
111 }
112 else {
113 pto->kw = pkw;
114 Py_INCREF(pkw);
115 }
70 } 116 }
71 117
72 pto->weakreflist = NULL; 118 pto->weakreflist = NULL;
73 pto->dict = NULL; 119 pto->dict = NULL;
74 120
75 return (PyObject *)pto; 121 return (PyObject *)pto;
76 } 122 }
77 123
78 static void 124 static void
79 partial_dealloc(partialobject *pto) 125 partial_dealloc(partialobject *pto)
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 600
555 typedef struct lru_list_elem { 601 typedef struct lru_list_elem {
556 PyObject_HEAD 602 PyObject_HEAD
557 struct lru_list_elem *prev, *next; /* borrowed links */ 603 struct lru_list_elem *prev, *next; /* borrowed links */
558 PyObject *key, *result; 604 PyObject *key, *result;
559 } lru_list_elem; 605 } lru_list_elem;
560 606
561 static void 607 static void
562 lru_list_elem_dealloc(lru_list_elem *link) 608 lru_list_elem_dealloc(lru_list_elem *link)
563 { 609 {
564 Py_DECREF(link->key); 610 _PyObject_GC_UNTRACK(link);
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); 611 Py_XDECREF(link->key);
566 PyObject_FREE(link); 612 Py_XDECREF(link->result);
AntoinePitrou 2013/11/22 20:36:58 PyObject_GC_Del, no?
storchaka 2013/11/22 21:54:56 Done.
613 PyObject_GC_Del(link);
567 } 614 }
568 615
569 static int 616 static int
570 lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg) 617 lru_list_elem_traverse(lru_list_elem *link, visitproc visit, void *arg)
571 { 618 {
572 Py_VISIT(link->key); 619 Py_VISIT(link->key);
573 Py_VISIT(link->result); 620 Py_VISIT(link->result);
574 return 0; 621 return 0;
575 } 622 }
576 623
(...skipping 19 matching lines...) Expand all
596 0, /* tp_repr */ 643 0, /* tp_repr */
597 0, /* tp_as_number */ 644 0, /* tp_as_number */
598 0, /* tp_as_sequence */ 645 0, /* tp_as_sequence */
599 0, /* tp_as_mapping */ 646 0, /* tp_as_mapping */
600 0, /* tp_hash */ 647 0, /* tp_hash */
601 0, /* tp_call */ 648 0, /* tp_call */
602 0, /* tp_str */ 649 0, /* tp_str */
603 0, /* tp_getattro */ 650 0, /* tp_getattro */
604 0, /* tp_setattro */ 651 0, /* tp_setattro */
605 0, /* tp_as_buffer */ 652 0, /* tp_as_buffer */
606 Py_TPFLAGS_DEFAULT, /* tp_flags */ 653 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* 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 */ 654 0, /* tp_doc */
608 (traverseproc)lru_list_elem_traverse, /* tp_traverse */ 655 (traverseproc)lru_list_elem_traverse, /* tp_traverse */
609 (inquiry)lru_list_elem_clear, /* tp_clear */ 656 (inquiry)lru_list_elem_clear, /* tp_clear */
610 }; 657 };
611 658
612 659
613 typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject * , PyObject *); 660 typedef PyObject *(*lru_cache_ternaryfunc)(struct lru_cache_object *, PyObject * , PyObject *);
614 661
615 typedef struct lru_cache_object { 662 typedef struct lru_cache_object {
616 lru_list_elem root; /* includes PyObject_HEAD */ 663 lru_list_elem root; /* includes PyObject_HEAD */
617 Py_ssize_t maxsize; 664 Py_ssize_t maxsize;
618 PyObject *maxsize_O; 665 PyObject *maxsize_O;
619 PyObject *func; 666 PyObject *func;
620 lru_cache_ternaryfunc wrapper; 667 lru_cache_ternaryfunc wrapper;
621 PyObject *cache; 668 PyObject *cache;
622 PyObject *cache_info_type; 669 PyObject *cache_info_type;
623 Py_ssize_t misses, hits; 670 Py_ssize_t misses, hits;
624 int typed; 671 int typed;
625 PyObject *dict; 672 PyObject *dict;
626 int full; 673 int full;
627 } lru_cache_object; 674 } lru_cache_object;
628 675
629 static PyTypeObject lru_cache_type; 676 static PyTypeObject lru_cache_type;
630 677
631 static PyObject * 678 static PyObject *
632 lru_cache_make_key(PyObject *args, PyObject *kwds, int typed) 679 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 { 680 {
634 PyObject *key, *sorted_items; 681 PyObject *key, *sorted_items;
635 Py_ssize_t key_size, pos, key_pos; 682 Py_ssize_t key_size, pos, key_pos;
636 683
637 /* short path, key will match args anyway, which is a tuple */ 684 /* short path, key will match args anyway, which is a tuple */
638 if (!typed && !kwds) { 685 if (!typed && !kwds) {
639 Py_INCREF(args); 686 Py_INCREF(args);
640 return args; 687 return args;
641 } 688 }
642 689
643 if (kwds && PyDict_Size(kwds) > 0) { 690 if (kwds && PyDict_Size(kwds) > 0) {
644 sorted_items = PyDict_Items(kwds); 691 sorted_items = PyDict_Items(kwds);
645 if (!sorted_items) 692 if (!sorted_items)
646 return NULL; 693 return NULL;
647 if (PyList_Sort(sorted_items) < 0) { 694 if (PyList_Sort(sorted_items) < 0) {
648 Py_DECREF(sorted_items); 695 Py_DECREF(sorted_items);
649 return NULL; 696 return NULL;
650 } 697 }
651 } else 698 } else
652 sorted_items = NULL; 699 sorted_items = NULL;
653 700
654 key_size = PyTuple_GET_SIZE(args); 701 key_size = PyTuple_GET_SIZE(args);
655 if (sorted_items) 702 if (sorted_items)
656 key_size += PyList_GET_SIZE(sorted_items); 703 key_size += PyList_GET_SIZE(sorted_items);
657 if (typed) 704 if (typed)
658 key_size *= 2; 705 key_size *= 2;
659 if (sorted_items) 706 if (sorted_items)
660 key_size++; 707 key_size++;
661 708
662 key = PyTuple_New(key_size); 709 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.
710 if (key == NULL)
711 goto done;
712
663 key_pos = 0; 713 key_pos = 0;
664
665 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) { 714 for (pos = 0; pos < PyTuple_GET_SIZE(args); ++pos) {
666 PyObject *item = PyTuple_GET_ITEM(args, pos); 715 PyObject *item = PyTuple_GET_ITEM(args, pos);
667 Py_INCREF(item); 716 Py_INCREF(item);
668 PyTuple_SET_ITEM(key, key_pos++, item); 717 PyTuple_SET_ITEM(key, key_pos++, item);
669 } 718 }
670 if (sorted_items) { 719 if (sorted_items) {
671 Py_INCREF(kwd_mark); 720 Py_INCREF(kwd_mark);
672 PyTuple_SET_ITEM(key, key_pos++, kwd_mark); 721 PyTuple_SET_ITEM(key, key_pos++, kwd_mark);
673 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) { 722 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) {
674 PyObject *item = PyList_GET_ITEM(sorted_items, pos); 723 PyObject *item = PyList_GET_ITEM(sorted_items, pos);
(...skipping 11 matching lines...) Expand all
686 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) { 735 for (pos = 0; pos < PyList_GET_SIZE(sorted_items); ++pos) {
687 PyObject *tp_items = PyList_GET_ITEM(sorted_items, pos); 736 PyObject *tp_items = PyList_GET_ITEM(sorted_items, pos);
688 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(tp_items, 1)); 737 PyObject *item = (PyObject *)Py_TYPE(PyTuple_GET_ITEM(tp_items, 1));
689 Py_INCREF(item); 738 Py_INCREF(item);
690 PyTuple_SET_ITEM(key, key_pos++, item); 739 PyTuple_SET_ITEM(key, key_pos++, item);
691 } 740 }
692 } 741 }
693 } 742 }
694 assert(key_pos == key_size); 743 assert(key_pos == key_size);
695 744
745 done:
696 if (sorted_items) 746 if (sorted_items)
697 Py_DECREF(sorted_items); 747 Py_DECREF(sorted_items);
698 return key; 748 return key;
699 } 749 }
700 750
701 static PyObject * 751 static PyObject *
702 uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd s) 752 uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd s)
703 { 753 {
704 PyObject *result = PyObject_Call(self->func, args, kwds); 754 PyObject *result = PyObject_Call(self->func, args, kwds);
705 if (!result) 755 if (!result)
706 return NULL; 756 return NULL;
707 self->misses++; 757 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; 758 return result;
709 } 759 }
710 760
711 static PyObject * 761 static PyObject *
712 infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd s) 762 infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd s)
713 { 763 {
714 PyObject *result; 764 PyObject *result;
715 PyObject *key = lru_cache_make_key(args, kwds, self->typed); 765 PyObject *key = lru_cache_make_key(args, kwds, self->typed);
716 if (!key) 766 if (!key)
717 return NULL; 767 return NULL;
(...skipping 12 matching lines...) Expand all
730 if (!result) { 780 if (!result) {
731 Py_DECREF(key); 781 Py_DECREF(key);
732 return NULL; 782 return NULL;
733 } 783 }
734 if (PyDict_SetItem(self->cache, key, result) < 0) { 784 if (PyDict_SetItem(self->cache, key, result) < 0) {
735 Py_DECREF(result); 785 Py_DECREF(result);
736 Py_DECREF(key); 786 Py_DECREF(key);
737 return NULL; 787 return NULL;
738 } 788 }
739 Py_DECREF(key); 789 Py_DECREF(key);
740 self->misses++; 790 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; 791 return result;
742 } 792 }
743 793
744 static void 794 static void
745 lru_cache_extricate_link(lru_list_elem *link) 795 lru_cache_extricate_link(lru_list_elem *link)
746 { 796 {
747 link->prev->next = link->next; 797 link->prev->next = link->next;
748 link->next->prev = link->prev; 798 link->next->prev = link->prev;
749 } 799 }
750 800
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 if (!result) { 835 if (!result) {
786 Py_DECREF(key); 836 Py_DECREF(key);
787 return NULL; 837 return NULL;
788 } 838 }
789 if (self->full && self->root.next != &self->root) { 839 if (self->full && self->root.next != &self->root) {
790 /* Use the oldest item to store the new key and result. */ 840 /* Use the oldest item to store the new key and result. */
791 PyObject *oldkey, *oldresult; 841 PyObject *oldkey, *oldresult;
792 /* Extricate the oldest item. */ 842 /* Extricate the oldest item. */
793 link = self->root.next; 843 link = self->root.next;
794 lru_cache_extricate_link(link); 844 lru_cache_extricate_link(link);
795 /* Remove it from the cache. */ 845 /* Remove it from the cache.
846 The cache dict holds one reference to the link,
847 and the linked list holds yet one reference to it. */
796 if (PyDict_DelItem(self->cache, link->key) < 0) { 848 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); 849 lru_cache_append_link(self, link);
798 Py_DECREF(key); 850 Py_DECREF(key);
799 Py_DECREF(result); 851 Py_DECREF(result);
800 return NULL; 852 return NULL;
801 } 853 }
802 /* Keep a reference to the old key and old result to 854 /* Keep a reference to the old key and old result to
803 prevent their ref counts from going to zero during the 855 prevent their ref counts from going to zero during the
804 update. That will prevent potentially arbitrary object 856 update. That will prevent potentially arbitrary object
805 clean-up code (i.e. __del__) from running while we're 857 clean-up code (i.e. __del__) from running while we're
806 still adjusting the links. */ 858 still adjusting the links. */
807 oldkey = link->key; 859 oldkey = link->key;
808 oldresult = link->result; 860 oldresult = link->result;
809 861
810 link->key = key; 862 link->key = key;
811 link->result = result; 863 link->result = result;
812 if (PyDict_SetItem(self->cache, key, (PyObject *)link) < 0) { 864 if (PyDict_SetItem(self->cache, key, (PyObject *)link) < 0) {
813 Py_DECREF(link); 865 Py_DECREF(link);
814 Py_DECREF(oldkey); 866 Py_DECREF(oldkey);
815 Py_DECREF(oldresult); 867 Py_DECREF(oldresult);
816 return NULL; 868 return NULL;
817 } 869 }
818 lru_cache_append_link(self, link); 870 lru_cache_append_link(self, link);
819 Py_INCREF(result); /* for return */ 871 Py_INCREF(result); /* for return */
820 Py_DECREF(oldkey); 872 Py_DECREF(oldkey);
821 Py_DECREF(oldresult); 873 Py_DECREF(oldresult);
822 } else { 874 } else {
823 /* Put result in a new link at the front of the queue. */ 875 /* Put result in a new link at the front of the queue. */
824 link = (lru_list_elem *)PyObject_New(lru_list_elem, 876 link = (lru_list_elem *)PyObject_GC_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); 877 &lru_list_elem_type);
826 if (link == NULL) { 878 if (link == NULL) {
827 Py_DECREF(key); 879 Py_DECREF(key);
828 Py_DECREF(result); 880 Py_DECREF(result);
829 return NULL; 881 return NULL;
830 } 882 }
831 883
832 link->key = key; 884 link->key = key;
833 link->result = result; 885 link->result = result;
886 _PyObject_GC_TRACK(link);
834 if (PyDict_SetItem(self->cache, key, (PyObject *)link) < 0) { 887 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); 888 Py_DECREF(link);
836 return NULL; 889 return NULL;
837 } 890 }
838 lru_cache_append_link(self, link); 891 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 */ 892 Py_INCREF(result); /* for return */
840 self->full = (PyDict_Size(self->cache) >= self->maxsize); 893 self->full = (PyDict_Size(self->cache) >= self->maxsize);
841 } 894 }
842 self->misses++; 895 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; 896 return result;
844 } 897 }
845 898
846 static PyObject * 899 static PyObject *
847 lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw) 900 lru_cache_new(PyTypeObject *type, PyObject *args, PyObject *kw)
848 { 901 {
849 PyObject *func, *maxsize_O, *cache_info_type; 902 PyObject *func, *maxsize_O, *cache_info_type, *cachedict;
850 int typed; 903 int typed;
851 lru_cache_object *obj; 904 lru_cache_object *obj;
852 Py_ssize_t maxsize; 905 Py_ssize_t maxsize;
853 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *); 906 PyObject *(*wrapper)(lru_cache_object *, PyObject *, PyObject *);
854 static char *keywords[] = {"user_function", "maxsize", "typed", 907 static char *keywords[] = {"user_function", "maxsize", "typed",
855 "cache_info_type", NULL}; 908 "cache_info_type", NULL};
856 909
857 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords, 910 if (!PyArg_ParseTupleAndKeywords(args, kw, "OOpO:lru_cache", keywords,
858 &func, &maxsize_O, &typed, 911 &func, &maxsize_O, &typed,
859 &cache_info_type)) { 912 &cache_info_type)) {
860 return NULL; 913 return NULL;
861 } 914 }
862 915
863 if (!PyCallable_Check(func)) { 916 if (!PyCallable_Check(func)) {
864 PyErr_SetString(PyExc_TypeError, 917 PyErr_SetString(PyExc_TypeError,
865 "the first argument must be callable"); 918 "the first argument must be callable");
866 return NULL; 919 return NULL;
867 } 920 }
868 921
869 /* select the caching function, and make/inc maxsize_O */ 922 /* select the caching function, and make/inc maxsize_O */
870 if (maxsize_O == Py_None) { 923 if (maxsize_O == Py_None) {
871 wrapper = infinite_lru_cache_wrapper; 924 wrapper = infinite_lru_cache_wrapper;
872 /* use this only to initialize lru_cache_object attribute maxsize */ 925 /* use this only to initialize lru_cache_object attribute maxsize */
873 maxsize = -1; 926 maxsize = -1;
874 } else if (PyNumber_Check(maxsize_O)) { 927 } else if (PyIndex_Check(maxsize_O)) {
875 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError); 928 maxsize = PyNumber_AsSsize_t(maxsize_O, PyExc_OverflowError);
876 if (maxsize == -1 && PyErr_Occurred()) 929 if (maxsize == -1 && PyErr_Occurred())
877 return NULL; 930 return NULL;
878 if (maxsize == 0) 931 if (maxsize == 0)
879 wrapper = uncached_lru_cache_wrapper; 932 wrapper = uncached_lru_cache_wrapper;
880 else 933 else
881 wrapper = bounded_lru_cache_wrapper; 934 wrapper = bounded_lru_cache_wrapper;
882 } else { 935 } else {
883 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None"); 936 PyErr_SetString(PyExc_TypeError, "maxsize should be integer or None");
884 return NULL; 937 return NULL;
885 } 938 }
886 939
940 if (!(cachedict = PyDict_New()))
941 return NULL;
942
887 obj = (lru_cache_object *)type->tp_alloc(type, 0); 943 obj = (lru_cache_object *)type->tp_alloc(type, 0);
888 if (obj == NULL) 944 if (obj == NULL) {
889 return NULL; 945 Py_DECREF(cachedict);
890 946 return NULL;
891 if (!(obj->cache = PyDict_New())) { 947 }
892 Py_DECREF(obj); 948
893 return NULL; 949 obj->cache = cachedict;
894 }
895
896 obj->root.prev = &obj->root; 950 obj->root.prev = &obj->root;
897 obj->root.next = &obj->root; 951 obj->root.next = &obj->root;
898 obj->maxsize = maxsize; 952 obj->maxsize = maxsize;
899 Py_INCREF(maxsize_O); 953 Py_INCREF(maxsize_O);
900 obj->maxsize_O = maxsize_O; 954 obj->maxsize_O = maxsize_O;
901 Py_INCREF(func); 955 Py_INCREF(func);
902 obj->func = func; 956 obj->func = func;
903 obj->wrapper = wrapper; 957 obj->wrapper = wrapper;
904 obj->misses = obj->hits = 0; 958 obj->misses = obj->hits = 0;
905 obj->typed = typed; 959 obj->typed = typed;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
944 Py_TYPE(obj)->tp_free(obj); 998 Py_TYPE(obj)->tp_free(obj);
945 } 999 }
946 1000
947 static PyObject * 1001 static PyObject *
948 lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds) 1002 lru_cache_call(lru_cache_object *self, PyObject *args, PyObject *kwds)
949 { 1003 {
950 return self->wrapper(self, args, kwds); 1004 return self->wrapper(self, args, kwds);
951 } 1005 }
952 1006
953 static PyObject * 1007 static PyObject *
1008 lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
1009 {
1010 if (obj == Py_None || obj == NULL) {
1011 Py_INCREF(self);
1012 return self;
1013 }
1014 return PyMethod_New(self, obj);
1015 }
1016
1017 static PyObject *
954 lru_cache_cache_info(lru_cache_object *self, PyObject *unused) 1018 lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
955 { 1019 {
956 return PyObject_CallFunction(self->cache_info_type, "nnOn", 1020 return PyObject_CallFunction(self->cache_info_type, "nnOn",
957 self->hits, self->misses, self->maxsize_O, 1021 self->hits, self->misses, self->maxsize_O,
958 PyDict_Size(self->cache)); 1022 PyDict_Size(self->cache));
959 } 1023 }
960 1024
961 static PyObject * 1025 static PyObject *
962 lru_cache_cache_clear(lru_cache_object *self, PyObject *unused) 1026 lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
963 { 1027 {
964 lru_list_elem *list = lru_cache_unlink_list(self); 1028 lru_list_elem *list = lru_cache_unlink_list(self);
965 self->hits = self->misses = 0; 1029 self->hits = self->misses = 0;
966 self->full = 0; 1030 self->full = 0;
967 PyDict_Clear(self->cache); 1031 PyDict_Clear(self->cache);
968 lru_cache_clear_list(list); 1032 lru_cache_clear_list(list);
969 Py_RETURN_NONE; 1033 Py_RETURN_NONE;
970 } 1034 }
971 1035
972 static int 1036 static int
973 lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg) 1037 lru_cache_tp_traverse(lru_cache_object *self, visitproc visit, void *arg)
974 { 1038 {
1039 lru_list_elem *link = self->root.next;
1040 while (link != &self->root) {
1041 lru_list_elem *next = link->next;
1042 Py_VISIT(link);
1043 link = next;
1044 }
975 Py_VISIT(self->maxsize_O); 1045 Py_VISIT(self->maxsize_O);
976 Py_VISIT(self->func); 1046 Py_VISIT(self->func);
977 Py_VISIT(self->cache); 1047 Py_VISIT(self->cache);
978 Py_VISIT(self->cache_info_type); 1048 Py_VISIT(self->cache_info_type);
979 Py_VISIT(self->dict); 1049 Py_VISIT(self->dict);
980 return 0; 1050 return 0;
981 } 1051 }
982 1052
983 static int 1053 static int
984 lru_cache_tp_clear(lru_cache_object *self) 1054 lru_cache_tp_clear(lru_cache_object *self)
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1049 (inquiry)lru_cache_tp_clear, /* tp_clear */ 1119 (inquiry)lru_cache_tp_clear, /* tp_clear */
1050 0, /* tp_richcompare */ 1120 0, /* tp_richcompare */
1051 0, /* tp_weaklistoffset */ 1121 0, /* tp_weaklistoffset */
1052 0, /* tp_iter */ 1122 0, /* tp_iter */
1053 0, /* tp_iternext */ 1123 0, /* tp_iternext */
1054 lru_cache_methods, /* tp_methods */ 1124 lru_cache_methods, /* tp_methods */
1055 0, /* tp_members */ 1125 0, /* tp_members */
1056 lru_cache_getsetlist, /* tp_getset */ 1126 lru_cache_getsetlist, /* tp_getset */
1057 0, /* tp_base */ 1127 0, /* tp_base */
1058 0, /* tp_dict */ 1128 0, /* tp_dict */
1059 0, /* tp_descr_get */ 1129 lru_cache_descr_get, /* tp_descr_get */
1060 0, /* tp_descr_set */ 1130 0, /* tp_descr_set */
1061 offsetof(lru_cache_object, dict), /* tp_dictoffset */ 1131 offsetof(lru_cache_object, dict), /* tp_dictoffset */
1062 0, /* tp_init */ 1132 0, /* tp_init */
1063 0, /* tp_alloc */ 1133 0, /* tp_alloc */
1064 lru_cache_new, /* tp_new */ 1134 lru_cache_new, /* tp_new */
1065 }; 1135 };
1066 1136
1067 /* module level code ********************************************************/ 1137 /* module level code ********************************************************/
1068 1138
1069 PyDoc_STRVAR(module_doc, 1139 PyDoc_STRVAR(module_doc,
1070 "Tools that operate on functions."); 1140 "Tools that operate on functions.");
1071 1141
1072 static PyMethodDef module_methods[] = { 1142 static PyMethodDef module_methods[] = {
1073 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc }, 1143 {"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc },
1074 {"cmp_to_key", (PyCFunction)functools_cmp_to_key, 1144 {"cmp_to_key", (PyCFunction)functools_cmp_to_key,
1075 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc}, 1145 METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
1076 {NULL, NULL} /* sentinel */ 1146 {NULL, NULL} /* sentinel */
1077 }; 1147 };
1078 1148
1079 static void 1149 static void
1080 module_free(void *m) 1150 module_free(void *m)
1081 { 1151 {
1082 Py_XDECREF(kwd_mark); 1152 Py_CLEAR(kwd_mark);
AntoinePitrou 2013/11/22 20:36:58 Well, this should use Py_CLEAR.
storchaka 2013/11/22 21:54:56 Done.
1083 } 1153 }
1084 1154
1085 static struct PyModuleDef _functoolsmodule = { 1155 static struct PyModuleDef _functoolsmodule = {
1086 PyModuleDef_HEAD_INIT, 1156 PyModuleDef_HEAD_INIT,
1087 "_functools", 1157 "_functools",
1088 module_doc, 1158 module_doc,
1089 -1, 1159 -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
1090 module_methods, 1160 module_methods,
1091 NULL, 1161 NULL,
1092 NULL, 1162 NULL,
1093 NULL, 1163 NULL,
1094 module_free, 1164 module_free,
1095 }; 1165 };
1096 1166
1097 PyMODINIT_FUNC 1167 PyMODINIT_FUNC
1098 PyInit__functools(void) 1168 PyInit__functools(void)
1099 { 1169 {
(...skipping 21 matching lines...) Expand all
1121 Py_DECREF(m); 1191 Py_DECREF(m);
1122 return NULL; 1192 return NULL;
1123 } 1193 }
1124 name = strchr(typelist[i]->tp_name, '.'); 1194 name = strchr(typelist[i]->tp_name, '.');
1125 assert (name != NULL); 1195 assert (name != NULL);
1126 Py_INCREF(typelist[i]); 1196 Py_INCREF(typelist[i]);
1127 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]); 1197 PyModule_AddObject(m, name+1, (PyObject *)typelist[i]);
1128 } 1198 }
1129 return m; 1199 return m;
1130 } 1200 }
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

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