summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/COW.py
diff options
context:
space:
mode:
authorRichard Purdie <richard@openedhand.com>2006-11-16 15:02:15 +0000
committerRichard Purdie <richard@openedhand.com>2006-11-16 15:02:15 +0000
commit306b7c7a9757ead077363074e7bbac2e5c03e7c5 (patch)
tree6935017a9af749c46816881c86258f514384ba1c /bitbake/lib/bb/COW.py
parent65930a38e415ae4a0182e1cea1be838e0ada50ee (diff)
downloadopenembedded-core-contrib-306b7c7a9757ead077363074e7bbac2e5c03e7c5.tar.gz
bitbake: Upgrade from 1.4 -> 1.7.4ish
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@863 311d38ba-8fff-0310-9ca6-ca027cbcb966
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 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+This is a copy on write dictionary and set which abuses classes to try and be nice and fast.
+
+Please Note:
+ Be careful when using mutable types (ie Dict and Lists) - operations involving these are SLOW.
+ Assign a file to __warn__ to get warnings about slow operations.
+"""
+
+from inspect import getmro
+
+import copy
+import types, sets
+types.ImmutableTypes = tuple([ \
+ types.BooleanType, \
+ types.ComplexType, \
+ types.FloatType, \
+ types.IntType, \
+ types.LongType, \
+ types.NoneType, \
+ types.TupleType, \
+ sets.ImmutableSet] + \
+ list(types.StringTypes))
+
+MUTABLE = "__mutable__"
+
+class COWMeta(type):
+ pass
+
+class COWDictMeta(COWMeta):
+ __warn__ = False
+ __hasmutable__ = False
+ __marker__ = tuple()
+
+ def __str__(cls):
+ # FIXME: I have magic numbers!
+ return "<COWDict Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) - 3)
+ __repr__ = __str__
+
+ def cow(cls):
+ class C(cls):
+ __count__ = cls.__count__ + 1
+ return C
+ copy = cow
+ __call__ = cow
+
+ def __setitem__(cls, key, value):
+ if not isinstance(value, types.ImmutableTypes):
+ if not isinstance(value, COWMeta):
+ cls.__hasmutable__ = True
+ key += MUTABLE
+ setattr(cls, key, value)
+
+ def __getmutable__(cls, key, readonly=False):
+ nkey = key + MUTABLE
+ try:
+ return cls.__dict__[nkey]
+ except KeyError:
+ pass
+
+ value = getattr(cls, nkey)
+ if readonly:
+ return value
+
+ if not cls.__warn__ is False and not isinstance(value, COWMeta):
+ print >> cls.__warn__, "Warning: Doing a copy because %s is a mutable type." % key
+ try:
+ value = value.copy()
+ except AttributeError, e:
+ value = copy.copy(value)
+ setattr(cls, nkey, value)
+ return value
+
+ __getmarker__ = []
+ def __getreadonly__(cls, key, default=__getmarker__):
+ """\
+ Get a value (even if mutable) which you promise not to change.
+ """
+ return cls.__getitem__(key, default, True)
+
+ def __getitem__(cls, key, default=__getmarker__, readonly=False):
+ try:
+ try:
+ value = getattr(cls, key)
+ except AttributeError:
+ value = cls.__getmutable__(key, readonly)
+
+ # This is for values which have been deleted
+ if value is cls.__marker__:
+ raise AttributeError("key %s does not exist." % key)
+
+ return value
+ except AttributeError, e:
+ if not default is cls.__getmarker__:
+ return default
+
+ raise KeyError(str(e))
+
+ def __delitem__(cls, key):
+ cls.__setitem__(key, cls.__marker__)
+
+ def __revertitem__(cls, key):
+ if not cls.__dict__.has_key(key):
+ key += MUTABLE
+ delattr(cls, key)
+
+ def has_key(cls, key):
+ value = cls.__getreadonly__(key, cls.__marker__)
+ if value is cls.__marker__:
+ return False
+ return True
+
+ def iter(cls, type, readonly=False):
+ for key in dir(cls):
+ if key.startswith("__"):
+ continue
+
+ if key.endswith(MUTABLE):
+ key = key[:-len(MUTABLE)]
+
+ if type == "keys":
+ yield key
+
+ try:
+ if readonly:
+ value = cls.__getreadonly__(key)
+ else:
+ value = cls[key]
+ except KeyError:
+ continue
+
+ if type == "values":
+ yield value
+ if type == "items":
+ yield (key, value)
+ raise StopIteration()
+
+ def iterkeys(cls):
+ return cls.iter("keys")
+ def itervalues(cls, readonly=False):
+ if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
+ print >> cls.__warn__, "Warning: If you arn't going to change any of the values call with True."
+ return cls.iter("values", readonly)
+ def iteritems(cls, readonly=False):
+ if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
+ print >> cls.__warn__, "Warning: If you arn't going to change any of the values call with True."
+ return cls.iter("items", readonly)
+
+class COWSetMeta(COWDictMeta):
+ def __str__(cls):
+ # FIXME: I have magic numbers!
+ return "<COWSet Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) -3)
+ __repr__ = __str__
+
+ def cow(cls):
+ class C(cls):
+ __count__ = cls.__count__ + 1
+ return C
+
+ def add(cls, value):
+ COWDictMeta.__setitem__(cls, repr(hash(value)), value)
+
+ def remove(cls, value):
+ COWDictMeta.__delitem__(cls, repr(hash(value)))
+
+ def __in__(cls, value):
+ return COWDictMeta.has_key(repr(hash(value)))
+
+ def iterkeys(cls):
+ raise TypeError("sets don't have keys")
+
+ def iteritems(cls):
+ raise TypeError("sets don't have 'items'")
+
+# These are the actual classes you use!
+class COWDictBase(object):
+ __metaclass__ = COWDictMeta
+ __count__ = 0
+
+class COWSetBase(object):
+ __metaclass__ = COWSetMeta
+ __count__ = 0
+
+if __name__ == "__main__":
+ import sys
+ COWDictBase.__warn__ = sys.stderr
+ a = COWDictBase()
+ print "a", a
+
+ a['a'] = 'a'
+ a['b'] = 'b'
+ a['dict'] = {}
+
+ b = a.copy()
+ print "b", b
+ b['c'] = 'b'
+
+ print
+
+ print "a", a
+ for x in a.iteritems():
+ print x
+ print "--"
+ print "b", b
+ for x in b.iteritems():
+ print x
+ print
+
+ b['dict']['a'] = 'b'
+ b['a'] = 'c'
+
+ print "a", a
+ for x in a.iteritems():
+ print x
+ print "--"
+ print "b", b
+ for x in b.iteritems():
+ print x
+ print
+
+ try:
+ b['dict2']
+ except KeyError, e:
+ print "Okay!"
+
+ a['set'] = COWSetBase()
+ a['set'].add("o1")
+ a['set'].add("o1")
+ a['set'].add("o2")
+
+ print "a", a
+ for x in a['set'].itervalues():
+ print x
+ print "--"
+ print "b", b
+ for x in b['set'].itervalues():
+ print x
+ print
+
+ b['set'].add('o3')
+
+ print "a", a
+ for x in a['set'].itervalues():
+ print x
+ print "--"
+ print "b", b
+ for x in b['set'].itervalues():
+ print x
+ print
+
+ a['set2'] = set()
+ a['set2'].add("o1")
+ a['set2'].add("o1")
+ a['set2'].add("o2")
+
+ print "a", a
+ for x in a.iteritems():
+ print x
+ print "--"
+ print "b", b
+ for x in b.iteritems(readonly=True):
+ print x
+ print
+
+ del b['b']
+ try:
+ print b['b']
+ except KeyError:
+ print "Yay! deleted key raises error"
+
+ if b.has_key('b'):
+ print "Boo!"
+ else:
+ print "Yay - has_key with delete works!"
+
+ print "a", a
+ for x in a.iteritems():
+ print x
+ print "--"
+ print "b", b
+ for x in b.iteritems(readonly=True):
+ print x
+ print
+
+ b.__revertitem__('b')
+
+ print "a", a
+ for x in a.iteritems():
+ print x
+ print "--"
+ print "b", b
+ for x in b.iteritems(readonly=True):
+ print x
+ print
+
+ b.__revertitem__('dict')
+ print "a", a
+ for x in a.iteritems():
+ print x
+ print "--"
+ print "b", b
+ for x in b.iteritems(readonly=True):
+ print x
+ print