Browse Source

optimizations to overloaded functions

Joe Shochet 21 years ago
parent
commit
b8613bcccb
2 changed files with 67 additions and 35 deletions
  1. 53 19
      direct/src/ffi/FFIOverload.py
  2. 14 16
      direct/src/ffi/FFISpecs.py

+ 53 - 19
direct/src/ffi/FFIOverload.py

@@ -341,20 +341,49 @@ class FFIMethodArgumentTree:
     def traverse(self, file, nesting, level):
         oneTreeHasArgs = 0
         typeNameList = []
+
+        # First see if this tree branches at all. If it does not there are
+        # drastic optimizations we can take because we can simply call the
+        # bottom-most function. We are not checking the types of all the
+        # arguments for the sake of type checking, we are simply trying to
+        # figure out which overloaded function to call. If there is only
+        # one overloaded function with this number of arguements at this
+        # level, it must be the one. No need to continue checking all the
+        # arguments.
+        branches = 0
+        subTree = self
+        prevTree = subTree
+        levelCopy = level
+
+        while subTree:
+            if (len(subTree.tree.keys()) == 0):
+                # Dead end branch
+                break
+            if (len(subTree.tree.keys()) > 1):
+                # Ok, we branch, it was worth a try though
+                branches = 1
+                break
+            
+            prevTree = subTree
+            # Must only have one subtree, traverse it
+            subTree = subTree.tree.values()[0][0]
+            levelCopy += 1
+
+        # If there were no branches, this is easy
+        # Just output the function and return
+        # Note this operates on prevTree because subTree went one too far
+        if not branches:
+            methodSpec = prevTree.tree.values()[0][1]
+            indent(file, nesting+2, 'return ')
+            methodSpec.outputOverloadedCall(file, prevTree.classTypeDesc, levelCopy)
+            return
+
+        # Ok, We must have a branch down here somewhere
         # Make a copy of the keys so we can sort them in place
         sortedKeys = self.tree.keys()
         # Sort the keys based on inheritance hierarchy, most specific classes first
         sortedKeys.sort(subclass)
-        # Import everybody we need
-        for i in range(len(sortedKeys)):
-            typeDesc = sortedKeys[i]
-            if ((typeDesc != 0) and
-                (not typeDesc.isNested) and
-                # Do not put our own module in the import list
-                (self.classTypeDesc != typeDesc) and
-                # If this is a class (not a primitive), put it on the list
-                (typeDesc.__class__ == FFITypes.ClassTypeDescriptor)):
-                indent(file, nesting+2, 'import ' + typeDesc.foreignTypeName + '\n')
+
         for i in range(len(sortedKeys)):
             typeDesc = sortedKeys[i]
             # See if this takes no arguments
@@ -364,6 +393,15 @@ class FFIMethodArgumentTree:
                 indent(file, nesting+2, 'return ')
                 methodSpec.outputOverloadedCall(file, self.classTypeDesc, 0)
             else:
+                # Import a file if we need to for this typeDesc
+                if ((typeDesc != 0) and
+                    (not typeDesc.isNested) and
+                    # Do not put our own module in the import list
+                    (self.classTypeDesc != typeDesc) and
+                    # If this is a class (not a primitive), put it on the list
+                    (typeDesc.__class__ == FFITypes.ClassTypeDescriptor)):
+                    indent(file, nesting+2, 'import ' + typeDesc.foreignTypeName + '\n')
+
                 # Specify that at least one of these trees had arguments
                 # so we know to output an else clause
                 oneTreeHasArgs = 1
@@ -384,23 +422,19 @@ class FFIMethodArgumentTree:
                                       + 'types.IntType'
                                       + '))')
                     
-                if (i == 0):
-                    indent(file, nesting+2, 'if ' + condition + ':\n')
-                else:
-                    indent(file, nesting+2, 'elif ' + condition + ':\n')
-                # Get to the bottom of this chain
-                if (self.tree[typeDesc][0] != None):
+                indent(file, nesting+2, 'if ' + condition + ':\n')
+                    
+                if (self.tree[typeDesc][0] is not None):
                     self.tree[typeDesc][0].traverse(file, nesting+1, level+1)
                 else:
-                    # Output the function
                     methodSpec = self.tree[typeDesc][1]
                     indent(file, nesting+3, 'return ')
                     numArgs = level+1
                     methodSpec.outputOverloadedCall(file, self.classTypeDesc, numArgs)
+
         # Output an else clause if one of the trees had arguments
         if oneTreeHasArgs:
-            indent(file, nesting+2, 'else:\n')
-            indent(file, nesting+3, "raise TypeError, 'Invalid argument " + `level` + ", expected one of: ")
+            indent(file, nesting+2, "raise TypeError, 'Invalid argument " + `level` + ", expected one of: ")
             for name in typeNameList:
                 indent(file, 0, ('<' + name + '> '))
             indent(file, 0, "'\n")

+ 14 - 16
direct/src/ffi/FFISpecs.py

@@ -101,9 +101,9 @@ class FunctionSpecification:
         """
         Write the function call to call this overloaded method
         For example:
-          self.overloaded_setPos_ptrNodePath_float_float_float(_args[0], _args[1], _args[2])
+          self.overloaded_setPos_ptrNodePath_float_float_float(*_args)
         If it is a class (static) method, call the class method
-          Class.overloaded_setPos_ptrNodePath_float_float_float(_args[0], _args[1], _args[2])
+          Class.overloaded_setPos_ptrNodePath_float_float_float(*_args)
 
         Constructors are not treated as static. They are special because
         they are not really constructors, they are instance methods that fill
@@ -117,22 +117,20 @@ class FunctionSpecification:
         """
         if classTypeDesc:
             if (self.isStatic() and not self.isConstructor()):
-                indent(file, 0, classTypeDesc.foreignTypeName + '.' + self.getFinalName() + '(')
+                if numArgs:
+                    indent(file, 0, classTypeDesc.foreignTypeName + '.' + self.getFinalName() + '(*_args)\n')
+                else:
+                    indent(file, 0, classTypeDesc.foreignTypeName + '.' + self.getFinalName() + '()\n')
             else:
-                indent(file, 0, 'self.' + self.getFinalName() + '(')
-
-            for i in range(numArgs):
-                file.write('_args[' + `i` + ']')
-                if (i != (numArgs - 1)):
-                    file.write(', ')
-            file.write(')\n')
+                if numArgs:
+                    indent(file, 0, 'self.' + self.getFinalName() + '(*_args)\n')
+                else:
+                    indent(file, 0, 'self.' + self.getFinalName() + '()\n')
         else:
-            indent(file, 0, self.getFinalName() + '(')
-            for i in range(numArgs):
-                file.write('_args[' + `i` + ']')
-                if (i != (numArgs - 1)):
-                    file.write(', ')
-            file.write(')\n')
+            if numArgs:
+                indent(file, 0, self.getFinalName() + '(*_args)\n')
+            else:
+                indent(file, 0, self.getFinalName() + '()\n')
             
 
 class GlobalFunctionSpecification(FunctionSpecification):