##// END OF EJS Templates
Changed OrderedDict implementation to pypy odict, in general it's the fastest and most reliable solution. Added OrderedTuple from python foundation.
marcink -
r1337:37625d30 beta
parent child Browse files
Show More
@@ -0,0 +1,291 b''
1 # Python Software Foundation License
2
3 # XXX: it feels like using the class with "is" and "is not" instead of "==" and
4 # "!=" should be faster.
5 class _Nil(object):
6
7 def __repr__(self):
8 return "nil"
9
10 def __eq__(self, other):
11 if (isinstance(other, _Nil)):
12 return True
13 else:
14 return NotImplemented
15
16 def __ne__(self, other):
17 if (isinstance(other, _Nil)):
18 return False
19 else:
20 return NotImplemented
21
22 _nil = _Nil()
23
24 class _odict(object):
25 """Ordered dict data structure, with O(1) complexity for dict operations
26 that modify one element.
27
28 Overwriting values doesn't change their original sequential order.
29 """
30
31 def _dict_impl(self):
32 return None
33
34 def __init__(self, data=(), **kwds):
35 """This doesn't accept keyword initialization as normal dicts to avoid
36 a trap - inside a function or method the keyword args are accessible
37 only as a dict, without a defined order, so their original order is
38 lost.
39 """
40 if kwds:
41 raise TypeError("__init__() of ordered dict takes no keyword "
42 "arguments to avoid an ordering trap.")
43 self._dict_impl().__init__(self)
44 # If you give a normal dict, then the order of elements is undefined
45 if hasattr(data, "iteritems"):
46 for key, val in data.iteritems():
47 self[key] = val
48 else:
49 for key, val in data:
50 self[key] = val
51
52 # Double-linked list header
53 def _get_lh(self):
54 dict_impl = self._dict_impl()
55 if not hasattr(self, '_lh'):
56 dict_impl.__setattr__(self, '_lh', _nil)
57 return dict_impl.__getattribute__(self, '_lh')
58
59 def _set_lh(self, val):
60 self._dict_impl().__setattr__(self, '_lh', val)
61
62 lh = property(_get_lh, _set_lh)
63
64 # Double-linked list tail
65 def _get_lt(self):
66 dict_impl = self._dict_impl()
67 if not hasattr(self, '_lt'):
68 dict_impl.__setattr__(self, '_lt', _nil)
69 return dict_impl.__getattribute__(self, '_lt')
70
71 def _set_lt(self, val):
72 self._dict_impl().__setattr__(self, '_lt', val)
73
74 lt = property(_get_lt, _set_lt)
75
76 def __getitem__(self, key):
77 return self._dict_impl().__getitem__(self, key)[1]
78
79 def __setitem__(self, key, val):
80 dict_impl = self._dict_impl()
81 try:
82 dict_impl.__getitem__(self, key)[1] = val
83 except KeyError, e:
84 new = [dict_impl.__getattribute__(self, 'lt'), val, _nil]
85 dict_impl.__setitem__(self, key, new)
86 if dict_impl.__getattribute__(self, 'lt') == _nil:
87 dict_impl.__setattr__(self, 'lh', key)
88 else:
89 dict_impl.__getitem__(
90 self, dict_impl.__getattribute__(self, 'lt'))[2] = key
91 dict_impl.__setattr__(self, 'lt', key)
92
93 def __delitem__(self, key):
94 dict_impl = self._dict_impl()
95 pred, _ , succ = self._dict_impl().__getitem__(self, key)
96 if pred == _nil:
97 dict_impl.__setattr__(self, 'lh', succ)
98 else:
99 dict_impl.__getitem__(self, pred)[2] = succ
100 if succ == _nil:
101 dict_impl.__setattr__(self, 'lt', pred)
102 else:
103 dict_impl.__getitem__(self, succ)[0] = pred
104 dict_impl.__delitem__(self, key)
105
106 def __contains__(self, key):
107 return key in self.keys()
108
109 def __len__(self):
110 return len(self.keys())
111
112 def __str__(self):
113 pairs = ("%r: %r" % (k, v) for k, v in self.iteritems())
114 return "{%s}" % ", ".join(pairs)
115
116 def __repr__(self):
117 if self:
118 pairs = ("(%r, %r)" % (k, v) for k, v in self.iteritems())
119 return "odict([%s])" % ", ".join(pairs)
120 else:
121 return "odict()"
122
123 def get(self, k, x=None):
124 if k in self:
125 return self._dict_impl().__getitem__(self, k)[1]
126 else:
127 return x
128
129 def __iter__(self):
130 dict_impl = self._dict_impl()
131 curr_key = dict_impl.__getattribute__(self, 'lh')
132 while curr_key != _nil:
133 yield curr_key
134 curr_key = dict_impl.__getitem__(self, curr_key)[2]
135
136 iterkeys = __iter__
137
138 def keys(self):
139 return list(self.iterkeys())
140
141 def itervalues(self):
142 dict_impl = self._dict_impl()
143 curr_key = dict_impl.__getattribute__(self, 'lh')
144 while curr_key != _nil:
145 _, val, curr_key = dict_impl.__getitem__(self, curr_key)
146 yield val
147
148 def values(self):
149 return list(self.itervalues())
150
151 def iteritems(self):
152 dict_impl = self._dict_impl()
153 curr_key = dict_impl.__getattribute__(self, 'lh')
154 while curr_key != _nil:
155 _, val, next_key = dict_impl.__getitem__(self, curr_key)
156 yield curr_key, val
157 curr_key = next_key
158
159 def items(self):
160 return list(self.iteritems())
161
162 def sort(self, cmp=None, key=None, reverse=False):
163 items = [(k, v) for k, v in self.items()]
164 if cmp is not None:
165 items = sorted(items, cmp=cmp)
166 elif key is not None:
167 items = sorted(items, key=key)
168 else:
169 items = sorted(items, key=lambda x: x[1])
170 if reverse:
171 items.reverse()
172 self.clear()
173 self.__init__(items)
174
175 def clear(self):
176 dict_impl = self._dict_impl()
177 dict_impl.clear(self)
178 dict_impl.__setattr__(self, 'lh', _nil)
179 dict_impl.__setattr__(self, 'lt', _nil)
180
181 def copy(self):
182 return self.__class__(self)
183
184 def update(self, data=(), **kwds):
185 if kwds:
186 raise TypeError("update() of ordered dict takes no keyword "
187 "arguments to avoid an ordering trap.")
188 if hasattr(data, "iteritems"):
189 data = data.iteritems()
190 for key, val in data:
191 self[key] = val
192
193 def setdefault(self, k, x=None):
194 try:
195 return self[k]
196 except KeyError:
197 self[k] = x
198 return x
199
200 def pop(self, k, x=_nil):
201 try:
202 val = self[k]
203 del self[k]
204 return val
205 except KeyError:
206 if x == _nil:
207 raise
208 return x
209
210 def popitem(self):
211 try:
212 dict_impl = self._dict_impl()
213 key = dict_impl.__getattribute__(self, 'lt')
214 return key, self.pop(key)
215 except KeyError:
216 raise KeyError("'popitem(): ordered dictionary is empty'")
217
218 def riterkeys(self):
219 """To iterate on keys in reversed order.
220 """
221 dict_impl = self._dict_impl()
222 curr_key = dict_impl.__getattribute__(self, 'lt')
223 while curr_key != _nil:
224 yield curr_key
225 curr_key = dict_impl.__getitem__(self, curr_key)[0]
226
227 __reversed__ = riterkeys
228
229 def rkeys(self):
230 """List of the keys in reversed order.
231 """
232 return list(self.riterkeys())
233
234 def ritervalues(self):
235 """To iterate on values in reversed order.
236 """
237 dict_impl = self._dict_impl()
238 curr_key = dict_impl.__getattribute__(self, 'lt')
239 while curr_key != _nil:
240 curr_key, val, _ = dict_impl.__getitem__(self, curr_key)
241 yield val
242
243 def rvalues(self):
244 """List of the values in reversed order.
245 """
246 return list(self.ritervalues())
247
248 def riteritems(self):
249 """To iterate on (key, value) in reversed order.
250 """
251 dict_impl = self._dict_impl()
252 curr_key = dict_impl.__getattribute__(self, 'lt')
253 while curr_key != _nil:
254 pred_key, val, _ = dict_impl.__getitem__(self, curr_key)
255 yield curr_key, val
256 curr_key = pred_key
257
258 def ritems(self):
259 """List of the (key, value) in reversed order.
260 """
261 return list(self.riteritems())
262
263 def firstkey(self):
264 if self:
265 return self._dict_impl().__getattribute__(self, 'lh')
266 else:
267 raise KeyError("'firstkey(): ordered dictionary is empty'")
268
269 def lastkey(self):
270 if self:
271 return self._dict_impl().__getattribute__(self, 'lt')
272 else:
273 raise KeyError("'lastkey(): ordered dictionary is empty'")
274
275 def as_dict(self):
276 return self._dict_impl()(self.items())
277
278 def _repr(self):
279 """_repr(): low level repr of the whole data contained in the odict.
280 Useful for debugging.
281 """
282 dict_impl = self._dict_impl()
283 form = "odict low level repr lh,lt,data: %r, %r, %s"
284 return form % (dict_impl.__getattribute__(self, 'lh'),
285 dict_impl.__getattribute__(self, 'lt'),
286 dict_impl.__repr__(self))
287
288 class OrderedDict(_odict, dict):
289
290 def _dict_impl(self):
291 return dict
@@ -0,0 +1,64 b''
1 KEY, PREV, NEXT = range(3)
2 import collections
3
4 class OrderedSet(collections.MutableSet):
5
6 def __init__(self, iterable=None):
7 self.end = end = []
8 end += [None, end, end] # sentinel node for doubly linked list
9 self.map = {} # key --> [key, prev, next]
10 if iterable is not None:
11 self |= iterable
12
13 def __len__(self):
14 return len(self.map)
15
16 def __contains__(self, key):
17 return key in self.map
18
19 def add(self, key):
20 if key not in self.map:
21 end = self.end
22 curr = end[PREV]
23 curr[NEXT] = end[PREV] = self.map[key] = [key, curr, end]
24
25 def discard(self, key):
26 if key in self.map:
27 key, prev, next = self.map.pop(key)
28 prev[NEXT] = next
29 next[PREV] = prev
30
31 def __iter__(self):
32 end = self.end
33 curr = end[NEXT]
34 while curr is not end:
35 yield curr[KEY]
36 curr = curr[NEXT]
37
38 def __reversed__(self):
39 end = self.end
40 curr = end[PREV]
41 while curr is not end:
42 yield curr[KEY]
43 curr = curr[PREV]
44
45 def pop(self, last=True):
46 if not self:
47 raise KeyError('set is empty')
48 key = next(reversed(self)) if last else next(iter(self))
49 self.discard(key)
50 return key
51
52 def __repr__(self):
53 if not self:
54 return '%s()' % (self.__class__.__name__,)
55 return '%s(%r)' % (self.__class__.__name__, list(self))
56
57 def __eq__(self, other):
58 if isinstance(other, OrderedSet):
59 return len(self) == len(other) and list(self) == list(other)
60 return set(self) == set(other)
61
62 def __del__(self):
63 self.clear() # remove circular references
64
@@ -29,7 +29,7 b' from pylons import tmpl_context as c'
29
29
30 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
30 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
31 from rhodecode.lib.base import BaseRepoController, render
31 from rhodecode.lib.base import BaseRepoController, render
32 from rhodecode.lib.utils import OrderedDict
32 from rhodecode.lib.odict import OrderedDict
33
33
34 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
35
35
@@ -34,12 +34,12 b' import rhodecode.lib.helpers as h'
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 from rhodecode.lib.base import BaseRepoController, render
35 from rhodecode.lib.base import BaseRepoController, render
36 from rhodecode.lib.utils import EmptyChangeset
36 from rhodecode.lib.utils import EmptyChangeset
37 from rhodecode.lib.odict import OrderedDict
37
38
38 from vcs.exceptions import RepositoryError, ChangesetError, \
39 from vcs.exceptions import RepositoryError, ChangesetError, \
39 ChangesetDoesNotExistError
40 ChangesetDoesNotExistError
40 from vcs.nodes import FileNode
41 from vcs.nodes import FileNode
41 from vcs.utils import diffs as differ
42 from vcs.utils import diffs as differ
42 from vcs.utils.ordered_dict import OrderedDict
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
@@ -38,7 +38,8 b' from rhodecode.model.repo import RepoMod'
38
38
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
39 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
40 from rhodecode.lib.base import BaseRepoController, render
40 from rhodecode.lib.base import BaseRepoController, render
41 from rhodecode.lib.utils import OrderedDict, EmptyChangeset
41 from rhodecode.lib.utils import EmptyChangeset
42 from rhodecode.lib.odict import OrderedDict
42
43
43 from rhodecode.lib.celerylib import run_task
44 from rhodecode.lib.celerylib import run_task
44 from rhodecode.lib.celerylib.tasks import get_commits_stats, \
45 from rhodecode.lib.celerylib.tasks import get_commits_stats, \
@@ -28,7 +28,7 b' from pylons import tmpl_context as c'
28
28
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
29 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
30 from rhodecode.lib.base import BaseRepoController, render
30 from rhodecode.lib.base import BaseRepoController, render
31 from rhodecode.lib.utils import OrderedDict
31 from rhodecode.lib.odict import OrderedDict
32
32
33 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
34
34
@@ -41,7 +41,8 b' from rhodecode.lib.celerylib import run_'
41 __get_lockkey, LockHeld, DaemonLock
41 __get_lockkey, LockHeld, DaemonLock
42 from rhodecode.lib.helpers import person
42 from rhodecode.lib.helpers import person
43 from rhodecode.lib.smtp_mailer import SmtpMailer
43 from rhodecode.lib.smtp_mailer import SmtpMailer
44 from rhodecode.lib.utils import OrderedDict, add_cache
44 from rhodecode.lib.utils import add_cache
45 from rhodecode.lib.odict import OrderedDict
45 from rhodecode.model import init_model
46 from rhodecode.model import init_model
46 from rhodecode.model import meta
47 from rhodecode.model import meta
47 from rhodecode.model.db import RhodeCodeUi, Statistics, Repository
48 from rhodecode.model.db import RhodeCodeUi, Statistics, Repository
@@ -405,107 +405,6 b' def repo2db_mapper(initial_repo_list, re'
405
405
406 return added, removed
406 return added, removed
407
407
408
409 class OrderedDict(dict, DictMixin):
410
411 def __init__(self, *args, **kwds):
412 if len(args) > 1:
413 raise TypeError('expected at most 1 arguments, got %d' % len(args))
414 try:
415 self.__end
416 except AttributeError:
417 self.clear()
418 self.update(*args, **kwds)
419
420 def clear(self):
421 self.__end = end = []
422 end += [None, end, end] # sentinel node for doubly linked list
423 self.__map = {} # key --> [key, prev, next]
424 dict.clear(self)
425
426 def __setitem__(self, key, value):
427 if key not in self:
428 end = self.__end
429 curr = end[1]
430 curr[2] = end[1] = self.__map[key] = [key, curr, end]
431 dict.__setitem__(self, key, value)
432
433 def __delitem__(self, key):
434 dict.__delitem__(self, key)
435 key, prev, next = self.__map.pop(key)
436 prev[2] = next
437 next[1] = prev
438
439 def __iter__(self):
440 end = self.__end
441 curr = end[2]
442 while curr is not end:
443 yield curr[0]
444 curr = curr[2]
445
446 def __reversed__(self):
447 end = self.__end
448 curr = end[1]
449 while curr is not end:
450 yield curr[0]
451 curr = curr[1]
452
453 def popitem(self, last=True):
454 if not self:
455 raise KeyError('dictionary is empty')
456 if last:
457 key = reversed(self).next()
458 else:
459 key = iter(self).next()
460 value = self.pop(key)
461 return key, value
462
463 def __reduce__(self):
464 items = [[k, self[k]] for k in self]
465 tmp = self.__map, self.__end
466 del self.__map, self.__end
467 inst_dict = vars(self).copy()
468 self.__map, self.__end = tmp
469 if inst_dict:
470 return (self.__class__, (items,), inst_dict)
471 return self.__class__, (items,)
472
473 def keys(self):
474 return list(self)
475
476 setdefault = DictMixin.setdefault
477 update = DictMixin.update
478 pop = DictMixin.pop
479 values = DictMixin.values
480 items = DictMixin.items
481 iterkeys = DictMixin.iterkeys
482 itervalues = DictMixin.itervalues
483 iteritems = DictMixin.iteritems
484
485 def __repr__(self):
486 if not self:
487 return '%s()' % (self.__class__.__name__,)
488 return '%s(%r)' % (self.__class__.__name__, self.items())
489
490 def copy(self):
491 return self.__class__(self)
492
493 @classmethod
494 def fromkeys(cls, iterable, value=None):
495 d = cls()
496 for key in iterable:
497 d[key] = value
498 return d
499
500 def __eq__(self, other):
501 if isinstance(other, OrderedDict):
502 return len(self) == len(other) and self.items() == other.items()
503 return dict.__eq__(self, other)
504
505 def __ne__(self, other):
506 return not self == other
507
508
509 #set cache regions for beaker so celery can utilise it
408 #set cache regions for beaker so celery can utilise it
510 def add_cache(settings):
409 def add_cache(settings):
511 cache_settings = {'regions': None}
410 cache_settings = {'regions': None}
General Comments 0
You need to be logged in to leave comments. Login now