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