hgweb: refactor multirequest to be a dict of lists
authorGregory Szorc <gregory.szorc@gmail.com>
Fri, 16 Mar 2018 09:41:21 -0700
changeset 37000 44467a4d472f
parent 36999 1bf555cb680e
child 37001 3723b42ff953
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
mercurial/hgweb/request.py
--- 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):