فهرست منبع

breadth-first search

Darren Ranalli 19 سال پیش
والد
کامیت
431d855513
1فایلهای تغییر یافته به همراه136 افزوده شده و 56 حذف شده
  1. 136 56
      direct/src/showbase/ContainerReport.py

+ 136 - 56
direct/src/showbase/ContainerReport.py

@@ -1,28 +1,49 @@
-from direct.showbase.PythonUtil import Stack, fastRepr, invertDictLossless
+from direct.showbase.PythonUtil import Queue, fastRepr, invertDictLossless
 from direct.showbase.PythonUtil import itype, safeRepr
 from direct.showbase.PythonUtil import itype, safeRepr
 import types
 import types
 
 
+"""
+import types;from direct.showbase.ContainerReport import ContainerReport;ContainerReport().log()
+"""
+
 class ContainerReport:
 class ContainerReport:
-    def __init__(self, rootObj, rootObjName=None):
-        self._rootObj = rootObj
-        if rootObjName is None:
-            rootObjName = repr(rootObj)
+    PrivateIds = set()
+    def __init__(self, name, log=False, limit=None):
+        self._name = name
         self._visitedIds = set()
         self._visitedIds = set()
         self._id2pathStr = {}
         self._id2pathStr = {}
         self._id2container = {}
         self._id2container = {}
-        self._id2len = {}
-        self._stack = Stack()
-        self._stack.push(rootObj)
-        self._id2pathStr[id(rootObj)] = rootObjName
+        self._type2id2len = {}
+        self._instanceDictIds = set()
+        # for breadth-first searching
+        self._queue = Queue()
+        ContainerReport.PrivateIds.update(set([
+            id(self._visitedIds),
+            id(self._id2pathStr),
+            id(self._id2container),
+            id(self._type2id2len),
+            id(self._queue),
+            id(self._instanceDictIds),
+            ]))
+        self._queue.push(__builtins__)
+        self._id2pathStr[id(__builtins__)] = ''
         self._traverse()
         self._traverse()
+        if log:
+            self.log(limit=limit)
     def _examine(self, obj):
     def _examine(self, obj):
         # return False if it's an object that can't contain or lead to other objects
         # return False if it's an object that can't contain or lead to other objects
         if type(obj) in (types.BooleanType, types.BuiltinFunctionType,
         if type(obj) in (types.BooleanType, types.BuiltinFunctionType,
                          types.BuiltinMethodType, types.ComplexType,
                          types.BuiltinMethodType, types.ComplexType,
                          types.FloatType, types.IntType, types.LongType,
                          types.FloatType, types.IntType, types.LongType,
                          types.NoneType, types.NotImplementedType,
                          types.NoneType, types.NotImplementedType,
-                         types.TypeType, types.CodeType):
+                         types.TypeType, types.CodeType, types.FunctionType):
+            return False
+        # if it's an internal object, ignore it
+        if id(obj) in ContainerReport.PrivateIds:
             return False
             return False
+        # this object might lead to more objects. put it on the queue
+        self._queue.push(obj)
+        # if it's a container, put it in the tables
         try:
         try:
             length = len(obj)
             length = len(obj)
         except:
         except:
@@ -30,65 +51,124 @@ class ContainerReport:
         if length is not None and length > 0:
         if length is not None and length > 0:
             objId = id(obj)
             objId = id(obj)
             self._id2container[objId] = obj
             self._id2container[objId] = obj
-            self._id2len[objId] = length
+            self._type2id2len.setdefault(type(obj), {})
+            self._type2id2len[type(obj)][objId] = length
         return True
         return True
     def _traverse(self):
     def _traverse(self):
-        while len(self._stack) > 0:
-            obj = self._stack.pop()
-            #print '_traverse: %s' % fastRepr(obj, 30)
+        while len(self._queue) > 0:
+            parentObj = self._queue.pop()
+            #print '%s: %s, %s' % (id(parentObj), type(parentObj), fastRepr(parentObj))
+            isInstanceDict = False
+            if id(parentObj) in self._instanceDictIds:
+                isInstanceDict = True
+
             try:
             try:
-                dirList = dir(obj)
+                if parentObj.__class__.__name__ == 'method-wrapper':
+                    continue
             except:
             except:
                 pass
                 pass
-            else:
-                for name in dirList:
-                    if name[-2:] == '__':
-                        continue
-                    attr = getattr(obj, name)
+
+            if type(parentObj) in (types.StringType, types.UnicodeType):
+                continue
+            
+            if type(parentObj) in (types.ModuleType, types.InstanceType):
+                child = parentObj.__dict__
+                if self._examine(child):
+                    assert _equal(self._queue.back(), child)
+                    self._instanceDictIds.add(id(child))
+                    self._id2pathStr[id(child)] = str(self._id2pathStr[id(parentObj)])
+                continue
+
+            if type(parentObj) is types.DictType:
+                key = None
+                attr = None
+                for key, attr in parentObj.items():
                     if id(attr) not in self._visitedIds:
                     if id(attr) not in self._visitedIds:
                         self._visitedIds.add(id(attr))
                         self._visitedIds.add(id(attr))
                         if self._examine(attr):
                         if self._examine(attr):
