<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>sipbenchmark.py</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -25,3 +25,5 @@ sipconfig.py
 .project
 .pydevproject
 
+# temporary benchmark directory
+benchmark/</diff>
      <filename>.gitignore</filename>
    </modified>
    <modified>
      <diff>@@ -5,6 +5,13 @@ print '*'* 80
 print 'python is &quot;%r&quot;' % sys.executable
 print '*'*80
 
+if os.name == 'nt':
+    def bison(cmd):
+        os.system(r'c:\cygwin\bin\bison.exe ' + cmd)
+else:
+    def bison(cmd):
+        os.system('bison ' + cmd)
+
 if not 'build' in sys.argv:
     # usage
     print 'use &quot;python setup.py build&quot; to build SIP'
@@ -13,6 +20,14 @@ else:
     import distutils.sysconfig as s
     s.python_build = True
 
+    print 'Generating parser.c from parser.y...'
+    cwd = os.getcwd()
+    try:
+        os.chdir('sipgen')
+        bison('parser.y -o parser.c')
+    finally:
+        os.chdir(cwd)
+    
     # configures SIP to build locally
     import configure
     args = 'configure.py -b sipgen -d siplib -e siplib -v siplib'.split()</diff>
      <filename>setup.py</filename>
    </modified>
    <modified>
      <diff>@@ -2256,10 +2256,10 @@ static void generateOrdinaryFunction(moduleDef *mod, classDef *cd,
     need_intro = TRUE;
 
     meth_name = md-&gt;pyname-&gt;text;
-    if (!noThreadCheck(md) &amp;&amp; thread_check &amp;&amp; 
-    		strcmp(&quot;SEHGuard&quot;, meth_name) &amp;&amp; strcmp(&quot;CallAfter&quot;, meth_name) &amp;&amp; strcmp(&quot;IsMainThread&quot;, meth_name) &amp;&amp; 
-    		strcmp(&quot;SipNewThread&quot;, meth_name) &amp;&amp; strcmp(&quot;SipEndThread&quot;, meth_name) &amp;&amp; strcmp(&quot;GetApp&quot;, meth_name) &amp;&amp;
-    		strcmp(&quot;GetTopLevelWindows&quot;, meth_name) &amp;&amp; strcmp(&quot;OnFatalException&quot;, meth_name))
+    if (!noThreadCheck(md) &amp;&amp; thread_check &amp;&amp;
+            strcmp(&quot;SEHGuard&quot;, meth_name) &amp;&amp; strcmp(&quot;CallAfter&quot;, meth_name) &amp;&amp; strcmp(&quot;IsMainThread&quot;, meth_name) &amp;&amp;
+            strcmp(&quot;SipNewThread&quot;, meth_name) &amp;&amp; strcmp(&quot;SipEndThread&quot;, meth_name) &amp;&amp; strcmp(&quot;GetApp&quot;, meth_name) &amp;&amp;
+            strcmp(&quot;GetTopLevelWindows&quot;, meth_name) &amp;&amp; strcmp(&quot;OnFatalException&quot;, meth_name))
         prcode(fp,
 &quot;    if (!SIP_THREAD_CHECK) {\n&quot;
 &quot;        SIP_THREAD_ERROR\n&quot;
@@ -3415,6 +3415,7 @@ static void generateMappedTypeCpp(mappedTypeDef *mtd, sipSpec *pt, FILE *fp)
 static void generateClassCpp(classDef *cd, sipSpec *pt, FILE *fp)
 {
     varDef *vd;
+    int nr_variables;
     moduleDef *mod = cd-&gt;iff-&gt;module;
 
     /* Generate any local class code. */
@@ -3425,8 +3426,10 @@ static void generateClassCpp(classDef *cd, sipSpec *pt, FILE *fp)
 
     generateAccessFunctions(pt, mod, cd, fp);
 
+    nr_variables = getNumVariables(pt-&gt;vars, cd);
+
     /* Generate the variable and property handlers. */
-    if (hasVarHandlers(cd))
+    if (nr_variables &amp;&amp; hasVarHandlers(cd))
     {
         for (vd = pt-&gt;vars; vd != NULL; vd = vd-&gt;next)
             if (vd-&gt;ecd == cd &amp;&amp; needsHandler(vd))
@@ -3448,7 +3451,6 @@ static void generateClassCpp(classDef *cd, sipSpec *pt, FILE *fp)
                     ,vd-&gt;pyname,vd-&gt;fqcname,(isStaticVar(vd) ? &quot;METH_STATIC&quot; : &quot;0&quot;));
 
         prcode(fp,
-&quot;    {0, 0, 0, 0}\n&quot;
 &quot;};\n&quot;
             );
     }
@@ -3607,7 +3609,6 @@ static sortedMethTab *createMethodTable(classDef *cd, int *nrp)
     return mtab;
 }
 
-
 /*
  * The qsort helper to compare two sortedMethTab structures based on the Python
  * name of the method.
@@ -4791,17 +4792,17 @@ static void generateSlot(moduleDef *mod, classDef *cd, enumDef *ed,
 int is_wxobject(classDef* cd)
 {
     static const char* baseclass_name = &quot;Window&quot;;
-    
-	classList* superClass;
-	
-	if (0 == strcmp(baseclass_name, cd-&gt;pyname))
-		return 1;
-	
-	for (superClass = cd-&gt;supers; superClass; superClass = superClass-&gt;next)
-		if (0 == strcmp(baseclass_name, superClass-&gt;cd-&gt;pyname) || is_wxobject(superClass-&gt;cd))
-			return 1;
-	
-	return 0;
+
+    classList* superClass;
+
+    if (0 == strcmp(baseclass_name, cd-&gt;pyname))
+        return 1;
+
+    for (superClass = cd-&gt;supers; superClass; superClass = superClass-&gt;next)
+        if (0 == strcmp(baseclass_name, superClass-&gt;cd-&gt;pyname) || is_wxobject(superClass-&gt;cd))
+            return 1;
+
+    return 0;
 }
 
 /*
@@ -4935,11 +4936,11 @@ static void generateClassFunctions(sipSpec *pt, moduleDef *mod, classDef *cd,
              * way to call it which we haven't worked out (because we don't
              * fully understand C++).
              */
-            
+
             if (optWxThreadHop() &amp;&amp; is_wxobject(cd))
             {
-            
-            
+
+
             prcode(fp,
 &quot;    if (!wxIsMainThread()) {\n&quot;);
             if (rgil)
@@ -4971,7 +4972,7 @@ static void generateClassFunctions(sipSpec *pt, moduleDef *mod, classDef *cd,
                 prcode(fp,
 &quot;        { wxCriticalSectionLocker locker(wxPendingDeleteCS);\n&quot;);
 
-            
+
             if (hasShadow(cd))
             {
                 prcode(fp,
@@ -4995,16 +4996,16 @@ static void generateClassFunctions(sipSpec *pt, moduleDef *mod, classDef *cd,
             if (optWxThreadHop() &amp;&amp; is_wxobject(cd) &amp;&amp; (hasShadow(cd) || isPublicDtor(cd)))
                 prcode(fp,
 &quot;        wxPendingDelete.DeleteObject(reinterpret_cast&lt;wxObject*&gt;(sipCppV)); }\n&quot;);
-            
+
             if (rgil)
                 prcode(fp,
 &quot;\n&quot;
 &quot;        Py_END_ALLOW_THREADS\n&quot;
                     );
         }
-        
+
         if (optWxThreadHop() &amp;&amp; is_wxobject(cd) &amp;&amp; (hasShadow(cd) || isPublicDtor(cd)) &amp;&amp; cd-&gt;dealloccode == NULL)
-        	prcode(fp, &quot;    }\n&quot;);
+            prcode(fp, &quot;    }\n&quot;);
 
         prcode(fp,
 &quot;}\n&quot;
@@ -5683,13 +5684,13 @@ static void generateVirtualCatcher(moduleDef *mod, classDef *cd, int virtNr,
 
     if (thread_check)
     {
-        prcode(fp, 
+        prcode(fp,
 &quot;    if (!SIP_THREAD_CHECK) {\n&quot;
 &quot;       SIP_THREAD_ERROR\n&quot;);
         generateVirtHandlerErrorReturn(res,fp);
         prcode(fp,
 &quot;    }\n&quot;);
-        
+
     }
 
     restoreArgs(od-&gt;cppsig);
@@ -8008,6 +8009,21 @@ static void generateSimpleFunctionCall(fcallDef *fcd,FILE *fp)
     prcode(fp,&quot;)&quot;);
 }
 
+/*
+ * Returns the number of exposed variables in a class.
+ */
+static int getNumVariables(varDef *vd, classDef *cd)
+{
+    int varcount = 0;
+
+    while (vd) {
+        if (vd-&gt;ecd == cd &amp;&amp; needsHandler(vd))
+            ++varcount;
+        vd = vd-&gt;next;
+    }
+
+    return varcount;
+}
 
 /*
  * Generate the type structure that contains all the information needed by the
@@ -8016,7 +8032,7 @@ static void generateSimpleFunctionCall(fcallDef *fcd,FILE *fp)
 static void generateTypeDefinition(sipSpec *pt, classDef *cd, FILE *fp)
 {
     const char *mname, *sep;
-    int is_slots, nr_methods, nr_enums;
+    int is_slots, nr_methods, nr_enums, nr_variables;
     int is_inst_class, is_inst_voidp, is_inst_char, is_inst_string;
     int is_inst_int, is_inst_long, is_inst_ulong, is_inst_longlong;
     int is_inst_ulonglong, is_inst_double, is_inst_enum;
@@ -8085,6 +8101,7 @@ static void generateTypeDefinition(sipSpec *pt, classDef *cd, FILE *fp)
     /* Generate the attributes tables. */
     nr_methods = generateMethodTable(cd,fp);
     nr_enums = generateEnumMemberTable(pt, mod, cd, fp);
+    nr_variables = getNumVariables(pt-&gt;vars, cd);
 
     /* Generate each instance table. */
     is_inst_class = generateClasses(pt, mod, cd, fp);
@@ -8202,13 +8219,13 @@ static void generateTypeDefinition(sipSpec *pt, classDef *cd, FILE *fp)
 &quot;    %d, enummembers_%C,\n&quot;
             , nr_enums, classFQCName(cd));
 
-    if (hasVarHandlers(cd))
+    if (nr_variables &amp;&amp; hasVarHandlers(cd))
         prcode(fp,
-&quot;    variables_%C,\n&quot;
-            , classFQCName(cd));
+&quot;    %d, variables_%C,\n&quot;
+            ,nr_variables, classFQCName(cd));
     else
         prcode(fp,
-&quot;    0,\n&quot;
+&quot;    0, 0,\n&quot;
             );
 
     if (canCreate(cd))</diff>
      <filename>sipgen/gencode.c</filename>
    </modified>
    <modified>
      <diff>@@ -5545,6 +5545,31 @@ static void parseFile(FILE *fp, char *name, moduleDef *prevmod, int optional)
         currentContext = pc;
 }
 
+/*
+ * Adds a variable definition to the module.
+ */
+static void insertVariable(sipSpec *pt, varDef *vd)
+{
+    varDef* curr = pt-&gt;vars;
+    varDef* prev = NULL;
+
+    /* sorted linked list insert */
+    while (curr) {
+        if (strcmp(curr-&gt;pyname-&gt;text, vd-&gt;pyname-&gt;text) &gt;= 0)
+            break;
+
+        prev = curr;
+        curr = curr-&gt;next;
+    }
+    
+    if (!prev) {
+        vd-&gt;next = pt-&gt;vars;
+        pt-&gt;vars = vd;
+    } else {
+        prev-&gt;next = vd;
+        vd-&gt;next = curr;
+    }
+}
 
 /*
  * Find an interface file, or create a new one.
@@ -6672,8 +6697,7 @@ static void instantiateTemplateVars(sipSpec *pt, classTmplDef *tcd,
             vd-&gt;getcode = templateCode(pt, used, vd-&gt;getcode, type_names, type_values);
             vd-&gt;setcode = templateCode(pt, used, vd-&gt;setcode, type_names, type_values);
 
-            vd-&gt;next = pt-&gt;vars;
-            pt-&gt;vars = vd;
+            insertVariable(pt, vd);
         }
 }
 
@@ -7108,12 +7132,11 @@ static void newVar(sipSpec *pt,moduleDef *mod,char *name,int isstatic,
     var -&gt; setcode = scode;
     var -&gt; getter = NULL;
     var -&gt; setter = NULL;
-    var -&gt; next = pt -&gt; vars;
 
     if (isstatic || (escope != NULL &amp;&amp; escope-&gt;iff-&gt;type == namespace_iface))
         setIsStaticVar(var);
 
-    pt -&gt; vars = var;
+    insertVariable(pt, var);
 }
 
 </diff>
      <filename>sipgen/parser.c</filename>
    </modified>
    <modified>
      <diff>@@ -2635,6 +2635,31 @@ static void parseFile(FILE *fp, char *name, moduleDef *prevmod, int optional)
         currentContext = pc;
 }
 
+/*
+ * Adds a variable definition to the module.
+ */
+static void insertVariable(sipSpec *pt, varDef *vd)
+{
+    varDef* curr = pt-&gt;vars;
+    varDef* prev = NULL;
+
+    /* sorted linked list insert */
+    while (curr) {
+        if (strcmp(curr-&gt;pyname-&gt;text, vd-&gt;pyname-&gt;text) &gt;= 0)
+            break;
+
+        prev = curr;
+        curr = curr-&gt;next;
+    }
+    
+    if (!prev) {
+        vd-&gt;next = pt-&gt;vars;
+        pt-&gt;vars = vd;
+    } else {
+        prev-&gt;next = vd;
+        vd-&gt;next = curr;
+    }
+}
 
 /*
  * Find an interface file, or create a new one.
@@ -3762,8 +3787,7 @@ static void instantiateTemplateVars(sipSpec *pt, classTmplDef *tcd,
             vd-&gt;getcode = templateCode(pt, used, vd-&gt;getcode, type_names, type_values);
             vd-&gt;setcode = templateCode(pt, used, vd-&gt;setcode, type_names, type_values);
 
-            vd-&gt;next = pt-&gt;vars;
-            pt-&gt;vars = vd;
+            insertVariable(pt, vd);
         }
 }
 
@@ -4198,12 +4222,11 @@ static void newVar(sipSpec *pt,moduleDef *mod,char *name,int isstatic,
     var -&gt; setcode = scode;
     var -&gt; getter = NULL;
     var -&gt; setter = NULL;
-    var -&gt; next = pt -&gt; vars;
 
     if (isstatic || (escope != NULL &amp;&amp; escope-&gt;iff-&gt;type == namespace_iface))
         setIsStaticVar(var);
 
-    pt -&gt; vars = var;
+    insertVariable(pt, var);
 }
 
 </diff>
      <filename>sipgen/parser.y</filename>
    </modified>
    <modified>
      <diff>@@ -283,10 +283,12 @@ void transform(sipSpec *pt)
     }
 
     /* Mark classes that should be registered as Qt meta types. */
+#if SIP_QT
     if (optRegisterTypes(pt))
         for (cd = pt-&gt;classes; cd != NULL; cd = cd-&gt;next)
             if (generatingCodeForModule(pt, cd-&gt;iff-&gt;module))
                 registerMetaType(cd);
+#endif
                 
     /* Autogenerate properties */
     if (optAutoProperties(pt))
@@ -3104,6 +3106,33 @@ static int countNonDefaultArgs(argDef args[], int nrArgs)
 }
 
 /*
+ * Adds a variable definition to the module.
+ */
+static void insertVariable(sipSpec *pt, varDef *vd)
+{
+    varDef* curr = pt-&gt;vars;
+    varDef* prev = NULL;
+    int cmp;
+
+    /* sorted linked list insert */
+    while (curr) {
+        if (strcmp(curr-&gt;pyname-&gt;text, vd-&gt;pyname-&gt;text) &gt;= 0)
+            break;
+
+        prev = curr;
+        curr = curr-&gt;next;
+    }
+    
+    if (!prev) {
+        vd-&gt;next = pt-&gt;vars;
+        pt-&gt;vars = vd;
+    } else {
+        prev-&gt;next = vd;
+        vd-&gt;next = curr;
+    }
+}
+
+/*
  * Add a varDef representing a property for a given getter or setter method.
  */
 static varDef* addOrFindProperty(sipSpec* pt, moduleDef* module, classDef* cd, overDef* over)
