Statistics
| Branch: | Tag: | Revision:

root / snf-common / synnefo / lib / ordereddict.py @ 1c65202f

History | View | Annotate | Download (4.1 kB)

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