diff options
| author | Richard Purdie <richard@openedhand.com> | 2008-09-30 15:08:33 +0000 | 
|---|---|---|
| committer | Richard Purdie <richard@openedhand.com> | 2008-09-30 15:08:33 +0000 | 
| commit | c30eddb243e7e65f67f656e62848a033cf6f2e5c (patch) | |
| tree | 110dd95788b76f55d31cb8d30aac2de8400b6f4a /bitbake-dev/lib/bb/COW.py | |
| parent | 5ef0510474004eeb2ae8a99b64e2febb1920e077 (diff) | |
| download | openembedded-core-c30eddb243e7e65f67f656e62848a033cf6f2e5c.tar.gz openembedded-core-c30eddb243e7e65f67f656e62848a033cf6f2e5c.tar.bz2 openembedded-core-c30eddb243e7e65f67f656e62848a033cf6f2e5c.zip | |
Add bitbake-dev to allow ease of testing and development of bitbake trunk
git-svn-id: https://svn.o-hand.com/repos/poky/trunk@5337 311d38ba-8fff-0310-9ca6-ca027cbcb966
Diffstat (limited to 'bitbake-dev/lib/bb/COW.py')
| -rw-r--r-- | bitbake-dev/lib/bb/COW.py | 320 | 
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 @@ +# 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. +# +# Copyright (C) 2006 Tim Amsell  +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +#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 | 
