]>
Commit | Line | Data |
---|---|---|
e89ac222 MR |
1 | # Copyright (c) 2009 Raymond Hettinger |
2 | # | |
3 | # Permission is hereby granted, free of charge, to any person | |
4 | # obtaining a copy of this software and associated documentation files | |
5 | # (the "Software"), to deal in the Software without restriction, | |
6 | # including without limitation the rights to use, copy, modify, merge, | |
7 | # publish, distribute, sublicense, and/or sell copies of the Software, | |
8 | # and to permit persons to whom the Software is furnished to do so, | |
9 | # subject to the following conditions: | |
10 | # | |
11 | # The above copyright notice and this permission notice shall be | |
12 | # included in all copies or substantial portions of the Software. | |
13 | # | |
14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
15 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
16 | # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
18 | # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
19 | # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
21 | # OTHER DEALINGS IN THE SOFTWARE. | |
22 | ||
23 | from UserDict import DictMixin | |
24 | ||
437db254 | 25 | |
e89ac222 MR |
26 | class OrderedDict(dict, DictMixin): |
27 | ||
28 | def __init__(self, *args, **kwds): | |
29 | if len(args) > 1: | |
30 | raise TypeError('expected at most 1 arguments, got %d' % len(args)) | |
31 | try: | |
32 | self.__end | |
33 | except AttributeError: | |
34 | self.clear() | |
35 | self.update(*args, **kwds) | |
36 | ||
37 | def clear(self): | |
38 | self.__end = end = [] | |
39 | end += [None, end, end] # sentinel node for doubly linked list | |
40 | self.__map = {} # key --> [key, prev, next] | |
41 | dict.clear(self) | |
42 | ||
43 | def __setitem__(self, key, value): | |
44 | if key not in self: | |
45 | end = self.__end | |
46 | curr = end[1] | |
47 | curr[2] = end[1] = self.__map[key] = [key, curr, end] | |
48 | dict.__setitem__(self, key, value) | |
49 | ||
50 | def __delitem__(self, key): | |
51 | dict.__delitem__(self, key) | |
52 | key, prev, next = self.__map.pop(key) | |
53 | prev[2] = next | |
54 | next[1] = prev | |
55 | ||
56 | def __iter__(self): | |
57 | end = self.__end | |
58 | curr = end[2] | |
59 | while curr is not end: | |
60 | yield curr[0] | |
61 | curr = curr[2] | |
62 | ||
63 | def __reversed__(self): | |
64 | end = self.__end | |
65 | curr = end[1] | |
66 | while curr is not end: | |
67 | yield curr[0] | |
68 | curr = curr[1] | |
69 | ||
70 | def popitem(self, last=True): | |
71 | if not self: | |
72 | raise KeyError('dictionary is empty') | |
73 | if last: | |
74 | key = reversed(self).next() | |
75 | else: | |
76 | key = iter(self).next() | |
77 | value = self.pop(key) | |
78 | return key, value | |
79 | ||
80 | def __reduce__(self): | |
81 | items = [[k, self[k]] for k in self] | |
82 | tmp = self.__map, self.__end | |
83 | del self.__map, self.__end | |
84 | inst_dict = vars(self).copy() | |
85 | self.__map, self.__end = tmp | |
86 | if inst_dict: | |
87 | return (self.__class__, (items,), inst_dict) | |
88 | return self.__class__, (items,) | |
89 | ||
90 | def keys(self): | |
91 | return list(self) | |
92 | ||
93 | setdefault = DictMixin.setdefault | |
94 | update = DictMixin.update | |
95 | pop = DictMixin.pop | |
96 | values = DictMixin.values | |
97 | items = DictMixin.items | |
98 | iterkeys = DictMixin.iterkeys | |
99 | itervalues = DictMixin.itervalues | |
100 | iteritems = DictMixin.iteritems | |
101 | ||
102 | def __repr__(self): | |
103 | if not self: | |
104 | return '%s()' % (self.__class__.__name__,) | |
105 | return '%s(%r)' % (self.__class__.__name__, self.items()) | |
106 | ||
107 | def copy(self): | |
108 | return self.__class__(self) | |
109 | ||
110 | @classmethod | |
111 | def fromkeys(cls, iterable, value=None): | |
112 | d = cls() | |
113 | for key in iterable: | |
114 | d[key] = value | |
115 | return d | |
116 | ||
117 | def __eq__(self, other): | |
118 | if isinstance(other, OrderedDict): | |
119 | if len(self) != len(other): | |
120 | return False | |
437db254 | 121 | for p, q in zip(self.items(), other.items()): |
e89ac222 MR |
122 | if p != q: |
123 | return False | |
124 | return True | |
125 | return dict.__eq__(self, other) | |
126 | ||
127 | def __ne__(self, other): | |
128 | return not self == other |