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
--- a/mercurial/hgweb/request.py Sun Mar 04 22:35:29 2018 +0530
+++ b/mercurial/hgweb/request.py Fri Mar 16 09:41:21 2018 -0700
@@ -28,39 +28,22 @@
This is inspired by WebOb's class of the same name.
"""
def __init__(self):
- # Stores (key, value) 2-tuples. This isn't the most efficient. But we
- # don't rely on parameters that much, so it shouldn't be a perf issue.
- # we can always add dict for fast lookups.
- self._items = []
+ self._items = {}
def __getitem__(self, key):
"""Returns the last set value for a key."""
- for k, v in reversed(self._items):
- if k == key:
- return v
-
- raise KeyError(key)
+ return self._items[key][-1]
def __setitem__(self, key, value):
"""Replace a values for a key with a new value."""
- try:
- del self[key]
- except KeyError:
- pass
-
- self._items.append((key, value))
+ self._items[key] = [value]
def __delitem__(self, key):
"""Delete all values for a key."""
- oldlen = len(self._items)
-
- self._items[:] = [(k, v) for k, v in self._items if k != key]
-
- if oldlen == len(self._items):
- raise KeyError(key)
+ del self._items[key]
def __contains__(self, key):
- return any(k == key for k, v in self._items)
+ return key in self._items
def __len__(self):
return len(self._items)
@@ -73,21 +56,18 @@
def add(self, key, value):
"""Add a new value for a key. Does not replace existing values."""
- self._items.append((key, value))
+ self._items.setdefault(key, []).append(value)
def getall(self, key):
"""Obtains all values for a key."""
- return [v for k, v in self._items if k == key]
+ return self._items.get(key, [])
def getone(self, key):
"""Obtain a single value for a key.
Raises KeyError if key not defined or it has multiple values set.
"""
- vals = self.getall(key)
-
- if not vals:
- raise KeyError(key)
+ vals = self._items[key]
if len(vals) > 1:
raise KeyError('multiple values for %r' % key)
@@ -95,14 +75,7 @@
return vals[0]
def asdictoflists(self):
- d = {}
- for k, v in self._items:
- if k in d:
- d[k].append(v)
- else:
- d[k] = [v]
-
- return d
+ return {k: list(v) for k, v in self._items.iteritems()}
@attr.s(frozen=True)
class parsedrequest(object):