]>
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 | ||
25 | class OrderedDict(dict, DictMixin): | |
26 | ||
27 | def __init__(self, *args, **kwds): | |
28 | if len(args) > 1: | |
29 | raise TypeError('expected at most 1 arguments, got %d' % len(args)) | |
30 | try: | |
31 | self.__end | |
32 | except AttributeError: | |
33 | self.clear() | |
34 | self.update(*args, **kwds) | |
35 | ||
36 | def clear(self): | |
37 | self.__end = end = [] | |
38 | end += [None, end, end] # sentinel node for doubly linked list | |
39 | self.__map = {} # key --> [key, prev, next] | |
40 | dict.clear(self) | |
41 | ||
42 | def __setitem__(self, key, value): | |
43 | if key not in self: | |
44 | end = self.__end | |
45 | curr = end[1] | |
46 | curr[2] = end[1] = self.__map[key] = [key, curr, end] | |
47 | dict.__setitem__(self, key, value) | |
48 | ||
49 | def __delitem__(self, key): | |
50 | dict.__delitem__(self, key) | |
51 | key, prev, next = self.__map.pop(key) | |
52 | prev[2] = next | |
53 | next[1] = prev | |
54 | ||
55 | def __iter__(self): | |
56 | end = self.__end | |
57 | curr = end[2] | |
58 | while curr is not end: | |
59 | yield curr[0] | |
60 | curr = curr[2] | |
61 | ||
62 | def __reversed__(self): | |
63 | end = self.__end | |
64 | curr = end[1] | |
65 | while curr is not end: | |
66 | yield curr[0] | |
67 | curr = curr[1] | |
68 | ||
69 | def popitem(self, last=True): | |
70 | if not self: | |
71 | raise KeyError('dictionary is empty') | |
72 | if last: | |
73 | key = reversed(self).next() | |
74 | else: | |
75 | key = iter(self).next() | |
76 | value = self.pop(key) | |
77 | return key, value | |
78 | ||
79 | def __reduce__(self): | |
80 | items = [[k, self[k]] for k in self] | |
81 | tmp = self.__map, self.__end | |
82 | del self.__map, self.__end | |
83 | inst_dict = vars(self).copy() | |
84 | self.__map, self.__end = tmp | |
85 | if inst_dict: | |
86 | return (self.__class__, (items,), inst_dict) | |
87 | return self.__class__, (items,) | |
88 | ||
89 | def keys(self): | |
90 | return list(self) | |
91 | ||
92 | setdefault = DictMixin.setdefault | |
93 | update = DictMixin.update | |
94 | pop = DictMixin.pop | |
95 | values = DictMixin.values | |
96 | items = DictMixin.items | |
97 | iterkeys = DictMixin.iterkeys | |
98 | itervalues = DictMixin.itervalues | |
99 | iteritems = DictMixin.iteritems | |
100 | ||
101 | def __repr__(self): | |
102 | if not self: | |
103 | return '%s()' % (self.__class__.__name__,) | |
104 | return '%s(%r)' % (self.__class__.__name__, self.items()) | |
105 | ||
106 | def copy(self): | |
107 | return self.__class__(self) | |
108 | ||
109 | @classmethod | |
110 | def fromkeys(cls, iterable, value=None): | |
111 | d = cls() | |
112 | for key in iterable: | |
113 | d[key] = value | |
114 | return d | |
115 | ||
116 | def __eq__(self, other): | |
117 | if isinstance(other, OrderedDict): | |
118 | if len(self) != len(other): | |
119 | return False | |
120 | for p, q in zip(self.items(), other.items()): | |
121 | if p != q: | |
122 | return False | |
123 | return True | |
124 | return dict.__eq__(self, other) | |
125 | ||
126 | def __ne__(self, other): | |
127 | return not self == other |