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