special keyword checking code when we know the exact number of arguments
authorStefan Behnel <scoder@users.berlios.de>
Fri, 26 Dec 2008 09:24:12 +0000 (10:24 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Fri, 26 Dec 2008 09:24:12 +0000 (10:24 +0100)
Cython/Compiler/Nodes.py

index 88a77fad85536805e128aabc65e5e42a5989f637..9e215f059bff79237f75a92046431474d33685ac 100644 (file)
@@ -2100,9 +2100,14 @@ class DefNode(FuncDefNode):
                                         kw_only_args, argtuple_error_label, code):
         all_args = tuple(positional_args) + tuple(kw_only_args)
         max_args = len(all_args)
+        all_required = self.num_required_args == len(self.args) \
+            and not self.star_arg and not self.starstar_arg
 
         code.putln("PyObject* values[%d] = {%s};" % (
                 max_args, ('0,'*max_args)[:-1]))
+        if all_required:
+            code.putln('Py_ssize_t kw_count = PyDict_Size(%s);' %
+                       Naming.kwds_cname)
 
         # parse the tuple and check that it's not too long
         code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
@@ -2120,8 +2125,13 @@ class DefNode(FuncDefNode):
 
         # parse all keyword arguments, check for duplicates, etc.
         if not self.num_required_kw_args:
-            code.putln('if (PyDict_Size(%s) > 0) {' % Naming.kwds_cname)
+            if all_required:
+                code.putln('if (kw_count > 0) {')
+            else:
+                code.putln('if (PyDict_Size(%s) > 0) {' % Naming.kwds_cname)
         if self.star_arg:
+            if self.num_required_kw_args:
+                code.putln('{')
             code.putln("const Py_ssize_t used_pos_args = (PyTuple_GET_SIZE(%s) < %d) ? PyTuple_GET_SIZE(%s) : %d;" % (
                     Naming.args_cname, max_positional_args,
                     Naming.args_cname, max_positional_args))
@@ -2137,19 +2147,30 @@ class DefNode(FuncDefNode):
                 pos_arg_count,
                 self.name.utf8encode()))
         code.putln(code.error_goto(self.pos))
-        if not self.num_required_kw_args:
+        if self.star_arg or not self.num_required_kw_args:
             code.putln('}')
 
         # make sure we found all required args
         if self.num_required_args:
-            last_required_arg = -1
-            for i, arg in enumerate(all_args):
-                if not arg.default:
-                    last_required_arg = i
-            use_switch = max_positional_args > 2 # switch has an overhead, too
+            if all_required:
+                # common case: we know the exact number of arguments
+                required_args = all_args
+                if len(required_args) > 1:
+                    code.putln('if (unlikely(PyTuple_GET_SIZE(%s) + kw_count != %d)) {' % (
+                            Naming.args_cname, max_args))
+            else:
+                last_required_arg = -1
+                for i, arg in enumerate(all_args):
+                    if not arg.default:
+                        last_required_arg = i
+                required_args = all_args[:last_required_arg+1]
+            # avoid switch for the simple cases - it has an overhead, too
+            use_switch = max_positional_args > 2 and len(required_args) > 2 \
+                and not all_required # specialised above already
             if use_switch:
-                code.putln('switch (PyTuple_GET_SIZE(%s)) {' % Naming.args_cname)
-            for i, arg in enumerate(all_args[:last_required_arg+1]):
+                code.putln('switch (PyTuple_GET_SIZE(%s)) {' %
+                           Naming.args_cname)
+            for i, arg in enumerate(required_args):
                 if use_switch and i <= max_positional_args:
                     if self.star_arg and i == max_positional_args:
                         code.putln('default:')
@@ -2170,6 +2191,8 @@ class DefNode(FuncDefNode):
                 code.putln('}')
             if use_switch:
                 code.putln('}')
+            if all_required and len(required_args) > 1:
+                code.putln('}')
 
         # convert arg values to their final type and assign them
         for i, arg in enumerate(all_args):