data_smart: Micro optimisation - search for "${" instead of "$"
[vuplus_bitbake] / lib / bb / data_smart.py
index 01d3891..d63fdde 100644 (file)
@@ -29,14 +29,12 @@ Based on functions from the base bb module, Copyright 2003 Holger Schurig
 """
 
 import copy, os, re, sys, time, types
-from bb   import note, debug, error, fatal, utils, methodpool
+import bb
+from bb   import utils, methodpool
+from COW  import COWDictBase
 from sets import Set
+from new  import classobj
 
-try:
-    import cPickle as pickle
-except ImportError:
-    import pickle
-    print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
 
 __setvar_keyword__ = ["_append","_prepend"]
 __setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?')
@@ -44,84 +42,15 @@ __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
 __expand_python_regexp__ = re.compile(r"\${@.+?}")
 
 
-#=====
-#
-# Helper Class
-#
-#====
-class ParentDictSet:
-    """
-    To avoid DeepCopies of shared dictionaries
-    we use a COW/parenting pattern.
-
-    This class looks like a dictionary. If we
-    set a key that is also present in the parent
-    we will make a copy of it.
-
-    Currently it is not possible to remove keys
-    """
-
-    def __init__(self, parent=None):
-        self._dict = {}
-
-        #set the parent of this dict
-        #and save the lists of keys
-        if parent:
-            self._dict['_PARENT_OF_DICT'] = parent._dict
-            self._keys = parent._keys
-        else:
-            self._keys = []
-
-    def _crazy_lookup(self, dict, name):
-        # crazy lookup
-        while dict:
-            if name in dict:
-                return (dict[name],True)
-            elif '_PARENT_OF_DICT' in dict:
-                dict = dict['_PARENT_OF_DICT']
-            else:
-                break
-
-        return (None,False)
-
-
-    def get(self, name):
-        (var,found) = self._crazy_lookup(self._dict, name)
-
-        return var
-
-    def add(self, name, value):
-        #
-        # Check if we have the key already locally
-        #
-        if name in self._dict:
-            self._dict[name].add( value )
-            return
-
-        #
-        # Check if the key is used by our parent
-        #
-        if '_PARENT_OF_DICT' in self._dict:
-            (var,found) = self._crazy_lookup(self._dict['_PARENT_OF_DICT'], name)
-            if found:
-                self._dict[name] = copy.copy(var)
-                self._dict[name].add(value)
-        else:
-            # a new name is born
-            self._keys.append(name)
-            self._dict[name] = Set()
-            self._dict[name].add(value)
-
-    def keys(self):
-        return self._keys
-
 class DataSmart:
-    def __init__(self):
+    def __init__(self, special = COWDictBase.copy(), seen = COWDictBase.copy() ):
         self.dict = {}
 
         # cookie monster tribute
-        self._special_values = ParentDictSet()
-        self._seen_overrides = ParentDictSet()
+        self._special_values = special
+        self._seen_overrides = seen
+
+        self.expand_cache = {}
 
     def expand(self,s, varname):
         def var_sub(match):
@@ -146,22 +75,30 @@ class DataSmart:
         if type(s) is not types.StringType: # sanity check
             return s
 
-        while s.find('$') != -1:
+        if varname and varname in self.expand_cache:
+            return self.expand_cache[varname]
+
+        while s.find('${') != -1:
             olds = s
             try:
                 s = __expand_var_regexp__.sub(var_sub, s)
                 s = __expand_python_regexp__.sub(python_sub, s)
                 if s == olds: break
                 if type(s) is not types.StringType: # sanity check
-                    error('expansion of %s returned non-string %s' % (olds, s))
+                    bb.msg.error(bb.msg.domain.Data, 'expansion of %s returned non-string %s' % (olds, s))
             except KeyboardInterrupt:
                 raise
             except:
-                note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
+                bb.msg.note(1, bb.msg.domain.Data, "%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
                 raise
+
+        if varname:
+            self.expand_cache[varname] = s
+
         return s
 
     def initVar(self, var):
+        self.expand_cache = {}
         if not var in self.dict:
             self.dict[var] = {}
 
@@ -190,6 +127,7 @@ class DataSmart:
             self.initVar(var)
 
     def setVar(self,var,value):
+        self.expand_cache = {}
         match  = __setvar_regexp__.match(var)
         if match and match.group("keyword") in __setvar_keyword__:
             base = match.group('base')
@@ -199,8 +137,13 @@ class DataSmart:
             l.append([value, override])
             self.setVarFlag(base, keyword, l)
 
+            # todo make sure keyword is not __doc__ or __module__
             # pay the cookie monster
-            self._special_values.add( keyword, base )
+            try:
+                self._special_values[keyword].add( base )
+            except:
+                self._special_values[keyword] = Set()
+                self._special_values[keyword].add( base )
 
             return
 
@@ -213,7 +156,9 @@ class DataSmart:
         # more cookies for the cookie monster
         if '_' in var:
             override = var[var.rfind('_')+1:]
-            self._seen_overrides.add( override, var )
+            if not self._seen_overrides.has_key(override):
+                self._seen_overrides[override] = Set()
+            self._seen_overrides[override].add( var )
 
         # setting var
         self.dict[var]["content"] = value
@@ -226,6 +171,7 @@ class DataSmart:
         return value
 
     def delVar(self,var):
+        self.expand_cache = {}
         self.dict[var] = {}
 
     def setVarFlag(self,var,flag,flagvalue):
@@ -295,13 +241,9 @@ class DataSmart:
         Create a copy of self by setting _data to self
         """
         # we really want this to be a DataSmart...
-        data = DataSmart()
+        data = DataSmart(seen=self._seen_overrides.copy(), special=self._special_values.copy())
         data.dict["_data"] = self.dict
 
-        # reparent the dicts
-        data._seen_overrides = ParentDictSet(self._seen_overrides)
-        data._special_values = ParentDictSet(self._special_values)
-
         return data
 
     # Dictionary Methods
@@ -318,18 +260,11 @@ class DataSmart:
         return keytab.keys()
 
     def __getitem__(self,item):
-        start = self.dict
-        while start:
-            if item in start:
-                return start[item]
-            elif "_data" in start:
-                start = start["_data"]
-            else:
-                start = None
-        return None
+        #print "Warning deprecated"
+        return self.getVar(item, False)
 
     def __setitem__(self,var,data):
-        self._makeShadowCopy(var)
-        self.dict[var] = data
+        #print "Warning deprecated"
+        self.setVar(var,data)