Mercurial > public > mercurial-scm > hg
comparison mercurial/hgweb/request.py @ 36997:44467a4d472f
hgweb: refactor multirequest to be a dict of lists
... instead of a list of 2-tuples.
This makes key lookups faster. The only downside is we lose total
ordering of all entries. But we weren't relying on that before, so
it's no loss.
Differential Revision: https://phab.mercurial-scm.org/D2881
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Fri, 16 Mar 2018 09:41:21 -0700 |
parents | f0a851542a05 |
children | 55e901396005 |
comparison
equal
deleted
inserted
replaced
36996:1bf555cb680e | 36997:44467a4d472f |
---|---|
26 Used to store parsed request parameters. | 26 Used to store parsed request parameters. |
27 | 27 |
28 This is inspired by WebOb's class of the same name. | 28 This is inspired by WebOb's class of the same name. |
29 """ | 29 """ |
30 def __init__(self): | 30 def __init__(self): |
31 # Stores (key, value) 2-tuples. This isn't the most efficient. But we | 31 self._items = {} |
32 # don't rely on parameters that much, so it shouldn't be a perf issue. | |
33 # we can always add dict for fast lookups. | |
34 self._items = [] | |
35 | 32 |
36 def __getitem__(self, key): | 33 def __getitem__(self, key): |
37 """Returns the last set value for a key.""" | 34 """Returns the last set value for a key.""" |
38 for k, v in reversed(self._items): | 35 return self._items[key][-1] |
39 if k == key: | |
40 return v | |
41 | |
42 raise KeyError(key) | |
43 | 36 |
44 def __setitem__(self, key, value): | 37 def __setitem__(self, key, value): |
45 """Replace a values for a key with a new value.""" | 38 """Replace a values for a key with a new value.""" |
46 try: | 39 self._items[key] = [value] |
47 del self[key] | |
48 except KeyError: | |
49 pass | |
50 | |
51 self._items.append((key, value)) | |
52 | 40 |
53 def __delitem__(self, key): | 41 def __delitem__(self, key): |
54 """Delete all values for a key.""" | 42 """Delete all values for a key.""" |
55 oldlen = len(self._items) | 43 del self._items[key] |
56 | |
57 self._items[:] = [(k, v) for k, v in self._items if k != key] | |
58 | |
59 if oldlen == len(self._items): | |
60 raise KeyError(key) | |
61 | 44 |
62 def __contains__(self, key): | 45 def __contains__(self, key): |
63 return any(k == key for k, v in self._items) | 46 return key in self._items |
64 | 47 |
65 def __len__(self): | 48 def __len__(self): |
66 return len(self._items) | 49 return len(self._items) |
67 | 50 |
68 def get(self, key, default=None): | 51 def get(self, key, default=None): |
71 except KeyError: | 54 except KeyError: |
72 return default | 55 return default |
73 | 56 |
74 def add(self, key, value): | 57 def add(self, key, value): |
75 """Add a new value for a key. Does not replace existing values.""" | 58 """Add a new value for a key. Does not replace existing values.""" |
76 self._items.append((key, value)) | 59 self._items.setdefault(key, []).append(value) |
77 | 60 |
78 def getall(self, key): | 61 def getall(self, key): |
79 """Obtains all values for a key.""" | 62 """Obtains all values for a key.""" |
80 return [v for k, v in self._items if k == key] | 63 return self._items.get(key, []) |
81 | 64 |
82 def getone(self, key): | 65 def getone(self, key): |
83 """Obtain a single value for a key. | 66 """Obtain a single value for a key. |
84 | 67 |
85 Raises KeyError if key not defined or it has multiple values set. | 68 Raises KeyError if key not defined or it has multiple values set. |
86 """ | 69 """ |
87 vals = self.getall(key) | 70 vals = self._items[key] |
88 | |
89 if not vals: | |
90 raise KeyError(key) | |
91 | 71 |
92 if len(vals) > 1: | 72 if len(vals) > 1: |
93 raise KeyError('multiple values for %r' % key) | 73 raise KeyError('multiple values for %r' % key) |
94 | 74 |
95 return vals[0] | 75 return vals[0] |
96 | 76 |
97 def asdictoflists(self): | 77 def asdictoflists(self): |
98 d = {} | 78 return {k: list(v) for k, v in self._items.iteritems()} |
99 for k, v in self._items: | |
100 if k in d: | |
101 d[k].append(v) | |
102 else: | |
103 d[k] = [v] | |
104 | |
105 return d | |
106 | 79 |
107 @attr.s(frozen=True) | 80 @attr.s(frozen=True) |
108 class parsedrequest(object): | 81 class parsedrequest(object): |
109 """Represents a parsed WSGI request. | 82 """Represents a parsed WSGI request. |
110 | 83 |