-                            self._id2pathStr[id(attr)] = self._id2pathStr[id(obj)] + '.%s' % name
-                            self._stack.push(attr)
-            if type(obj) not in (types.StringType, types.UnicodeType):
-                if type(obj) is types.DictType:
-                    keys = obj.keys()
-                    for key in keys:
-                        attr = obj[key]
-                        if id(attr) not in self._visitedIds:
-                            self._visitedIds.add(id(attr))
-                            if self._examine(attr):
-                                self._id2pathStr[id(attr)] = self._id2pathStr[id(obj)] + '[%s]' % safeRepr(key)
-                                self._stack.push(attr)
-                elif type(obj) is not types.FileType:
+                            assert _equal(self._queue.back(), attr)
+                            if parentObj is __builtins__:
+                                self._id2pathStr[id(attr)] = key
+                            else:
+                                if isInstanceDict:
+                                    self._id2pathStr[id(attr)] = self._id2pathStr[id(parentObj)] + '.%s' % key
+                                else:
+                                    self._id2pathStr[id(attr)] = self._id2pathStr[id(parentObj)] + '[%s]' % safeRepr(key)
+                del key
+                del attr
+                continue
+
+            if type(parentObj) is not types.FileType:
+                try:
+                    itr = iter(parentObj)
+                except:
+                    pass
+                else:
                     try:
                     try:
-                        itr = iter(obj)
-                    except:
+                        index = 0
+                        while 1:
+                            try:
+                                attr = itr.next()
+                            except:
+                                # some custom classes don't do well when iterated
+                                attr = None
+                                break
+                            if id(attr) not in self._visitedIds:
+                                self._visitedIds.add(id(attr))
+                                if self._examine(attr):
+                                    assert _equal(self._queue.back(), attr)
+                                    self._id2pathStr[id(attr)] = self._id2pathStr[id(parentObj)] + '[%s]' % index
+                            index += 1
+                        del attr
+                    except StopIteration, e:
                         pass
                         pass
-                    else:
-                        try:
-                            index = 0
-                            while 1:
-                                try:
-                                    attr = itr.next()
-                                except:
-                                    # some custom classes don't do well when iterated
-                                    break
-                                if id(attr) not in self._visitedIds:
-                                    self._visitedIds.add(id(attr))
-                                    if self._examine(attr):
-                                        self._id2pathStr[id(attr)] = self._id2pathStr[id(obj)] + '[%s]' % index
-                                        self._stack.push(attr)
-                                index += 1
-                        except StopIteration, e:
-                            pass
-        
-    def __repr__(self):
-        len2ids = invertDictLossless(self._id2len)
+                    del itr
+                    continue
+
+            try:
+                childNames = dir(parentObj)
+            except:
+                pass
+            else:
+                childName = None
+                child = None
+                for childName in childNames:
+                    child = getattr(parentObj, childName)
+                    if id(child) not in self._visitedIds:
+                        self._visitedIds.add(id(child))
+                        if self._examine(child):
+                            assert _equal(self._queue.back(), child)
+                            self._id2pathStr[id(child)] = self._id2pathStr[id(parentObj)] + '.%s' % childName
+                del childName
+                del child
+                continue
+
+    def _outputType(self, type, limit=None):
+        if type not in self._type2id2len:
+            return
+        len2ids = invertDictLossless(self._type2id2len[type])
         lengths = len2ids.keys()
         lengths = len2ids.keys()
         lengths.sort()
         lengths.sort()
         lengths.reverse()
         lengths.reverse()
+        print '====='
+        print '===== %s' % type
+        count = 0
+        stop = False
         for l in lengths:
         for l in lengths:
             for id in len2ids[l]:
             for id in len2ids[l]:
                 obj = self._id2container[id]
                 obj = self._id2container[id]
-                print '%s: %s: %s' % (l, repr(itype(obj)), self._id2pathStr[id])
+                print '%s: %s' % (l, self._id2pathStr[id])
+                count += 1
+                if limit is not None and count >= limit:
+                    return
+
+    def _output(self, **kArgs):
+        initialTypes = (types.DictType, types.ListType, types.TupleType)
+        for type in initialTypes:
+            self._outputType(type, **kArgs)
+        otherTypes = set(self._type2id2len.keys()).difference(set(initialTypes))
+        for type in otherTypes:
+            self._outputType(type, **kArgs)
+
+    def log(self, **kArgs):
+        self._output(**kArgs)