comparison genshi/template/match.py @ 687:3d7288f373bd experimental-match-fastpaths

land first cut at fast-path matching - needs some cleanup
author aflett
date Mon, 25 Feb 2008 20:44:04 +0000
parents
children 1240ada13334
comparison
equal deleted inserted replaced
686:92efe764ec81 687:3d7288f373bd
1 from genshi.core import START
2 from genshi.path import CHILD, LocalNameTest
3
4 from copy import copy
5
6 def is_simple_path(path):
7 """
8 Is the path merely a tag match like "foo"?
9 """
10 if len(path.paths) == 1 and len(path.paths[0]) == 1:
11 axis, nodetest, predicates = path.paths[0][0]
12 if (axis is CHILD and
13 not predicates and
14 isinstance(nodetest, LocalNameTest)):
15 return True
16
17 return False
18
19
20 class MatchSet(object):
21
22 def __init__(self, parent=None, exclude=None):
23 """
24 If a parent is given, it means this is a wrapper around another
25 set. Just copy references to member variables in parent, but
26 also set exclude
27 """
28 self.parent = parent
29 if parent is None:
30 self.tag_templates = {}
31 self.other_templates = []
32 self.exclude = []
33 if exclude is not None:
34 self.exclude.append(exclude)
35 else:
36 self.tag_templates = parent.tag_templates
37 self.other_templates = parent.other_templates
38 self.exclude = copy(parent.exclude)
39 if exclude is not None:
40 self.exclude.append(exclude)
41
42 def add(self, match_template):
43 """
44 match_template is a tuple the form
45 test, path, template, hints, namespace, directives
46 """
47 path = match_template[1]
48
49 if is_simple_path(path):
50 # special cache of tag
51 tag_name = path.paths[0][0][1].name
52 # setdefault is wasteful
53 if tag_name not in self.tag_templates:
54 self.tag_templates[tag_name] = [match_template]
55 else:
56 self.tag_templates[tag_name].append(match_template)
57
58 else:
59 self.other_templates.append(match_template)
60
61 def remove(self, match_template):
62 """
63 Permanently remove a match_template - mainly for match_once
64 """
65 path = match_template[1]
66
67 if is_simple_path(path):
68 tag_name = path.paths[0][0][1].name
69 if tag_name in self.tag_templates:
70 template_list = self.tag_templates[tag_name]
71 template_list.remove(match_template)
72 if not template_list:
73 del self.tag_templates[tag_name]
74
75 else:
76 self.other_templates.remove(match_template)
77
78 def single_match(cls, match_template):
79 """
80 Factory for creating a MatchSet with just one match
81 """
82 match_set = cls()
83 match_set.add(match_template)
84 return match_set
85 single_match = classmethod(single_match)
86
87 def with_exclusion(self, exclude):
88 """
89 Factory for creating a MatchSet based on another MatchSet, but
90 with certain templates excluded
91 """
92 cls = self.__class__
93 new_match_set = cls(parent=self, exclude=exclude)
94 return new_match_set
95
96 def find_matches(self, event):
97 """
98 Return a list of all valid templates that can be used for the given event.
99 """
100 kind, data, pos = event[:3]
101
102 # todo: get the order right
103 if kind is START:
104 tag, attrs = data
105 if tag.localname in self.tag_templates:
106 for template in self.tag_templates[tag.localname]:
107 if template not in self.exclude:
108 yield template
109
110 for template in self.other_templates:
111 if template not in self.exclude:
112 yield template
113
114
115 def __nonzero__(self):
116 """
117 allow this to behave as a list
118 """
119 return bool(self.tag_templates or self.other_templates)
120
121 def __iter__(self):
122 """
123 I don't think we really need this, but it lets us behave like a list
124 """
125 for template_list in self.tag_templates.iteritems():
126 for template in template_list:
127 yield template
128 for template in self.other_templates:
129 yield template
130
131 def __str__(self):
132 parent = ""
133 if self.parent:
134 parent = ": child of 0x%x" % id(self.parent)
135
136 exclude = ""
137 if self.exclude:
138 exclude = " / excluding %d items" % len(self.exclude)
139
140 return "<MatchSet 0x%x %d tag templates, %d other templates%s%s>" % (id(self), len(self.tag_templates), len(self.other_templates), parent, exclude)
Copyright (C) 2012-2017 Edgewall Software