summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/COW.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/COW.py')
-rw-r--r--bitbake/lib/bb/COW.py305
1 files changed, 305 insertions, 0 deletions
diff --git a/bitbake/lib/bb/COW.py b/bitbake/lib/bb/COW.py
new file mode 100644
index 0000000000..826d435f98
--- /dev/null
+++ b/bitbake/lib/bb/COW.py
@@ -0,0 +1,305 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3"""
4This is a copy on write dictionary and set which abuses classes to try and be nice and fast.
5
6Please Note:
7 Be careful when using mutable types (ie Dict and Lists) - operations involving these are SLOW.
8 Assign a file to __warn__ to get warnings about slow operations.
9"""
10
11from inspect import getmro
12
13import copy
14import types, sets
15types.ImmutableTypes = tuple([ \
16 types.BooleanType, \
17 types.ComplexType, \
18 types.FloatType, \
19 types.IntType, \
20 types.LongType, \
21 types.NoneType, \
22 types.TupleType, \
23 sets.ImmutableSet] + \
24 list(types.StringTypes))
25
26MUTABLE = "__mutable__"
27
28class COWMeta(type):
29 pass
30
31class COWDictMeta(COWMeta):
32 __warn__ = False
33 __hasmutable__ = False
34 __marker__ = tuple()
35
36 def __str__(cls):
37 # FIXME: I have magic numbers!
38 return "<COWDict Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) - 3)
39 __repr__ = __str__
40
41 def cow(cls):
42 class C(cls):
43 __count__ = cls.__count__ + 1
44 return C
45 copy = cow
46 __call__ = cow
47
48 def __setitem__(cls, key, value):
49 if not isinstance(value, types.ImmutableTypes):
50 if not isinstance(value, COWMeta):
51 cls.__hasmutable__ = True
52 key += MUTABLE
53 setattr(cls, key, value)
54
55 def __getmutable__(cls, key, readonly=False):
56 nkey = key + MUTABLE
57 try:
58 return cls.__dict__[nkey]
59 except KeyError:
60 pass
61
62 value = getattr(cls, nkey)
63 if readonly:
64 return value
65
66 if not cls.__warn__ is False and not isinstance(value, COWMeta):
67 print >> cls.__warn__, "Warning: Doing a copy because %s is a mutable type." % key
68 try:
69 value = value.copy()
70 except AttributeError, e:
71 value = copy.copy(value)
72 setattr(cls, nkey, value)
73 return value
74
75 __getmarker__ = []
76 def __getreadonly__(cls, key, default=__getmarker__):
77 """\
78 Get a value (even if mutable) which you promise not to change.
79 """
80 return cls.__getitem__(key, default, True)
81
82 def __getitem__(cls, key, default=__getmarker__, readonly=False):
83 try:
84 try:
85 value = getattr(cls, key)
86 except AttributeError:
87 value = cls.__getmutable__(key, readonly)
88
89 # This is for values which have been deleted
90 if value is cls.__marker__:
91 raise AttributeError("key %s does not exist." % key)
92
93 return value
94 except AttributeError, e:
95 if not default is cls.__getmarker__:
96 return default
97
98 raise KeyError(str(e))
99
100 def __delitem__(cls, key):
101 cls.__setitem__(key, cls.__marker__)
102
103 def __revertitem__(cls, key):
104 if not cls.__dict__.has_key(key):
105 key += MUTABLE
106 delattr(cls, key)
107
108 def has_key(cls, key):
109 value = cls.__getreadonly__(key, cls.__marker__)
110 if value is cls.__marker__:
111 return False
112 return True
113
114 def iter(cls, type, readonly=False):
115 for key in dir(cls):
116 if key.startswith("__"):
117 continue
118
119 if key.endswith(MUTABLE):
120 key = key[:-len(MUTABLE)]
121
122 if type == "keys":
123 yield key
124
125 try:
126 if readonly:
127 value = cls.__getreadonly__(key)
128 else:
129 value = cls[key]
130 except KeyError:
131 continue
132
133 if type == "values":
134 yield value
135 if type == "items":
136 yield (key, value)
137 raise StopIteration()
138
139 def iterkeys(cls):
140 return cls.iter("keys")
141 def itervalues(cls, readonly=False):
142 if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
143 print >> cls.__warn__, "Warning: If you arn't going to change any of the values call with True."
144 return cls.iter("values", readonly)
145 def iteritems(cls, readonly=False):
146 if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
147 print >> cls.__warn__, "Warning: If you arn't going to change any of the values call with True."
148 return cls.iter("items", readonly)
149
150class COWSetMeta(COWDictMeta):
151 def __str__(cls):
152 # FIXME: I have magic numbers!
153 return "<COWSet Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) -3)
154 __repr__ = __str__
155
156 def cow(cls):
157 class C(cls):
158 __count__ = cls.__count__ + 1
159 return C
160
161 def add(cls, value):
162 COWDictMeta.__setitem__(cls, repr(hash(value)), value)
163
164 def remove(cls, value):
165 COWDictMeta.__delitem__(cls, repr(hash(value)))
166
167 def __in__(cls, value):
168 return COWDictMeta.has_key(repr(hash(value)))
169
170 def iterkeys(cls):
171 raise TypeError("sets don't have keys")
172
173 def iteritems(cls):
174 raise TypeError("sets don't have 'items'")
175
176# These are the actual classes you use!
177class COWDictBase(object):
178 __metaclass__ = COWDictMeta
179 __count__ = 0
180
181class COWSetBase(object):
182 __metaclass__ = COWSetMeta
183 __count__ = 0
184
185if __name__ == "__main__":
186 import sys
187 COWDictBase.__warn__ = sys.stderr
188 a = COWDictBase()
189 print "a", a
190
191 a['a'] = 'a'
192 a['b'] = 'b'
193 a['dict'] = {}
194
195 b = a.copy()
196 print "b", b
197 b['c'] = 'b'
198
199 print
200
201 print "a", a
202 for x in a.iteritems():
203 print x
204 print "--"
205 print "b", b
206 for x in b.iteritems():
207 print x
208 print
209
210 b['dict']['a'] = 'b'
211 b['a'] = 'c'
212
213 print "a", a
214 for x in a.iteritems():
215 print x
216 print "--"
217 print "b", b
218 for x in b.iteritems():
219 print x
220 print
221
222 try:
223 b['dict2']
224 except KeyError, e:
225 print "Okay!"
226
227 a['set'] = COWSetBase()
228 a['set'].add("o1")
229 a['set'].add("o1")
230 a['set'].add("o2")
231
232 print "a", a
233 for x in a['set'].itervalues():
234 print x
235 print "--"
236 print "b", b
237 for x in b['set'].itervalues():
238 print x
239 print
240
241 b['set'].add('o3')
242
243 print "a", a
244 for x in a['set'].itervalues():
245 print x
246 print "--"
247 print "b", b
248 for x in b['set'].itervalues():
249 print x
250 print
251
252 a['set2'] = set()
253 a['set2'].add("o1")
254 a['set2'].add("o1")
255 a['set2'].add("o2")
256
257 print "a", a
258 for x in a.iteritems():
259 print x
260 print "--"
261 print "b", b
262 for x in b.iteritems(readonly=True):
263 print x
264 print
265
266 del b['b']
267 try:
268 print b['b']
269 except KeyError:
270 print "Yay! deleted key raises error"
271
272 if b.has_key('b'):
273 print "Boo!"
274 else:
275 print "Yay - has_key with delete works!"
276
277 print "a", a
278 for x in a.iteritems():
279 print x
280 print "--"
281 print "b", b
282 for x in b.iteritems(readonly=True):
283 print x
284 print
285
286 b.__revertitem__('b')
287
288 print "a", a
289 for x in a.iteritems():
290 print x
291 print "--"
292 print "b", b
293 for x in b.iteritems(readonly=True):
294 print x
295 print
296
297 b.__revertitem__('dict')
298 print "a", a
299 for x in a.iteritems():
300 print x
301 print "--"
302 print "b", b
303 for x in b.iteritems(readonly=True):
304 print x
305 print