@@ -3172,8 +3201,7 @@ static varDef* addOrFindProperty(sipSpec* pt, moduleDef* module, classDef* cd, o
         setIsStaticVar(var);
                 
     /* Append the new variable to the module. */
-    var-&gt;next = pt-&gt;vars;
-    pt-&gt;vars = var;
+    insertVariable(pt, var);
     return var;
 }
 </diff>
      <filename>sipgen/transform.c</filename>
    </modified>
    <modified>
      <diff>@@ -205,8 +205,10 @@ typedef struct _sipWrapperType {
 typedef struct _sipWrapper {
     PyObject_HEAD
 
+#ifdef SIP_USER_OBJECT
     /* For the user to use. */
     PyObject *user;
+#endif
 
     union {
         /* C/C++ object pointer. */
@@ -555,6 +557,9 @@ typedef struct _sipTypeDef {
     /* The table of lazy enum members. */
     sipEnumMemberDef *td_enummembers;
 
+    /* The number of variables. */
+    int td_nrvariables;
+
     /* The variable table. */
     PyMethodDef *td_variables;
 
@@ -614,6 +619,7 @@ typedef struct _sipTypeDef {
     /* The optional PyQt defined information. */
     const void *td_qt;
 #endif
+
 } sipTypeDef;
 
 </diff>
      <filename>siplib/sip.h</filename>
    </modified>
    <modified>
      <diff>@@ -4475,18 +4475,10 @@ static void findLazyAttr(sipWrapperType *wt, char *name, PyMethodDef **pmdp,
             return;
         }
 
-        /* Try the variables.  Note, these aren't sorted. */
-        if (nsx-&gt;td_variables != NULL)
-        {
-            PyMethodDef *md;
-
-            for (md = nsx-&gt;td_variables; md-&gt;ml_name != NULL; ++md)
-                if (strcmp(name, md-&gt;ml_name) == 0)
-                {
-                    *vmdp = md;
-                    return;
-                }
-        }
+        /* Try the variables. */
+        if (nsx-&gt;td_nrvariables &gt; 0 &amp;&amp;
+            (*vmdp = (PyMethodDef *)bsearch(name, nsx-&gt;td_variables, nsx-&gt;td_nrvariables, sizeof (PyMethodDef), compareMethodName)) != NULL)
+            return;
 
         nsx = nsx-&gt;td_nsextender;
     }
@@ -4522,7 +4514,6 @@ static int compareEnumMemberName(const void *key,const void *el)
     return strcmp((const char *)key,((const sipEnumMemberDef *)el)-&gt;em_name);
 }
 
-
 /*
  * Report a function with invalid argument types.
  */</diff>
      <filename>siplib/siplib.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>a8aef53ca0663ed2c489773096fd92c51747b815</id>
    </parent>
  </parents>
  <author>
    <name>Kevin Watters</name>
    <email>kevinwatters@gmail.com</email>
  </author>
  <url>http://github.com/kevinw/sip/commit/6f479b75fa03d2a6ad38dfbc8571673668fdd801</url>
  <id>6f479b75fa03d2a6ad38dfbc8571673668fdd801</id>
  <committed-date>2008-10-06T10:23:10-07:00</committed-date>
  <authored-date>2008-10-06T10:23:10-07:00</authored-date>
  <message>Always insert variables into the sipSpec's variable list sorted.

Upon lazy variable lookup, use binary search on the sorted PyMethodDef* list.

This speeds up variable lookups on classes with lots of properties (like ours in wx) quite a bit.</message>
  <tree>54bbee57b038cc6edf790e9e0a93703a04e66c25</tree>
  <committer>
    <name>Kevin Watters</name>
    <email>kevinwatters@gmail.com</email>
  </committer>
</commit>
