[Python-checkins] r46194 - in python/branches/blais-bytebuf: Doc/api/exceptions.tex Doc/whatsnew/whatsnew25.tex Include/code.h Include/frameobject.h Include/unicodeobject.h Lib/distutils/command/build_ext.py Lib/distutils/sysconfig.py Lib/distutils/unixccompiler.py Lib/distutils/util.py Lib/struct.py Lib/test/regrtest.py Lib/test/test_builtin.py Lib/test/test_struct.py Mac/OSX/BuildScript Mac/OSX/Makefile.in Misc/ACKS Misc/NEWS Modules/Setup.dist Modules/_struct.c Modules/structmodule.c Objects/codeobject.c Objects/frameobject.c Objects/unicodeobject.c PC/config.c PCbuild/pythoncore.vcproj Python/ceval.c Python/errors.c Python/mystrtoul.c setup.py

martin.blais python-checkins at python.org
Wed May 24 20:30:47 CEST 2006


Author: martin.blais
Date: Wed May 24 20:30:42 2006
New Revision: 46194

Added:
   python/branches/blais-bytebuf/Lib/struct.py
      - copied unchanged from r46193, python/trunk/Lib/struct.py
   python/branches/blais-bytebuf/Mac/OSX/BuildScript/
      - copied from r46193, python/trunk/Mac/OSX/BuildScript/
   python/branches/blais-bytebuf/Modules/_struct.c
      - copied unchanged from r46193, python/trunk/Modules/_struct.c
Removed:
   python/branches/blais-bytebuf/Modules/structmodule.c
Modified:
   python/branches/blais-bytebuf/Doc/api/exceptions.tex
   python/branches/blais-bytebuf/Doc/whatsnew/whatsnew25.tex
   python/branches/blais-bytebuf/Include/code.h
   python/branches/blais-bytebuf/Include/frameobject.h
   python/branches/blais-bytebuf/Include/unicodeobject.h
   python/branches/blais-bytebuf/Lib/distutils/command/build_ext.py
   python/branches/blais-bytebuf/Lib/distutils/sysconfig.py
   python/branches/blais-bytebuf/Lib/distutils/unixccompiler.py
   python/branches/blais-bytebuf/Lib/distutils/util.py
   python/branches/blais-bytebuf/Lib/test/regrtest.py
   python/branches/blais-bytebuf/Lib/test/test_builtin.py
   python/branches/blais-bytebuf/Lib/test/test_struct.py
   python/branches/blais-bytebuf/Mac/OSX/Makefile.in
   python/branches/blais-bytebuf/Misc/ACKS
   python/branches/blais-bytebuf/Misc/NEWS
   python/branches/blais-bytebuf/Modules/Setup.dist
   python/branches/blais-bytebuf/Objects/codeobject.c
   python/branches/blais-bytebuf/Objects/frameobject.c
   python/branches/blais-bytebuf/Objects/unicodeobject.c
   python/branches/blais-bytebuf/PC/config.c
   python/branches/blais-bytebuf/PCbuild/pythoncore.vcproj
   python/branches/blais-bytebuf/Python/ceval.c
   python/branches/blais-bytebuf/Python/errors.c
   python/branches/blais-bytebuf/Python/mystrtoul.c
   python/branches/blais-bytebuf/setup.py
Log:
(Updated to trunk)

Modified: python/branches/blais-bytebuf/Doc/api/exceptions.tex
==============================================================================
--- python/branches/blais-bytebuf/Doc/api/exceptions.tex	(original)
+++ python/branches/blais-bytebuf/Doc/api/exceptions.tex	Wed May 24 20:30:42 2006
@@ -341,7 +341,8 @@
   The \member{__module__} attribute of the new class is set to the
   first part (up to the last dot) of the \var{name} argument, and the
   class name is set to the last part (after the last dot).  The
-  \var{base} argument can be used to specify an alternate base class.
+  \var{base} argument can be used to specify alternate base classes;
+  it can either be only one class or a tuple of classes.
   The \var{dict} argument can be used to specify a dictionary of class
   variables and methods.
 \end{cfuncdesc}

Modified: python/branches/blais-bytebuf/Doc/whatsnew/whatsnew25.tex
==============================================================================
--- python/branches/blais-bytebuf/Doc/whatsnew/whatsnew25.tex	(original)
+++ python/branches/blais-bytebuf/Doc/whatsnew/whatsnew25.tex	Wed May 24 20:30:42 2006
@@ -1120,6 +1120,13 @@
 %======================================================================
 \subsection{Optimizations\label{opts}}
 
+Several of the optimizations were developed at the NeedForSpeed
+sprint, an event held in Reykjavik, Iceland, from May 21--28 2006.
+The sprint focused on speed enhancements to the CPython implementation
+and was funded by EWT LLC with local support from CCP Games.  Those
+optimizations added at this sprint are specially marked in the
+following list.
+
 \begin{itemize}
 
 \item When they were introduced 
@@ -1129,15 +1136,34 @@
 and as a result sets will use a third less memory and are somewhat faster.
 (Implemented by Raymond Hettinger.)
 
-\item The performance of some Unicode operations, such as 
-character map decoding, has been improved.
+\item The speed of some Unicode operations, such as 
+finding substrings, string splitting, and character map decoding, has
+been improved.  (Substring search and splitting improvements were
+added by Fredrik Lundh and Andrew Dalke at the NeedForSpeed
+sprint. Character map decoding was improved by Walter D\"orwald.)
 % Patch 1313939
 
+\item The \module{struct} module now compiles structure format 
+strings into an internal representation and caches this
+representation, yielding a 20\% speedup.  (Contributed by Bob Ippolito
+at the NeedForSpeed sprint.)
+
 \item The code generator's peephole optimizer now performs
 simple constant folding in expressions.  If you write something like
 \code{a = 2+3}, the code generator will do the arithmetic and produce
 code corresponding to \code{a = 5}.
 
+\item Function calls are now faster because code objects now keep 
+the most recently finished frame (a ``zombie frame'') in an internal
+field of the code object, reusing it the next time the code object is
+invoked.  (Original patch by Michael Hudson, modified by Armin Rigo
+and Richard Jones; committed at the NeedForSpeed sprint.)
+% Patch 876206
+
+Frame objects are also slightly smaller, which may improve cache locality
+and reduce memory usage a bit.  (Contributed by Neal Norwitz.)
+% Patch 1337051
+
 \end{itemize}
 
 The net result of the 2.5 optimizations is that Python 2.5 runs the
@@ -1411,7 +1437,7 @@
 included in the \file{Tools/pybench} directory.  The pybench suite is
 an improvement on the commonly used \file{pystone.py} program because
 pybench provides a more detailed measurement of the interpreter's
-performance.  It times particular operations such as function calls,
+speed.  It times particular operations such as function calls,
 tuple slicing, method lookups, and numeric operations, instead of
 performing many different operations and reducing the result to a
 single number as \file{pystone.py} does.
@@ -1935,6 +1961,10 @@
 \code{"trunk:45355:45356M, Apr 13 2006, 07:42:19"}.  
 (Contributed by Barry Warsaw.)
 
+\item \cfunction{PyErr_NewException(\var{name}, \var{base},
+\var{dict})} can now accept a tuple of base classes as its \var{base}
+argument.  (Contributed by Georg Brandl.)
+
 \item The CPython interpreter is still written in C, but 
 the code can now be compiled with a {\Cpp} compiler without errors.  
 (Implemented by Anthony Baxter, Martin von~L\"owis, Skip Montanaro.)

Modified: python/branches/blais-bytebuf/Include/code.h
==============================================================================
--- python/branches/blais-bytebuf/Include/code.h	(original)
+++ python/branches/blais-bytebuf/Include/code.h	Wed May 24 20:30:42 2006
@@ -24,6 +24,7 @@
     PyObject *co_name;		/* string (name, for reference) */
     int co_firstlineno;		/* first source line number */
     PyObject *co_lnotab;	/* string (encoding addr<->lineno mapping) */
+    void *co_zombieframe;     /* for optimization only (see frameobject.c) */
 } PyCodeObject;
 
 /* Masks for co_flags above */

Modified: python/branches/blais-bytebuf/Include/frameobject.h
==============================================================================
--- python/branches/blais-bytebuf/Include/frameobject.h	(original)
+++ python/branches/blais-bytebuf/Include/frameobject.h	Wed May 24 20:30:42 2006
@@ -36,10 +36,6 @@
 				   in this scope */
     int f_iblock;		/* index in f_blockstack */
     PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
-    int f_nlocals;		/* number of locals */
-    int f_ncells;
-    int f_nfreevars;
-    int f_stacksize;		/* size of value stack */
     PyObject *f_localsplus[1];	/* locals+stack, dynamically sized */
 } PyFrameObject;
 

Modified: python/branches/blais-bytebuf/Include/unicodeobject.h
==============================================================================
--- python/branches/blais-bytebuf/Include/unicodeobject.h	(original)
+++ python/branches/blais-bytebuf/Include/unicodeobject.h	Wed May 24 20:30:42 2006
@@ -367,10 +367,12 @@
         for (i_ = 0; i_ < (length); i_++) t_[i_] = v_;\
     } while (0)
 
-#define Py_UNICODE_MATCH(string, offset, substring)\
-    ((*((string)->str + (offset)) == *((substring)->str)) &&\
-     !memcmp((string)->str + (offset), (substring)->str,\
-             (substring)->length*sizeof(Py_UNICODE)))
+/* check if substring matches at given offset.  the offset must be
+   valid, and the substring must not be empty */
+#define Py_UNICODE_MATCH(string, offset, substring) \
+    ((*((string)->str + (offset)) == *((substring)->str)) && \
+    ((*((string)->str + (offset) + (substring)->length-1) == *((substring)->str + (substring)->length-1))) && \
+     !memcmp((string)->str + (offset), (substring)->str, (substring)->length*sizeof(Py_UNICODE)))
 
 #ifdef __cplusplus
 extern "C" {

Modified: python/branches/blais-bytebuf/Lib/distutils/command/build_ext.py
==============================================================================
--- python/branches/blais-bytebuf/Lib/distutils/command/build_ext.py	(original)
+++ python/branches/blais-bytebuf/Lib/distutils/command/build_ext.py	Wed May 24 20:30:42 2006
@@ -689,6 +689,11 @@
             # don't extend ext.libraries, it may be shared with other
             # extensions, it is a reference to the original list
             return ext.libraries + [pythonlib, "m"] + extra
+
+        elif sys.platform == 'darwin':
+            # Don't use the default code below
+            return ext.libraries
+
         else:
             from distutils import sysconfig
             if sysconfig.get_config_var('Py_ENABLE_SHARED'):

Modified: python/branches/blais-bytebuf/Lib/distutils/sysconfig.py
==============================================================================
--- python/branches/blais-bytebuf/Lib/distutils/sysconfig.py	(original)
+++ python/branches/blais-bytebuf/Lib/distutils/sysconfig.py	Wed May 24 20:30:42 2006
@@ -500,6 +500,21 @@
         _config_vars['prefix'] = PREFIX
         _config_vars['exec_prefix'] = EXEC_PREFIX
 
+        if sys.platform == 'darwin':
+            kernel_version = os.uname()[2] # Kernel version (8.4.3)
+            major_version = int(kernel_version.split('.')[0])
+
+            if major_version < 8:
+                # On Mac OS X before 10.4, check if -arch and -isysroot
+                # are in CFLAGS or LDFLAGS and remove them if they are.
+                # This is needed when building extensions on a 10.3 system
+                # using a universal build of python.
+                for key in ('LDFLAGS', 'BASECFLAGS'):
+                    flags = _config_vars[key]
+                    flags = re.sub('-arch\s+\w+\s', ' ', flags)
+                    flags = re.sub('-isysroot [^ \t]* ', ' ', flags)
+                    _config_vars[key] = flags
+
     if args:
         vals = []
         for name in args:

Modified: python/branches/blais-bytebuf/Lib/distutils/unixccompiler.py
==============================================================================
--- python/branches/blais-bytebuf/Lib/distutils/unixccompiler.py	(original)
+++ python/branches/blais-bytebuf/Lib/distutils/unixccompiler.py	Wed May 24 20:30:42 2006
@@ -42,6 +42,48 @@
 #     should just happily stuff them into the preprocessor/compiler/linker
 #     options and carry on.
 
+def _darwin_compiler_fixup(compiler_so, cc_args):
+    """
+    This function will strip '-isysroot PATH' and '-arch ARCH' from the
+    compile flags if the user has specified one them in extra_compile_flags.
+
+    This is needed because '-arch ARCH' adds another architecture to the
+    build, without a way to remove an architecture. Furthermore GCC will
+    barf if multiple '-isysroot' arguments are present.
+    """
+    stripArch = stripSysroot = 0
+
+    compiler_so = list(compiler_so)
+    kernel_version = os.uname()[2] # 8.4.3
+    major_version = int(kernel_version.split('.')[0])
+
+    if major_version < 8:
+        # OSX before 10.4.0, these don't support -arch and -isysroot at
+        # all.
+        stripArch = stripSysroot = True
+    else:
+        stripArch = '-arch' in cc_args
+        stripSysroot = '-isysroot' in cc_args
+
+    if stripArch:
+        while 1:
+            try:
+                index = compiler_so.index('-arch')
+                # Strip this argument and the next one:
+                del compiler_so[index:index+2]
+            except ValueError:
+                break
+
+    if stripSysroot:
+        try:
+            index = compiler_so.index('-isysroot')
+            # Strip this argument and the next one:
+            del compiler_so[index:index+1]
+        except ValueError:
+            pass
+
+    return compiler_so
+
 class UnixCCompiler(CCompiler):
 
     compiler_type = 'unix'
@@ -108,8 +150,11 @@
                 raise CompileError, msg
 
     def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
+        compiler_so = self.compiler_so
+        if sys.platform == 'darwin':
+            compiler_so = _darwin_compiler_fixup(compiler_so, cc_args + extra_postargs)
         try:
-            self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
+            self.spawn(compiler_so + cc_args + [src, '-o', obj] +
                        extra_postargs)
         except DistutilsExecError, msg:
             raise CompileError, msg
@@ -172,7 +217,22 @@
                 else:
                     linker = self.linker_so[:]
                 if target_lang == "c++" and self.compiler_cxx:
-                    linker[0] = self.compiler_cxx[0]
+                    # skip over environment variable settings if /usr/bin/env
+                    # is used to set up the linker's environment.
+                    # This is needed on OSX. Note: this assumes that the
+                    # normal and C++ compiler have the same environment
+                    # settings.
+                    i = 0
+                    if os.path.basename(linker[0]) == "env":
+                        i = 1
+                        while '=' in linker[i]:
+                            i = i + 1
+
+                    linker[i] = self.compiler_cxx[i]
+
+                if sys.platform == 'darwin':
+                    linker = _darwin_compiler_fixup(linker, ld_args)
+
                 self.spawn(linker + ld_args)
             except DistutilsExecError, msg:
                 raise LinkError, msg

Modified: python/branches/blais-bytebuf/Lib/distutils/util.py
==============================================================================
--- python/branches/blais-bytebuf/Lib/distutils/util.py	(original)
+++ python/branches/blais-bytebuf/Lib/distutils/util.py	Wed May 24 20:30:42 2006
@@ -67,6 +67,54 @@
         m = rel_re.match(release)
         if m:
             release = m.group()
+    elif osname[:6] == "darwin":
+        #
+        # For our purposes, we'll assume that the system version from
+        # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
+        # to. This makes the compatibility story a bit more sane because the
+        # machine is going to compile and link as if it were
+        # MACOSX_DEPLOYMENT_TARGET.
+        from distutils.sysconfig import get_config_vars
+        cfgvars = get_config_vars()
+
+        macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET')
+        if not macver:
+            macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
+
+        if not macver:
+            # Get the system version. Reading this plist is a documented
+            # way to get the system version (see the documentation for
+            # the Gestalt Manager)
+            try:
+                f = open('/System/Library/CoreServices/SystemVersion.plist')
+            except IOError:
+                # We're on a plain darwin box, fall back to the default
+                # behaviour.
+                pass
+            else:
+                m = re.search(
+                        r'<key>ProductUserVisibleVersion</key>\s*' +
+                        r'<string>(.*?)</string>', f.read())
+                f.close()
+                if m is not None:
+                    macver = '.'.join(m.group(1).split('.')[:2])
+                # else: fall back to the default behaviour
+
+        if macver:
+            from distutils.sysconfig import get_config_vars
+            release = macver
+            osname = "macosx"
+
+
+            if (release + '.') < '10.4.' and \
+                    get_config_vars().get('UNIVERSALSDK', '').strip():
+                # The universal build will build fat binaries, but not on
+                # systems before 10.4
+                machine = 'fat'
+
+            elif machine in ('PowerPC', 'Power_Macintosh'):
+                # Pick a sane name for the PPC architecture.
+                machine = 'ppc'
 
     return "%s-%s-%s" % (osname, release, machine)
 

Modified: python/branches/blais-bytebuf/Lib/test/regrtest.py
==============================================================================
--- python/branches/blais-bytebuf/Lib/test/regrtest.py	(original)
+++ python/branches/blais-bytebuf/Lib/test/regrtest.py	Wed May 24 20:30:42 2006
@@ -545,6 +545,7 @@
                 def cleanup():
                     import _strptime, linecache, warnings, dircache
                     import urlparse, urllib, urllib2, mimetypes, doctest
+                    import struct
                     from distutils.dir_util import _path_created
                     _path_created.clear()
                     warnings.filters[:] = fs
@@ -561,6 +562,7 @@
                     dircache.reset()
                     linecache.clearcache()
                     mimetypes._default_mime_types()
+                    struct._cache.clear()
                     doctest.master = None
                 if indirect_test:
                     def run_the_test():

Modified: python/branches/blais-bytebuf/Lib/test/test_builtin.py
==============================================================================
--- python/branches/blais-bytebuf/Lib/test/test_builtin.py	(original)
+++ python/branches/blais-bytebuf/Lib/test/test_builtin.py	Wed May 24 20:30:42 2006
@@ -709,6 +709,84 @@
         self.assertEqual(int('0123', 0), 83)
         self.assertEqual(int('0x123', 16), 291)
 
+        # SF bug 1334662: int(string, base) wrong answers
+        # Various representations of 2**32 evaluated to 0
+        # rather than 2**32 in previous versions
+
+        self.assertEqual(int('100000000000000000000000000000000', 2), 4294967296L)
+        self.assertEqual(int('102002022201221111211', 3), 4294967296L)
+        self.assertEqual(int('10000000000000000', 4), 4294967296L)
+        self.assertEqual(int('32244002423141', 5), 4294967296L)
+        self.assertEqual(int('1550104015504', 6), 4294967296L)
+        self.assertEqual(int('211301422354', 7), 4294967296L)
+        self.assertEqual(int('40000000000', 8), 4294967296L)
+        self.assertEqual(int('12068657454', 9), 4294967296L)
+        self.assertEqual(int('4294967296', 10), 4294967296L)
+        self.assertEqual(int('1904440554', 11), 4294967296L)
+        self.assertEqual(int('9ba461594', 12), 4294967296L)
+        self.assertEqual(int('535a79889', 13), 4294967296L)
+        self.assertEqual(int('2ca5b7464', 14), 4294967296L)
+        self.assertEqual(int('1a20dcd81', 15), 4294967296L)
+        self.assertEqual(int('100000000', 16), 4294967296L)
+        self.assertEqual(int('a7ffda91', 17), 4294967296L)
+        self.assertEqual(int('704he7g4', 18), 4294967296L)
+        self.assertEqual(int('4f5aff66', 19), 4294967296L)
+        self.assertEqual(int('3723ai4g', 20), 4294967296L)
+        self.assertEqual(int('281d55i4', 21), 4294967296L)
+        self.assertEqual(int('1fj8b184', 22), 4294967296L)
+        self.assertEqual(int('1606k7ic', 23), 4294967296L)
+        self.assertEqual(int('mb994ag', 24), 4294967296L)
+        self.assertEqual(int('hek2mgl', 25), 4294967296L)
+        self.assertEqual(int('dnchbnm', 26), 4294967296L)
+        self.assertEqual(int('b28jpdm', 27), 4294967296L)
+        self.assertEqual(int('8pfgih4', 28), 4294967296L)
+        self.assertEqual(int('76beigg', 29), 4294967296L)
+        self.assertEqual(int('5qmcpqg', 30), 4294967296L)
+        self.assertEqual(int('4q0jto4', 31), 4294967296L)
+        self.assertEqual(int('4000000', 32), 4294967296L)
+        self.assertEqual(int('3aokq94', 33), 4294967296L)
+        self.assertEqual(int('2qhxjli', 34), 4294967296L)
+        self.assertEqual(int('2br45qb', 35), 4294967296L)
+        self.assertEqual(int('1z141z4', 36), 4294967296L)
+
+        # SF bug 1334662: int(string, base) wrong answers
+        # Checks for proper evaluation of 2**32 + 1
+        self.assertEqual(int('100000000000000000000000000000001', 2), 4294967297L)
+        self.assertEqual(int('102002022201221111212', 3), 4294967297L)
+        self.assertEqual(int('10000000000000001', 4), 4294967297L)
+        self.assertEqual(int('32244002423142', 5), 4294967297L)
+        self.assertEqual(int('1550104015505', 6), 4294967297L)
+        self.assertEqual(int('211301422355', 7), 4294967297L)
+        self.assertEqual(int('40000000001', 8), 4294967297L)
+        self.assertEqual(int('12068657455', 9), 4294967297L)
+        self.assertEqual(int('4294967297', 10), 4294967297L)
+        self.assertEqual(int('1904440555', 11), 4294967297L)
+        self.assertEqual(int('9ba461595', 12), 4294967297L)
+        self.assertEqual(int('535a7988a', 13), 4294967297L)
+        self.assertEqual(int('2ca5b7465', 14), 4294967297L)
+        self.assertEqual(int('1a20dcd82', 15), 4294967297L)
+        self.assertEqual(int('100000001', 16), 4294967297L)
+        self.assertEqual(int('a7ffda92', 17), 4294967297L)
+        self.assertEqual(int('704he7g5', 18), 4294967297L)
+        self.assertEqual(int('4f5aff67', 19), 4294967297L)
+        self.assertEqual(int('3723ai4h', 20), 4294967297L)
+        self.assertEqual(int('281d55i5', 21), 4294967297L)
+        self.assertEqual(int('1fj8b185', 22), 4294967297L)
+        self.assertEqual(int('1606k7id', 23), 4294967297L)
+        self.assertEqual(int('mb994ah', 24), 4294967297L)
+        self.assertEqual(int('hek2mgm', 25), 4294967297L)
+        self.assertEqual(int('dnchbnn', 26), 4294967297L)
+        self.assertEqual(int('b28jpdn', 27), 4294967297L)
+        self.assertEqual(int('8pfgih5', 28), 4294967297L)
+        self.assertEqual(int('76beigh', 29), 4294967297L)
+        self.assertEqual(int('5qmcpqh', 30), 4294967297L)
+        self.assertEqual(int('4q0jto5', 31), 4294967297L)
+        self.assertEqual(int('4000001', 32), 4294967297L)
+        self.assertEqual(int('3aokq95', 33), 4294967297L)
+        self.assertEqual(int('2qhxjlj', 34), 4294967297L)
+        self.assertEqual(int('2br45qc', 35), 4294967297L)
+        self.assertEqual(int('1z141z5', 36), 4294967297L)
+
     def test_intconversion(self):
         # Test __int__()
         class Foo0:

Modified: python/branches/blais-bytebuf/Lib/test/test_struct.py
==============================================================================
--- python/branches/blais-bytebuf/Lib/test/test_struct.py	(original)
+++ python/branches/blais-bytebuf/Lib/test/test_struct.py	Wed May 24 20:30:42 2006
@@ -437,3 +437,44 @@
         TestFailed("expected OverflowError")
 
 test_705836()
+
+def test_unpack_from():
+    test_string = 'abcd01234'
+    fmt = '4s'
+    s = struct.Struct(fmt)
+    for cls in (str, buffer):
+        data = cls(test_string)
+        assert s.unpack_from(data) == ('abcd',)
+        assert s.unpack_from(data, 2) == ('cd01',)
+        assert s.unpack_from(data, 4) == ('0123',)
+        for i in xrange(6):
+            assert s.unpack_from(data, i) == (data[i:i+4],)
+        for i in xrange(6, len(test_string) + 1):
+            simple_err(s.unpack_from, data, i)
+    for cls in (str, buffer):
+        data = cls(test_string)
+        assert struct.unpack_from(fmt, data) == ('abcd',)
+        assert struct.unpack_from(fmt, data, 2) == ('cd01',)
+        assert struct.unpack_from(fmt, data, 4) == ('0123',)
+        for i in xrange(6):
+            assert struct.unpack_from(fmt, data, i) == (data[i:i+4],)
+        for i in xrange(6, len(test_string) + 1):
+            simple_err(struct.unpack_from, fmt, data, i)
+
+test_unpack_from()
+
+def test_1229380():
+    for endian in ('', '>', '<'):
+        for cls in (int, long):
+            for fmt in ('B', 'H', 'I', 'L'):
+                any_err(struct.pack, endian + fmt, cls(-1))
+
+            any_err(struct.pack, endian + 'B', cls(300))
+            any_err(struct.pack, endian + 'H', cls(70000))
+
+        any_err(struct.pack, endian + 'I', sys.maxint * 4L)
+        any_err(struct.pack, endian + 'L', sys.maxint * 4L)
+
+if 0:
+    # TODO: bug #1229380
+    test_1229380()

Modified: python/branches/blais-bytebuf/Mac/OSX/Makefile.in
==============================================================================
--- python/branches/blais-bytebuf/Mac/OSX/Makefile.in	(original)
+++ python/branches/blais-bytebuf/Mac/OSX/Makefile.in	Wed May 24 20:30:42 2006
@@ -73,11 +73,16 @@
 install_versionedtools:
 	for fn in idle pydoc python-config ;\
 	do \
+		if [ -h "$(DESTDIR)$(prefix)/bin/$${fn}" ]; then \
+			continue ;\
+		fi ;\
 		mv "$(DESTDIR)$(prefix)/bin/$${fn}" "$(DESTDIR)$(prefix)/bin/$${fn}$(VERSION)"  ;\
 		ln -sf "$${fn}$(VERSION)" "$(DESTDIR)$(prefix)/bin/$${fn}" ;\
 	done
-	mv "$(DESTDIR)$(prefix)/bin/smtpd.py" "$(DESTDIR)$(prefix)/bin/smtpd$(VERSION).py" 
-	ln -sf "smtpd$(VERSION).py" "$(DESTDIR)$(prefix)/bin/smtpd.py"
+	if [ ! -h "$(DESTDIR)$(prefix)/bin/smtpd.py" ]; then \
+		mv "$(DESTDIR)$(prefix)/bin/smtpd.py" "$(DESTDIR)$(prefix)/bin/smtpd$(VERSION).py"  ;\
+		ln -sf "smtpd$(VERSION).py" "$(DESTDIR)$(prefix)/bin/smtpd.py" ;\
+	fi
 
 
 pythonw: $(srcdir)/Tools/pythonw.c

Modified: python/branches/blais-bytebuf/Misc/ACKS
==============================================================================
--- python/branches/blais-bytebuf/Misc/ACKS	(original)
+++ python/branches/blais-bytebuf/Misc/ACKS	Wed May 24 20:30:42 2006
@@ -390,6 +390,7 @@
 Mark Lutz
 Jim Lynch
 Mikael Lyngvig
+Alan McIntyre
 Andrew I MacIntyre
 Tim MacKenzie
 Nick Maclaren

Modified: python/branches/blais-bytebuf/Misc/NEWS
==============================================================================
--- python/branches/blais-bytebuf/Misc/NEWS	(original)
+++ python/branches/blais-bytebuf/Misc/NEWS	Wed May 24 20:30:42 2006
@@ -12,6 +12,19 @@
 Core and builtins
 -----------------
 
+- Bug #1334662: ``int(string, base)`` could deliver a wrong answer
+  when ``base`` was not 2, 4, 8, 10, 16 or 32, and ``string`` represented
+  an integer close to ``sys.maxint``.  This was repaired by patch
+  #1335972, which also gives a nice speedup.
+
+- Patch #1337051: reduced size of frame objects.
+
+- PyErr_NewException now accepts a tuple of base classes as its
+  "base" parameter.
+
+- Patch #876206: function call speedup by retaining allocated frame
+  objects.
+
 - Bug #1462152: file() now checks more thoroughly for invalid mode
   strings and removes a possible "U" before passing the mode to the
   C library function.
@@ -32,6 +45,8 @@
 Extension Modules
 -----------------
 
+- Patch #1493701: performance enhancements for struct module.
+
 - Patch #1490224: time.altzone is now set correctly on Cygwin.
 
 - Patch #1435422: zlib's compress and decompress objects now have a
@@ -49,6 +64,8 @@
 Library
 -------
 
+- Patch #1281707: speed up gzip.readline.
+
 - Patch #1180296: Two new functions were added to the locale module:
   format_string() to get the effect of  "format % items" but locale-aware,
   and currency() to format a monetary number with currency sign.

Modified: python/branches/blais-bytebuf/Modules/Setup.dist
==============================================================================
--- python/branches/blais-bytebuf/Modules/Setup.dist	(original)
+++ python/branches/blais-bytebuf/Modules/Setup.dist	Wed May 24 20:30:42 2006
@@ -167,7 +167,7 @@
 #array arraymodule.c	# array objects
 #cmath cmathmodule.c # -lm # complex math library functions
 #math mathmodule.c # -lm # math library functions, e.g. sin()
-#struct structmodule.c	# binary structure packing/unpacking
+#_struct _struct.c	# binary structure packing/unpacking
 #time timemodule.c # -lm # time operations and variables
 #operator operator.c	# operator.add() and similar goodies
 #_weakref _weakref.c	# basic weak reference support

Deleted: /python/branches/blais-bytebuf/Modules/structmodule.c
==============================================================================
--- /python/branches/blais-bytebuf/Modules/structmodule.c	Wed May 24 20:30:42 2006
+++ (empty file)
@@ -1,1293 +0,0 @@
-/* struct module -- pack values into and (out of) strings */
-
-/* New version supporting byte order, alignment and size options,
-   character strings, and unsigned numbers */
-
-#include "Python.h"
-#include <ctype.h>
-
-PyDoc_STRVAR(struct__doc__,
-"Functions to convert between Python values and C structs.\n\
-Python strings are used to hold the data representing the C struct\n\
-and also as format strings to describe the layout of data in the C struct.\n\
-\n\
-The optional first format char indicates byte order, size and alignment:\n\
- @: native order, size & alignment (default)\n\
- =: native order, std. size & alignment\n\
- <: little-endian, std. size & alignment\n\
- >: big-endian, std. size & alignment\n\
- !: same as >\n\
-\n\
-The remaining chars indicate types of args and must match exactly;\n\
-these can be preceded by a decimal repeat count:\n\
- x: pad byte (no data); c:char; b:signed byte; B:unsigned byte;\n\
- h:short; H:unsigned short; i:int; I:unsigned int;\n\
- l:long; L:unsigned long; f:float; d:double.\n\
-Special cases (preceding decimal count indicates length):\n\
- s:string (array of char); p: pascal string (with count byte).\n\
-Special case (only available in native format):\n\
- P:an integer type that is wide enough to hold a pointer.\n\
-Special case (not in native mode unless 'long long' in platform C):\n\
- q:long long; Q:unsigned long long\n\
-Whitespace between formats is ignored.\n\
-\n\
-The variable struct.error is an exception raised on errors.");
-
-
-/* Exception */
-
-static PyObject *StructError;
-
-
-/* Define various structs to figure out the alignments of types */
-
-
-typedef struct { char c; short x; } st_short;
-typedef struct { char c; int x; } st_int;
-typedef struct { char c; long x; } st_long;
-typedef struct { char c; float x; } st_float;
-typedef struct { char c; double x; } st_double;
-typedef struct { char c; void *x; } st_void_p;
-
-#define SHORT_ALIGN (sizeof(st_short) - sizeof(short))
-#define INT_ALIGN (sizeof(st_int) - sizeof(int))
-#define LONG_ALIGN (sizeof(st_long) - sizeof(long))
-#define FLOAT_ALIGN (sizeof(st_float) - sizeof(float))
-#define DOUBLE_ALIGN (sizeof(st_double) - sizeof(double))
-#define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *))
-
-/* We can't support q and Q in native mode unless the compiler does;
-   in std mode, they're 8 bytes on all platforms. */
-#ifdef HAVE_LONG_LONG
-typedef struct { char c; PY_LONG_LONG x; } s_long_long;
-#define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(PY_LONG_LONG))
-#endif
-
-#define STRINGIFY(x)    #x
-
-#ifdef __powerc
-#pragma options align=reset
-#endif
-
-/* Helper to get a PyLongObject by hook or by crook.  Caller should decref. */
-
-static PyObject *
-get_pylong(PyObject *v)
-{
-	PyNumberMethods *m;
-
-	assert(v != NULL);
-	if (PyInt_Check(v))
-		return PyLong_FromLong(PyInt_AS_LONG(v));
-	if (PyLong_Check(v)) {
-		Py_INCREF(v);
-		return v;
-	}
-	m = v->ob_type->tp_as_number;
-	if (m != NULL && m->nb_long != NULL) {
-		v = m->nb_long(v);
-		if (v == NULL)
-			return NULL;
-		if (PyLong_Check(v))
-			return v;
-		Py_DECREF(v);
-	}
-	PyErr_SetString(StructError,
-			"cannot convert argument to long");
-	return NULL;
-}
-
-/* Helper routine to get a Python integer and raise the appropriate error
-   if it isn't one */
-
-static int
-get_long(PyObject *v, long *p)
-{
-	long x = PyInt_AsLong(v);
-	if (x == -1 && PyErr_Occurred()) {
-		if (PyErr_ExceptionMatches(PyExc_TypeError))
-			PyErr_SetString(StructError,
-					"required argument is not an integer");
-		return -1;
-	}
-	*p = x;
-	return 0;
-}
-
-
-/* Same, but handling unsigned long */
-
-static int
-get_ulong(PyObject *v, unsigned long *p)
-{
-	if (PyLong_Check(v)) {
-		unsigned long x = PyLong_AsUnsignedLong(v);
-		if (x == (unsigned long)(-1) && PyErr_Occurred())
-			return -1;
-		*p = x;
-		return 0;
-	}
-	else {
-		return get_long(v, (long *)p);
-	}
-}
-
-#ifdef HAVE_LONG_LONG
-
-/* Same, but handling native long long. */
-
-static int
-get_longlong(PyObject *v, PY_LONG_LONG *p)
-{
-	PY_LONG_LONG x;
-
-	v = get_pylong(v);
-	if (v == NULL)
-		return -1;
-	assert(PyLong_Check(v));
-	x = PyLong_AsLongLong(v);
-	Py_DECREF(v);
-	if (x == (PY_LONG_LONG)-1 && PyErr_Occurred())
-		return -1;
-	*p = x;
-	return 0;
-}
-
-/* Same, but handling native unsigned long long. */
-
-static int
-get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p)
-{
-	unsigned PY_LONG_LONG x;
-
-	v = get_pylong(v);
-	if (v == NULL)
-		return -1;
-	assert(PyLong_Check(v));
-	x = PyLong_AsUnsignedLongLong(v);
-	Py_DECREF(v);
-	if (x == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
-		return -1;
-	*p = x;
-	return 0;
-}
-
-#endif
-
-/* Floating point helpers */
-
-static PyObject *
-unpack_float(const char *p,  /* start of 4-byte string */
-             int le)	     /* true for little-endian, false for big-endian */
-{
-	double x;
-
-	x = _PyFloat_Unpack4((unsigned char *)p, le);
-	if (x == -1.0 && PyErr_Occurred())
-		return NULL;
-	return PyFloat_FromDouble(x);
-}
-
-static PyObject *
-unpack_double(const char *p,  /* start of 8-byte string */
-              int le)         /* true for little-endian, false for big-endian */
-{
-	double x;
-
-	x = _PyFloat_Unpack8((unsigned char *)p, le);
-	if (x == -1.0 && PyErr_Occurred())
-		return NULL;
-	return PyFloat_FromDouble(x);
-}
-
-
-/* The translation function for each format character is table driven */
-
-typedef struct _formatdef {
-	char format;
-	int size;
-	int alignment;
-	PyObject* (*unpack)(const char *,
-			    const struct _formatdef *);
-	int (*pack)(char *, PyObject *,
-		    const struct _formatdef *);
-} formatdef;
-
-/* A large number of small routines follow, with names of the form
-
-	[bln][up]_TYPE
-
-   [bln] distiguishes among big-endian, little-endian and native.
-   [pu] distiguishes between pack (to struct) and unpack (from struct).
-   TYPE is one of char, byte, ubyte, etc.
-*/
-
-/* Native mode routines. ****************************************************/
-/* NOTE:
-   In all n[up]_<type> routines handling types larger than 1 byte, there is
-   *no* guarantee that the p pointer is properly aligned for each type,
-   therefore memcpy is called.  An intermediate variable is used to
-   compensate for big-endian architectures.
-   Normally both the intermediate variable and the memcpy call will be
-   skipped by C optimisation in little-endian architectures (gcc >= 2.91
-   does this). */
-
-static PyObject *
-nu_char(const char *p, const formatdef *f)
-{
-	return PyString_FromStringAndSize(p, 1);
-}
-
-static PyObject *
-nu_byte(const char *p, const formatdef *f)
-{
-	return PyInt_FromLong((long) *(signed char *)p);
-}
-
-static PyObject *
-nu_ubyte(const char *p, const formatdef *f)
-{
-	return PyInt_FromLong((long) *(unsigned char *)p);
-}
-
-static PyObject *
-nu_short(const char *p, const formatdef *f)
-{
-	short x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyInt_FromLong((long)x);
-}
-
-static PyObject *
-nu_ushort(const char *p, const formatdef *f)
-{
-	unsigned short x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyInt_FromLong((long)x);
-}
-
-static PyObject *
-nu_int(const char *p, const formatdef *f)
-{
-	int x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyInt_FromLong((long)x);
-}
-
-static PyObject *
-nu_uint(const char *p, const formatdef *f)
-{
-	unsigned int x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyLong_FromUnsignedLong((unsigned long)x);
-}
-
-static PyObject *
-nu_long(const char *p, const formatdef *f)
-{
-	long x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyInt_FromLong(x);
-}
-
-static PyObject *
-nu_ulong(const char *p, const formatdef *f)
-{
-	unsigned long x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyLong_FromUnsignedLong(x);
-}
-
-/* Native mode doesn't support q or Q unless the platform C supports
-   long long (or, on Windows, __int64). */
-
-#ifdef HAVE_LONG_LONG
-
-static PyObject *
-nu_longlong(const char *p, const formatdef *f)
-{
-	PY_LONG_LONG x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyLong_FromLongLong(x);
-}
-
-static PyObject *
-nu_ulonglong(const char *p, const formatdef *f)
-{
-	unsigned PY_LONG_LONG x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyLong_FromUnsignedLongLong(x);
-}
-
-#endif
-
-static PyObject *
-nu_float(const char *p, const formatdef *f)
-{
-	float x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyFloat_FromDouble((double)x);
-}
-
-static PyObject *
-nu_double(const char *p, const formatdef *f)
-{
-	double x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyFloat_FromDouble(x);
-}
-
-static PyObject *
-nu_void_p(const char *p, const formatdef *f)
-{
-	void *x;
-	memcpy((char *)&x, p, sizeof x);
-	return PyLong_FromVoidPtr(x);
-}
-
-static int
-np_byte(char *p, PyObject *v, const formatdef *f)
-{
-	long x;
-	if (get_long(v, &x) < 0)
-		return -1;
-	if (x < -128 || x > 127){
-		PyErr_SetString(StructError,
-				"byte format requires -128<=number<=127");
-		return -1;
-	}
-	*p = (char)x;
-	return 0;
-}
-
-static int
-np_ubyte(char *p, PyObject *v, const formatdef *f)
-{
-	long x;
-	if (get_long(v, &x) < 0)
-		return -1;
-	if (x < 0 || x > 255){
-		PyErr_SetString(StructError,
-				"ubyte format requires 0<=number<=255");
-		return -1;
-	}
-	*p = (char)x;
-	return 0;
-}
-
-static int
-np_char(char *p, PyObject *v, const formatdef *f)
-{
-	if (!PyString_Check(v) || PyString_Size(v) != 1) {
-		PyErr_SetString(StructError,
-				"char format require string of length 1");
-		return -1;
-	}
-	*p = *PyString_AsString(v);
-	return 0;
-}
-
-static int
-np_short(char *p, PyObject *v, const formatdef *f)
-{
-	long x;
-	short y;
-	if (get_long(v, &x) < 0)
-		return -1;
-	if (x < SHRT_MIN || x > SHRT_MAX){
-		PyErr_SetString(StructError,
-				"short format requires " STRINGIFY(SHRT_MIN)
-				"<=number<=" STRINGIFY(SHRT_MAX));
-		return -1;
-	}
-	y = (short)x;
-	memcpy(p, (char *)&y, sizeof y);
-	return 0;
-}
-
-static int
-np_ushort(char *p, PyObject *v, const formatdef *f)
-{
-	long x;
-	unsigned short y;
-	if (get_long(v, &x) < 0)
-		return -1;
-	if (x < 0 || x > USHRT_MAX){
-		PyErr_SetString(StructError,
-				"short format requires 0<=number<=" STRINGIFY(USHRT_MAX));
-		return -1;
-	}
-	y = (unsigned short)x;
-	memcpy(p, (char *)&y, sizeof y);
-	return 0;
-}
-
-static int
-np_int(char *p, PyObject *v, const formatdef *f)
-{
-	long x;
-	int y;
-	if (get_long(v, &x) < 0)
-		return -1;
-	y = (int)x;
-	memcpy(p, (char *)&y, sizeof y);
-	return 0;
-}
-
-static int
-np_uint(char *p, PyObject *v, const formatdef *f)
-{
-	unsigned long x;
-	unsigned int y;
-	if (get_ulong(v, &x) < 0)
-		return -1;
-	y = (unsigned int)x;
-	memcpy(p, (char *)&y, sizeof y);
-	return 0;
-}
-
-static int
-np_long(char *p, PyObject *v, const formatdef *f)
-{
-	long x;
-	if (get_long(v, &x) < 0)
-		return -1;
-	memcpy(p, (char *)&x, sizeof x);
-	return 0;
-}
-
-static int
-np_ulong(char *p, PyObject *v, const formatdef *f)
-{
-	unsigned long x;
-	if (get_ulong(v, &x) < 0)
-		return -1;
-	memcpy(p, (char *)&x, sizeof x);
-	return 0;
-}
-
-#ifdef HAVE_LONG_LONG
-
-static int
-np_longlong(char *p, PyObject *v, const formatdef *f)
-{
-	PY_LONG_LONG x;
-	if (get_longlong(v, &x) < 0)
-		return -1;
-	memcpy(p, (char *)&x, sizeof x);
-	return 0;
-}
-
-static int
-np_ulonglong(char *p, PyObject *v, const formatdef *f)
-{
-	unsigned PY_LONG_LONG x;
-	if (get_ulonglong(v, &x) < 0)
-		return -1;
-	memcpy(p, (char *)&x, sizeof x);
-	return 0;
-}
-#endif
-
-static int
-np_float(char *p, PyObject *v, const formatdef *f)
-{
-	float x = (float)PyFloat_AsDouble(v);
-	if (x == -1 && PyErr_Occurred()) {
-		PyErr_SetString(StructError,
-				"required argument is not a float");
-		return -1;
-	}
-	memcpy(p, (char *)&x, sizeof x);
-	return 0;
-}
-
-static int
-np_double(char *p, PyObject *v, const formatdef *f)
-{
-	double x = PyFloat_AsDouble(v);
-	if (x == -1 && PyErr_Occurred()) {
-		PyErr_SetString(StructError,
-				"required argument is not a float");
-		return -1;
-	}
-	memcpy(p, (char *)&x, sizeof(double));
-	return 0;
-}
-
-static int
-np_void_p(char *p, PyObject *v, const formatdef *f)
-{
-	void *x;
-
-	v = get_pylong(v);
-	if (v == NULL)
-		return -1;
-	assert(PyLong_Check(v));
-	x = PyLong_AsVoidPtr(v);
-	Py_DECREF(v);
-	if (x == NULL && PyErr_Occurred())
-		return -1;
-	memcpy(p, (char *)&x, sizeof x);
-	return 0;
-}
-
-static formatdef native_table[] = {
-	{'x',	sizeof(char),	0,		NULL},
-	{'b',	sizeof(char),	0,		nu_byte,	np_byte},
-	{'B',	sizeof(char),	0,		nu_ubyte,	np_ubyte},
-	{'c',	sizeof(char),	0,		nu_char,	np_char},
-	{'s',	sizeof(char),	0,		NULL},
-	{'p',	sizeof(char),	0,		NULL},
-	{'h',	sizeof(short),	SHORT_ALIGN,	nu_short,	np_short},
-	{'H',	sizeof(short),	SHORT_ALIGN,	nu_ushort,	np_ushort},
-	{'i',	sizeof(int),	INT_ALIGN,	nu_int,		np_int},
-	{'I',	sizeof(int),	INT_ALIGN,	nu_uint,	np_uint},
-	{'l',	sizeof(long),	LONG_ALIGN,	nu_long,	np_long},
-	{'L',	sizeof(long),	LONG_ALIGN,	nu_ulong,	np_ulong},
-	{'f',	sizeof(float),	FLOAT_ALIGN,	nu_float,	np_float},
-	{'d',	sizeof(double),	DOUBLE_ALIGN,	nu_double,	np_double},
-	{'P',	sizeof(void *),	VOID_P_ALIGN,	nu_void_p,	np_void_p},
-#ifdef HAVE_LONG_LONG
-	{'q',	sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_longlong, np_longlong},
-	{'Q',	sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_ulonglong,np_ulonglong},
-#endif
-	{0}
-};
-
-/* Big-endian routines. *****************************************************/
-
-static PyObject *
-bu_int(const char *p, const formatdef *f)
-{
-	long x = 0;
-	int i = f->size;
-	do {
-		x = (x<<8) | (*p++ & 0xFF);
-	} while (--i > 0);
-	/* Extend the sign bit. */
-	if (SIZEOF_LONG > f->size)
-		x |= -(x & (1L << (8*f->size - 1)));
-	return PyInt_FromLong(x);
-}
-
-static PyObject *
-bu_uint(const char *p, const formatdef *f)
-{
-	unsigned long x = 0;
-	int i = f->size;
-	do {
-		x = (x<<8) | (*p++ & 0xFF);
-	} while (--i > 0);
-	if (f->size >= 4)
-		return PyLong_FromUnsignedLong(x);
-	else
-		return PyInt_FromLong((long)x);
-}
-
-static PyObject *
-bu_longlong(const char *p, const formatdef *f)
-{
-	return _PyLong_FromByteArray((const unsigned char *)p,
-				      8,
-				      0, /* little-endian */
-				      1  /* signed */);
-}
-
-static PyObject *
-bu_ulonglong(const char *p, const formatdef *f)
-{
-	return _PyLong_FromByteArray((const unsigned char *)p,
-				      8,
-				      0, /* little-endian */
-				      0  /* signed */);
-}
-
-static PyObject *
-bu_float(const char *p, const formatdef *f)
-{
-	return unpack_float(p, 0);
-}
-
-static PyObject *
-bu_double(const char *p, const formatdef *f)
-{
-	return unpack_double(p, 0);
-}
-
-static int
-bp_int(char *p, PyObject *v, const formatdef *f)
-{
-	long x;
-	int i;
-	if (get_long(v, &x) < 0)
-		return -1;
-	i = f->size;
-	do {
-		p[--i] = (char)x;
-		x >>= 8;
-	} while (i > 0);
-	return 0;
-}
-
-static int
-bp_uint(char *p, PyObject *v, const formatdef *f)
-{
-	unsigned long x;
-	int i;
-	if (get_ulong(v, &x) < 0)
-		return -1;
-	i = f->size;
-	do {
-		p[--i] = (char)x;
-		x >>= 8;
-	} while (i > 0);
-	return 0;
-}
-
-static int
-bp_longlong(char *p, PyObject *v, const formatdef *f)
-{
-	int res;
-	v = get_pylong(v);
-	if (v == NULL)
-		return -1;
-	res = _PyLong_AsByteArray((PyLongObject *)v,
-			   	  (unsigned char *)p,
-				  8,
-				  0, /* little_endian */
-				  1  /* signed */);
-	Py_DECREF(v);
-	return res;
-}
-
-static int
-bp_ulonglong(char *p, PyObject *v, const formatdef *f)
-{
-	int res;
-	v = get_pylong(v);
-	if (v == NULL)
-		return -1;
-	res = _PyLong_AsByteArray((PyLongObject *)v,
-			   	  (unsigned char *)p,
-				  8,
-				  0, /* little_endian */
-				  0  /* signed */);
-	Py_DECREF(v);
-	return res;
-}
-
-static int
-bp_float(char *p, PyObject *v, const formatdef *f)
-{
-	double x = PyFloat_AsDouble(v);
-	if (x == -1 && PyErr_Occurred()) {
-		PyErr_SetString(StructError,
-				"required argument is not a float");
-		return -1;
-	}
-	return _PyFloat_Pack4(x, (unsigned char *)p, 0);
-}
-
-static int
-bp_double(char *p, PyObject *v, const formatdef *f)
-{
-	double x = PyFloat_AsDouble(v);
-	if (x == -1 && PyErr_Occurred()) {
-		PyErr_SetString(StructError,
-				"required argument is not a float");
-		return -1;
-	}
-	return _PyFloat_Pack8(x, (unsigned char *)p, 0);
-}
-
-static formatdef bigendian_table[] = {
-	{'x',	1,		0,		NULL},
-	{'b',	1,		0,		bu_int,		bp_int},
-	{'B',	1,		0,		bu_uint,	bp_int},
-	{'c',	1,		0,		nu_char,	np_char},
-	{'s',	1,		0,		NULL},
-	{'p',	1,		0,		NULL},
-	{'h',	2,		0,		bu_int,		bp_int},
-	{'H',	2,		0,		bu_uint,	bp_uint},
-	{'i',	4,		0,		bu_int,		bp_int},
-	{'I',	4,		0,		bu_uint,	bp_uint},
-	{'l',	4,		0,		bu_int,		bp_int},
-	{'L',	4,		0,		bu_uint,	bp_uint},
-	{'q',	8,		0,		bu_longlong,	bp_longlong},
-	{'Q',	8,		0,		bu_ulonglong,	bp_ulonglong},
-	{'f',	4,		0,		bu_float,	bp_float},
-	{'d',	8,		0,		bu_double,	bp_double},
-	{0}
-};
-
-/* Little-endian routines. *****************************************************/
-
-static PyObject *
-lu_int(const char *p, const formatdef *f)
-{
-	long x = 0;
-	int i = f->size;
-	do {
-		x = (x<<8) | (p[--i] & 0xFF);
-	} while (i > 0);
-	/* Extend the sign bit. */
-	if (SIZEOF_LONG > f->size)
-		x |= -(x & (1L << (8*f->size - 1)));
-	return PyInt_FromLong(x);
-}
-
-static PyObject *
-lu_uint(const char *p, const formatdef *f)
-{
-	unsigned long x = 0;
-	int i = f->size;
-	do {
-		x = (x<<8) | (p[--i] & 0xFF);
-	} while (i > 0);
-	if (f->size >= 4)
-		return PyLong_FromUnsignedLong(x);
-	else
-		return PyInt_FromLong((long)x);
-}
-
-static PyObject *
-lu_longlong(const char *p, const formatdef *f)
-{
-	return _PyLong_FromByteArray((const unsigned char *)p,
-				      8,
-				      1, /* little-endian */
-				      1  /* signed */);
-}
-
-static PyObject *
-lu_ulonglong(const char *p, const formatdef *f)
-{
-	return _PyLong_FromByteArray((const unsigned char *)p,
-				      8,
-				      1, /* little-endian */
-				      0  /* signed */);
-}
-
-static PyObject *
-lu_float(const char *p, const formatdef *f)
-{
-	return unpack_float(p, 1);
-}
-
-static PyObject *
-lu_double(const char *p, const formatdef *f)
-{
-	return unpack_double(p, 1);
-}
-
-static int
-lp_int(char *p, PyObject *v, const formatdef *f)
-{
-	long x;
-	int i;
-	if (get_long(v, &x) < 0)
-		return -1;
-	i = f->size;
-	do {
-		*p++ = (char)x;
-		x >>= 8;
-	} while (--i > 0);
-	return 0;
-}
-
-static int
-lp_uint(char *p, PyObject *v, const formatdef *f)
-{
-	unsigned long x;
-	int i;
-	if (get_ulong(v, &x) < 0)
-		return -1;
-	i = f->size;
-	do {
-		*p++ = (char)x;
-		x >>= 8;
-	} while (--i > 0);
-	return 0;
-}
-
-static int
-lp_longlong(char *p, PyObject *v, const formatdef *f)
-{
-	int res;
-	v = get_pylong(v);
-	if (v == NULL)
-		return -1;
-	res = _PyLong_AsByteArray((PyLongObject*)v,
-			   	  (unsigned char *)p,
-				  8,
-				  1, /* little_endian */
-				  1  /* signed */);
-	Py_DECREF(v);
-	return res;
-}
-
-static int
-lp_ulonglong(char *p, PyObject *v, const formatdef *f)
-{
-	int res;
-	v = get_pylong(v);
-	if (v == NULL)
-		return -1;
-	res = _PyLong_AsByteArray((PyLongObject*)v,
-			   	  (unsigned char *)p,
-				  8,
-				  1, /* little_endian */
-				  0  /* signed */);
-	Py_DECREF(v);
-	return res;
-}
-
-static int
-lp_float(char *p, PyObject *v, const formatdef *f)
-{
-	double x = PyFloat_AsDouble(v);
-	if (x == -1 && PyErr_Occurred()) {
-		PyErr_SetString(StructError,
-				"required argument is not a float");
-		return -1;
-	}
-	return _PyFloat_Pack4(x, (unsigned char *)p, 1);
-}
-
-static int
-lp_double(char *p, PyObject *v, const formatdef *f)
-{
-	double x = PyFloat_AsDouble(v);
-	if (x == -1 && PyErr_Occurred()) {
-		PyErr_SetString(StructError,
-				"required argument is not a float");
-		return -1;
-	}
-	return _PyFloat_Pack8(x, (unsigned char *)p, 1);
-}
-
-static formatdef lilendian_table[] = {
-	{'x',	1,		0,		NULL},
-	{'b',	1,		0,		lu_int,		lp_int},
-	{'B',	1,		0,		lu_uint,	lp_int},
-	{'c',	1,		0,		nu_char,	np_char},
-	{'s',	1,		0,		NULL},
-	{'p',	1,		0,		NULL},
-	{'h',	2,		0,		lu_int,		lp_int},
-	{'H',	2,		0,		lu_uint,	lp_uint},
-	{'i',	4,		0,		lu_int,		lp_int},
-	{'I',	4,		0,		lu_uint,	lp_uint},
-	{'l',	4,		0,		lu_int,		lp_int},
-	{'L',	4,		0,		lu_uint,	lp_uint},
-	{'q',	8,		0,		lu_longlong,	lp_longlong},
-	{'Q',	8,		0,		lu_ulonglong,	lp_ulonglong},
-	{'f',	4,		0,		lu_float,	lp_float},
-	{'d',	8,		0,		lu_double,	lp_double},
-	{0}
-};
-
-
-static const formatdef *
-whichtable(char **pfmt)
-{
-	const char *fmt = (*pfmt)++; /* May be backed out of later */
-	switch (*fmt) {
-	case '<':
-		return lilendian_table;
-	case '>':
-	case '!': /* Network byte order is big-endian */
-		return bigendian_table;
-	case '=': { /* Host byte order -- different from native in aligment! */
-		int n = 1;
-		char *p = (char *) &n;
-		if (*p == 1)
-			return lilendian_table;
-		else
-			return bigendian_table;
-	}
-	default:
-		--*pfmt; /* Back out of pointer increment */
-		/* Fall through */
-	case '@':
-		return native_table;
-	}
-}
-
-
-/* Get the table entry for a format code */
-
-static const formatdef *
-getentry(int c, const formatdef *f)
-{
-	for (; f->format != '\0'; f++) {
-		if (f->format == c) {
-			return f;
-		}
-	}
-	PyErr_SetString(StructError, "bad char in struct format");
-	return NULL;
-}
-
-
-/* Align a size according to a format code */
-
-static int
-align(int size, int c, const formatdef *e)
-{
-	if (e->format == c) {
-		if (e->alignment) {
-			size = ((size + e->alignment - 1)
-				/ e->alignment)
-				* e->alignment;
-		}
-	}
-	return size;
-}
-
-
-/* calculate the size of a format string */
-
-static int
-calcsize(const char *fmt, const formatdef *f)
-{
-	const formatdef *e;
-	const char *s;
-	char c;
-	int size,  num, itemsize, x;
-
-	s = fmt;
-	size = 0;
-	while ((c = *s++) != '\0') {
-		if (isspace(Py_CHARMASK(c)))
-			continue;
-		if ('0' <= c && c <= '9') {
-			num = c - '0';
-			while ('0' <= (c = *s++) && c <= '9') {
-				x = num*10 + (c - '0');
-				if (x/10 != num) {
-					PyErr_SetString(
-						StructError,
-						"overflow in item count");
-					return -1;
-				}
-				num = x;
-			}
-			if (c == '\0')
-				break;
-		}
-		else
-			num = 1;
-
-		e = getentry(c, f);
-		if (e == NULL)
-			return -1;
-		itemsize = e->size;
-		size = align(size, c, e);
-		x = num * itemsize;
-		size += x;
-		if (x/itemsize != num || size < 0) {
-			PyErr_SetString(StructError,
-					"total struct size too long");
-			return -1;
-		}
-	}
-
-	return size;
-}
-
-
-PyDoc_STRVAR(calcsize__doc__,
-"calcsize(fmt) -> int\n\
-Return size of C struct described by format string fmt.\n\
-See struct.__doc__ for more on format strings.");
-
-static PyObject *
-struct_calcsize(PyObject *self, PyObject *args)
-{
-	char *fmt;
-	const formatdef *f;
-	int size;
-
-	if (!PyArg_ParseTuple(args, "s:calcsize", &fmt))
-		return NULL;
-	f = whichtable(&fmt);
-	size = calcsize(fmt, f);
-	if (size < 0)
-		return NULL;
-	return PyInt_FromLong((long)size);
-}
-
-
-PyDoc_STRVAR(pack__doc__,
-"pack(fmt, v1, v2, ...) -> string\n\
-Return string containing values v1, v2, ... packed according to fmt.\n\
-See struct.__doc__ for more on format strings.");
-
-static PyObject *
-struct_pack(PyObject *self, PyObject *args)
-{
-	const formatdef *f, *e;
-	PyObject *format, *result, *v;
-	char *fmt;
-	int size, num;
-	Py_ssize_t i, n;
-	char *s, *res, *restart, *nres;
-	char c;
-
-	if (args == NULL || !PyTuple_Check(args) ||
-	    (n = PyTuple_Size(args)) < 1)
-	{
-		PyErr_SetString(PyExc_TypeError,
-			"struct.pack requires at least one argument");
-		return NULL;
-	}
-	format = PyTuple_GetItem(args, 0);
-	fmt = PyString_AsString(format);
-	if (!fmt)
-		return NULL;
-	f = whichtable(&fmt);
-	size = calcsize(fmt, f);
-	if (size < 0)
-		return NULL;
-	result = PyString_FromStringAndSize((char *)NULL, size);
-	if (result == NULL)
-		return NULL;
-
-	s = fmt;
-	i = 1;
-	res = restart = PyString_AsString(result);
-
-	while ((c = *s++) != '\0') {
-		if (isspace(Py_CHARMASK(c)))
-			continue;
-		if ('0' <= c && c <= '9') {
-			num = c - '0';
-			while ('0' <= (c = *s++) && c <= '9')
-			       num = num*10 + (c - '0');
-			if (c == '\0')
-				break;
-		}
-		else
-			num = 1;
-
-		e = getentry(c, f);
-		if (e == NULL)
-			goto fail;
-		nres = restart + align((int)(res-restart), c, e);
-		/* Fill padd bytes with zeros */
-		while (res < nres)
-			*res++ = '\0';
-		if (num == 0 && c != 's')
-			continue;
-		do {
-			if (c == 'x') {
-				/* doesn't consume arguments */
-				memset(res, '\0', num);
-				res += num;
-				break;
-			}
-			if (i >= n) {
-				PyErr_SetString(StructError,
-					"insufficient arguments to pack");
-				goto fail;
-				}
-			v = PyTuple_GetItem(args, i++);
-			if (v == NULL)
-				goto fail;
-			if (c == 's') {
-				/* num is string size, not repeat count */
-				Py_ssize_t n;
-				if (!PyString_Check(v)) {
-					PyErr_SetString(StructError,
-					  "argument for 's' must be a string");
-					goto fail;
-				}
-				n = PyString_Size(v);
-				if (n > num)
-					n = num;
-				if (n > 0)
-					memcpy(res, PyString_AsString(v), n);
-				if (n < num)
-					memset(res+n, '\0', num-n);
-				res += num;
-				break;
-			}
-			else if (c == 'p') {
-				/* num is string size + 1,
-				   to fit in the count byte */
-				Py_ssize_t n;
-				num--; /* now num is max string size */
-				if (!PyString_Check(v)) {
-					PyErr_SetString(StructError,
-					  "argument for 'p' must be a string");
-					goto fail;
-				}
-				n = PyString_Size(v);
-				if (n > num)
-					n = num;
-				if (n > 0)
-					memcpy(res+1, PyString_AsString(v), n);
-				if (n < num)
-					/* no real need, just to be nice */
-					memset(res+1+n, '\0', num-n);
-				if (n > 255)
-					n = 255;
-				/* store the length byte */
-				*res++ = Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char);
-				res += num;
-				break;
-			}
-			else {
-				if (e->pack(res, v, e) < 0)
-					goto fail;
-				res += e->size;
-			}
-		} while (--num > 0);
-	}
-
-	if (i < n) {
-		PyErr_SetString(StructError,
-				"too many arguments for pack format");
-		goto fail;
-	}
-
-	return result;
-
- fail:
-	Py_DECREF(result);
-	return NULL;
-}
-
-
-PyDoc_STRVAR(unpack__doc__,
-"unpack(fmt, string) -> (v1, v2, ...)\n\
-Unpack the string, containing packed C structure data, according\n\
-to fmt.  Requires len(string)==calcsize(fmt).\n\
-See struct.__doc__ for more on format strings.");
-
-static PyObject *
-struct_unpack(PyObject *self, PyObject *args)
-{
-	const formatdef *f, *e;
-	char *str, *start, *fmt, *s;
-	char c;
-	int len, size, num;
-	PyObject *res, *v;
-
-	if (!PyArg_ParseTuple(args, "ss#:unpack", &fmt, &start, &len))
-		return NULL;
-	f = whichtable(&fmt);
-	size = calcsize(fmt, f);
-	if (size < 0)
-		return NULL;
-	if (size != len) {
-		PyErr_SetString(StructError,
-				"unpack str size does not match format");
-		return NULL;
-	}
-	res = PyList_New(0);
-	if (res == NULL)
-		return NULL;
-	str = start;
-	s = fmt;
-	while ((c = *s++) != '\0') {
-		if (isspace(Py_CHARMASK(c)))
-			continue;
-		if ('0' <= c && c <= '9') {
-			num = c - '0';
-			while ('0' <= (c = *s++) && c <= '9')
-			       num = num*10 + (c - '0');
-			if (c == '\0')
-				break;
-		}
-		else
-			num = 1;
-
-		e = getentry(c, f);
-		if (e == NULL)
-			goto fail;
-		str = start + align((int)(str-start), c, e);
-		if (num == 0 && c != 's')
-			continue;
-
-		do {
-			if (c == 'x') {
-				str += num;
-				break;
-			}
-			if (c == 's') {
-				/* num is string size, not repeat count */
-				v = PyString_FromStringAndSize(str, num);
-				if (v == NULL)
-					goto fail;
-				str += num;
-				num = 0;
-			}
-			else if (c == 'p') {
-				/* num is string buffer size,
-				   not repeat count */
-				int n = *(unsigned char*)str;
-				/* first byte (unsigned) is string size */
-				if (n >= num)
-					n = num-1;
-				v = PyString_FromStringAndSize(str+1, n);
-				if (v == NULL)
-					goto fail;
-				str += num;
-				num = 0;
-			}
-			else {
-				v = e->unpack(str, e);
-				if (v == NULL)
-					goto fail;
-				str += e->size;
-			}
-			if (v == NULL || PyList_Append(res, v) < 0)
-				goto fail;
-			Py_DECREF(v);
-		} while (--num > 0);
-	}
-
-	v = PyList_AsTuple(res);
-	Py_DECREF(res);
-	return v;
-
- fail:
-	Py_DECREF(res);
-	return NULL;
-}
-
-
-/* List of functions */
-
-static PyMethodDef struct_methods[] = {
-	{"calcsize",	struct_calcsize,	METH_VARARGS, calcsize__doc__},
-	{"pack",	struct_pack,		METH_VARARGS, pack__doc__},
-	{"unpack",	struct_unpack,		METH_VARARGS, unpack__doc__},
-	{NULL,		NULL}		/* sentinel */
-};
-
-
-/* Module initialization */
-
-PyMODINIT_FUNC
-initstruct(void)
-{
-	PyObject *m;
-
-	/* Create the module and add the functions */
-	m = Py_InitModule4("struct", struct_methods, struct__doc__,
-			   (PyObject*)NULL, PYTHON_API_VERSION);
-	if (m == NULL)
-		return;
-
-	/* Add some symbolic constants to the module */
-	if (StructError == NULL) {
-		StructError = PyErr_NewException("struct.error", NULL, NULL);
-		if (StructError == NULL)
-			return;
-	}
-	Py_INCREF(StructError);
-	PyModule_AddObject(m, "error", StructError);
-}

Modified: python/branches/blais-bytebuf/Objects/codeobject.c
==============================================================================
--- python/branches/blais-bytebuf/Objects/codeobject.c	(original)
+++ python/branches/blais-bytebuf/Objects/codeobject.c	Wed May 24 20:30:42 2006
@@ -102,6 +102,7 @@
 		co->co_firstlineno = firstlineno;
 		Py_INCREF(lnotab);
 		co->co_lnotab = lnotab;
+                co->co_zombieframe = NULL;
 	}
 	return co;
 }
@@ -265,6 +266,8 @@
 	Py_XDECREF(co->co_filename);
 	Py_XDECREF(co->co_name);
 	Py_XDECREF(co->co_lnotab);
+        if (co->co_zombieframe != NULL)
+                PyObject_GC_Del(co->co_zombieframe);
 	PyObject_DEL(co);
 }
 

Modified: python/branches/blais-bytebuf/Objects/frameobject.c
==============================================================================
--- python/branches/blais-bytebuf/Objects/frameobject.c	(original)
+++ python/branches/blais-bytebuf/Objects/frameobject.c	Wed May 24 20:30:42 2006
@@ -350,13 +350,32 @@
 };
 
 /* Stack frames are allocated and deallocated at a considerable rate.
-   In an attempt to improve the speed of function calls, we maintain a
-   separate free list of stack frames (just like integers are
-   allocated in a special way -- see intobject.c).  When a stack frame
-   is on the free list, only the following members have a meaning:
+   In an attempt to improve the speed of function calls, we:
+
+   1. Hold a single "zombie" frame on each code object. This retains
+   the allocated and initialised frame object from an invocation of
+   the code object. The zombie is reanimated the next time we need a
+   frame object for that code object. Doing this saves the malloc/
+   realloc required when using a free_list frame that isn't the
+   correct size. It also saves some field initialisation.
+
+   In zombie mode, no field of PyFrameObject holds a reference, but
+   the following fields are still valid:
+
+     * ob_type, ob_size, f_code, f_valuestack;
+       
+     * f_locals, f_trace,
+       f_exc_type, f_exc_value, f_exc_traceback are NULL;
+
+     * f_localsplus does not require re-allocation and
+       the local variables in f_localsplus are NULL.
+
+   2. We also maintain a separate free list of stack frames (just like
+   integers are allocated in a special way -- see intobject.c).  When
+   a stack frame is on the free list, only the following members have
+   a meaning:
 	ob_type		== &Frametype
 	f_back		next item on free list, or NULL
-	f_nlocals	number of locals
 	f_stacksize	size of value stack
         ob_size         size of localsplus
    Note that the value and block stacks are preserved -- this can save
@@ -380,41 +399,43 @@
 static void
 frame_dealloc(PyFrameObject *f)
 {
-	int i, slots;
-	PyObject **fastlocals;
-	PyObject **p;
+	PyObject **p, **valuestack;
+	PyCodeObject *co;
 
  	PyObject_GC_UnTrack(f);
 	Py_TRASHCAN_SAFE_BEGIN(f)
 	/* Kill all local variables */
-	slots = f->f_nlocals + f->f_ncells + f->f_nfreevars;
-	fastlocals = f->f_localsplus;
-	for (i = slots; --i >= 0; ++fastlocals) {
-		Py_XDECREF(*fastlocals);
-	}
+        valuestack = f->f_valuestack;
+        for (p = f->f_localsplus; p < valuestack; p++)
+                Py_CLEAR(*p);
 
 	/* Free stack */
 	if (f->f_stacktop != NULL) {
-		for (p = f->f_valuestack; p < f->f_stacktop; p++)
+		for (p = valuestack; p < f->f_stacktop; p++)
 			Py_XDECREF(*p);
 	}
 
 	Py_XDECREF(f->f_back);
-	Py_DECREF(f->f_code);
 	Py_DECREF(f->f_builtins);
 	Py_DECREF(f->f_globals);
-	Py_XDECREF(f->f_locals);
-	Py_XDECREF(f->f_trace);
-	Py_XDECREF(f->f_exc_type);
-	Py_XDECREF(f->f_exc_value);
-	Py_XDECREF(f->f_exc_traceback);
-	if (numfree < MAXFREELIST) {
+	Py_CLEAR(f->f_locals);
+	Py_CLEAR(f->f_trace);
+	Py_CLEAR(f->f_exc_type);
+	Py_CLEAR(f->f_exc_value);
+	Py_CLEAR(f->f_exc_traceback);
+
+        co = f->f_code;
+        if (co != NULL && co->co_zombieframe == NULL)
+                co->co_zombieframe = f;
+	else if (numfree < MAXFREELIST) {
 		++numfree;
 		f->f_back = free_list;
 		free_list = f;
-	}
-	else
+        }
+	else 
 		PyObject_GC_Del(f);
+
+        Py_XDECREF(co);
 	Py_TRASHCAN_SAFE_END(f)
 }
 
@@ -435,7 +456,7 @@
 	Py_VISIT(f->f_exc_traceback);
 
 	/* locals */
-	slots = f->f_nlocals + f->f_ncells + f->f_nfreevars;
+	slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars);
 	fastlocals = f->f_localsplus;
 	for (i = slots; --i >= 0; ++fastlocals)
 		Py_VISIT(*fastlocals);
@@ -468,7 +489,7 @@
 	Py_CLEAR(f->f_trace);
 
 	/* locals */
-	slots = f->f_nlocals + f->f_ncells + f->f_nfreevars;
+	slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars);
 	fastlocals = f->f_localsplus;
 	for (i = slots; --i >= 0; ++fastlocals)
 		Py_CLEAR(*fastlocals);
@@ -532,7 +553,7 @@
 	PyFrameObject *back = tstate->frame;
 	PyFrameObject *f;
 	PyObject *builtins;
-	Py_ssize_t extras, ncells, nfrees, i;
+	Py_ssize_t i;
 
 #ifdef Py_DEBUG
 	if (code == NULL || globals == NULL || !PyDict_Check(globals) ||
@@ -541,9 +562,6 @@
 		return NULL;
 	}
 #endif
-	ncells = PyTuple_GET_SIZE(code->co_cellvars);
-	nfrees = PyTuple_GET_SIZE(code->co_freevars);
-	extras = code->co_stacksize + code->co_nlocals + ncells + nfrees;
 	if (back == NULL || back->f_globals != globals) {
 		builtins = PyDict_GetItem(globals, builtin_object);
 		if (builtins) {
@@ -574,71 +592,82 @@
 		assert(builtins != NULL && PyDict_Check(builtins));
 		Py_INCREF(builtins);
 	}
-	if (free_list == NULL) {
-		f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, extras);
-		if (f == NULL) {
-			Py_DECREF(builtins);
-			return NULL;
-		}
-	}
-	else {
-		assert(numfree > 0);
-		--numfree;
-		f = free_list;
-		free_list = free_list->f_back;
-		if (f->ob_size < extras) {
-			f = PyObject_GC_Resize(PyFrameObject, f, extras);
-			if (f == NULL) {
-				Py_DECREF(builtins);
-				return NULL;
-			}
-		}
-		_Py_NewReference((PyObject *)f);
+	if (code->co_zombieframe != NULL) {
+                f = code->co_zombieframe;
+                code->co_zombieframe = NULL;
+                _Py_NewReference((PyObject *)f);
+                assert(f->f_code == code);
+	}
+        else {
+                Py_ssize_t extras, ncells, nfrees;
+                ncells = PyTuple_GET_SIZE(code->co_cellvars);
+                nfrees = PyTuple_GET_SIZE(code->co_freevars);
+                extras = code->co_stacksize + code->co_nlocals + ncells +
+                    nfrees;
+                if (free_list == NULL) {
+                    f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type,
+                        extras);
+                    if (f == NULL) {
+                            Py_DECREF(builtins);
+                            return NULL;
+                    }
+                }
+                else {
+                    assert(numfree > 0);
+                    --numfree;
+                    f = free_list;
+                    free_list = free_list->f_back;
+                    if (f->ob_size < extras) {
+                            f = PyObject_GC_Resize(PyFrameObject, f, extras);
+                            if (f == NULL) {
+                                    Py_DECREF(builtins);
+                                    return NULL;
+                            }
+                    }
+                    _Py_NewReference((PyObject *)f);
+                }
+
+		f->f_code = code;
+		extras = code->co_nlocals + ncells + nfrees;
+		f->f_valuestack = f->f_localsplus + extras;
+		for (i=0; i<extras; i++)
+			f->f_localsplus[i] = NULL;
+		f->f_locals = NULL;
+		f->f_trace = NULL;
+                f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL;
 	}
 	f->f_builtins = builtins;
 	Py_XINCREF(back);
 	f->f_back = back;
 	Py_INCREF(code);
-	f->f_code = code;
 	Py_INCREF(globals);
 	f->f_globals = globals;
 	/* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */
 	if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) ==
 		(CO_NEWLOCALS | CO_OPTIMIZED))
-		locals = NULL; /* PyFrame_FastToLocals() will set. */
+		; /* f_locals = NULL; will be set by PyFrame_FastToLocals() */
 	else if (code->co_flags & CO_NEWLOCALS) {
 		locals = PyDict_New();
 		if (locals == NULL) {
 			Py_DECREF(f);
 			return NULL;
 		}
+                f->f_locals = locals;
 	}
 	else {
 		if (locals == NULL)
 			locals = globals;
 		Py_INCREF(locals);
+                f->f_locals = locals;
 	}
-	f->f_locals = locals;
-	f->f_trace = NULL;
-	f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL;
 	f->f_tstate = tstate;
 
 	f->f_lasti = -1;
 	f->f_lineno = code->co_firstlineno;
 	f->f_restricted = (builtins != tstate->interp->builtins);
 	f->f_iblock = 0;
-	f->f_nlocals = code->co_nlocals;
-	f->f_stacksize = code->co_stacksize;
-	f->f_ncells = ncells;
-	f->f_nfreevars = nfrees;
-
-	extras = f->f_nlocals + ncells + nfrees;
-	/* Tim said it's ok to replace memset */
-	for (i=0; i<extras; i++)
-		f->f_localsplus[i] = NULL;
 
-	f->f_valuestack = f->f_localsplus + extras;
-	f->f_stacktop = f->f_valuestack;
+        f->f_stacktop = f->f_valuestack;
 	_PyObject_GC_TRACK(f);
 	return f;
 }
@@ -725,7 +754,9 @@
 	PyObject *locals, *map;
 	PyObject **fast;
 	PyObject *error_type, *error_value, *error_traceback;
+	PyCodeObject *co;
 	Py_ssize_t j;
+        int ncells, nfreevars;
 	if (f == NULL)
 		return;
 	locals = f->f_locals;
@@ -736,27 +767,24 @@
 			return;
 		}
 	}
-	map = f->f_code->co_varnames;
+	co = f->f_code;
+	map = co->co_varnames;
 	if (!PyTuple_Check(map))
 		return;
 	PyErr_Fetch(&error_type, &error_value, &error_traceback);
 	fast = f->f_localsplus;
 	j = PyTuple_GET_SIZE(map);
-	if (j > f->f_nlocals)
-		j = f->f_nlocals;
-	if (f->f_nlocals)
+	if (j > co->co_nlocals)
+		j = co->co_nlocals;
+	if (co->co_nlocals)
 		map_to_dict(map, j, locals, fast, 0);
-	if (f->f_ncells || f->f_nfreevars) {
-		if (!(PyTuple_Check(f->f_code->co_cellvars)
-		      && PyTuple_Check(f->f_code->co_freevars))) {
-			return;
-		}
-		map_to_dict(f->f_code->co_cellvars,
-			    PyTuple_GET_SIZE(f->f_code->co_cellvars),
-			    locals, fast + f->f_nlocals, 1);
-		map_to_dict(f->f_code->co_freevars,
-			    PyTuple_GET_SIZE(f->f_code->co_freevars),
-			    locals, fast + f->f_nlocals + f->f_ncells, 1);
+	ncells = PyTuple_GET_SIZE(co->co_cellvars);
+	nfreevars = PyTuple_GET_SIZE(co->co_freevars);
+	if (ncells || nfreevars) {
+		map_to_dict(co->co_cellvars, ncells,
+			    locals, fast + co->co_nlocals, 1);
+		map_to_dict(co->co_freevars, nfreevars,
+			    locals, fast + co->co_nlocals + ncells, 1);
 	}
 	PyErr_Restore(error_type, error_value, error_traceback);
 }
@@ -768,11 +796,14 @@
 	PyObject *locals, *map;
 	PyObject **fast;
 	PyObject *error_type, *error_value, *error_traceback;
+	PyCodeObject *co;
 	Py_ssize_t j;
+	int ncells, nfreevars;
 	if (f == NULL)
 		return;
 	locals = f->f_locals;
-	map = f->f_code->co_varnames;
+	co = f->f_code;
+	map = co->co_varnames;
 	if (locals == NULL)
 		return;
 	if (!PyTuple_Check(map))
@@ -780,21 +811,18 @@
 	PyErr_Fetch(&error_type, &error_value, &error_traceback);
 	fast = f->f_localsplus;
 	j = PyTuple_GET_SIZE(map);
-	if (j > f->f_nlocals)
-		j = f->f_nlocals;
-	if (f->f_nlocals)
-	    dict_to_map(f->f_code->co_varnames, j, locals, fast, 0, clear);
-	if (f->f_ncells || f->f_nfreevars) {
-		if (!(PyTuple_Check(f->f_code->co_cellvars)
-		      && PyTuple_Check(f->f_code->co_freevars)))
-			return;
-		dict_to_map(f->f_code->co_cellvars,
-			    PyTuple_GET_SIZE(f->f_code->co_cellvars),
-			    locals, fast + f->f_nlocals, 1, clear);
-		dict_to_map(f->f_code->co_freevars,
-			    PyTuple_GET_SIZE(f->f_code->co_freevars),
-			    locals, fast + f->f_nlocals + f->f_ncells, 1,
-			    clear);
+	if (j > co->co_nlocals)
+		j = co->co_nlocals;
+	if (co->co_nlocals)
+	    dict_to_map(co->co_varnames, j, locals, fast, 0, clear);
+	ncells = PyTuple_GET_SIZE(co->co_cellvars);
+	nfreevars = PyTuple_GET_SIZE(co->co_freevars);
+	if (ncells || nfreevars) {
+		dict_to_map(co->co_cellvars, ncells,
+			    locals, fast + co->co_nlocals, 1, clear);
+		dict_to_map(co->co_freevars, nfreevars,
+			    locals, fast + co->co_nlocals + ncells, 1, 
+ 			    clear);
 	}
 	PyErr_Restore(error_type, error_value, error_traceback);
 }

Modified: python/branches/blais-bytebuf/Objects/unicodeobject.c
==============================================================================
--- python/branches/blais-bytebuf/Objects/unicodeobject.c	(original)
+++ python/branches/blais-bytebuf/Objects/unicodeobject.c	Wed May 24 20:30:42 2006
@@ -46,6 +46,18 @@
 #include <windows.h>
 #endif
 
+#undef USE_INLINE /* XXX - set via configure? */
+
+#if defined(_MSC_VER) /* this is taken from _sre.c */
+#pragma warning(disable: 4710)
+/* fastest possible local call under MSVC */
+#define LOCAL(type) static __inline type __fastcall
+#elif defined(USE_INLINE)
+#define LOCAL(type) static inline type
+#else
+#define LOCAL(type) static type
+#endif
+
 /* Limit for the Unicode object free list */
 
 #define MAX_UNICODE_FREELIST_SIZE       1024
@@ -121,6 +133,51 @@
 #endif
 }
 
+/* --- Bloom Filters ----------------------------------------------------- */
+
+/* stuff to implement simple "bloom filters" for Unicode characters.
+   to keep things simple, we use a single bitmask, using the least 5
+   bits from each unicode characters as the bit index. */
+
+/* the linebreak mask is set up by Unicode_Init below */
+
+#define BLOOM_MASK unsigned long
+
+static BLOOM_MASK bloom_linebreak;
+
+#define BLOOM(mask, ch) ((mask & (1 << ((ch) & 0x1F))))
+
+#define BLOOM_LINEBREAK(ch)\
+    (BLOOM(bloom_linebreak, (ch)) && Py_UNICODE_ISLINEBREAK((ch)))
+
+LOCAL(BLOOM_MASK) make_bloom_mask(Py_UNICODE* ptr, Py_ssize_t len)
+{
+    /* calculate simple bloom-style bitmask for a given unicode string */
+
+    long mask;
+    Py_ssize_t i;
+
+    mask = 0;
+    for (i = 0; i < len; i++)
+        mask |= (1 << (ptr[i] & 0x1F));
+
+    return mask;
+}
+
+LOCAL(int) unicode_member(Py_UNICODE chr, Py_UNICODE* set, Py_ssize_t setlen)
+{
+    Py_ssize_t i;
+
+    for (i = 0; i < setlen; i++)
+        if (set[i] == chr)
+            return 1;
+
+    return 0;
+}
+
+#define BLOOM_MEMBER(mask, chr, set, setlen)\
+    BLOOM(mask, chr) && unicode_member(chr, set, setlen)
+
 /* --- Unicode Object ----------------------------------------------------- */
 
 static
@@ -1963,9 +2020,20 @@
 
 */
 
-static const Py_UNICODE *findchar(const Py_UNICODE *s,
-				  Py_ssize_t size,
-				  Py_UNICODE ch);
+LOCAL(const Py_UNICODE *) findchar(const Py_UNICODE *s,
+                                   Py_ssize_t size,
+                                   Py_UNICODE ch)
+{
+    /* like wcschr, but doesn't stop at NULL characters */
+
+    while (size-- > 0) {
+        if (*s == ch)
+            return s;
+        s++;
+    }
+
+    return NULL;
+}
 
 static
 PyObject *unicodeescape_string(const Py_UNICODE *s,
@@ -3791,8 +3859,98 @@
 
 /* --- Helpers ------------------------------------------------------------ */
 
-static
-Py_ssize_t count(PyUnicodeObject *self,
+#define USE_FAST /* experimental fast search implementation */
+
+/* fast search/count implementation, based on a mix between boyer-
+   moore and horspool, with a few more bells and whistles on the top.
+   for some more background, see: http://effbot.org/stringlib */
+
+/* note: fastsearch may access s[n], which isn't a problem when using
+   Python's ordinary string types.  also, the count mode returns -1 if
+   there cannot possible be a match in the target string, and 0 if it
+   has actually checked for matches. */
+
+#define FAST_COUNT 0
+#define FAST_SEARCH 1
+
+LOCAL(Py_ssize_t)
+fastsearch(Py_UNICODE* s, Py_ssize_t n, Py_UNICODE* p, Py_ssize_t m, int mode)
+{
+    long mask;
+    int skip, count = 0;
+    Py_ssize_t i, j, mlast, w;
+
+    w = n - m;
+
+    if (w < 0)
+        return -1;
+
+    /* look for special cases */
+    if (m <= 1) {
+        if (m <= 0)
+            return -1;
+        /* use special case for 1-character strings */
+        if (mode == FAST_COUNT) {
+            for (i = 0; i < n; i++)
+                if (s[i] == p[0])
+                    count++;
+            return count;
+        } else {
+            for (i = 0; i < n; i++)
+                if (s[i] == p[0])
+                    return i;
+        }
+        return -1;
+    }
+
+    mlast = m - 1;
+
+    /* create compressed boyer-moore delta 1 table */
+    skip = mlast - 1;
+    /* process pattern[:-1] */
+    for (mask = i = 0; i < mlast; i++) {
+        mask |= (1 << (p[i] & 0x1F));
+        if (p[i] == p[mlast])
+            skip = mlast - i - 1;
+    }
+    /* process pattern[-1] outside the loop */
+    mask |= (1 << (p[mlast] & 0x1F));
+
+    for (i = 0; i <= w; i++) {
+        /* note: using mlast in the skip path slows things down on x86 */
+        if (s[i+m-1] == p[m-1]) {
+            /* candidate match */
+            for (j = 0; j < mlast; j++)
+                if (s[i+j] != p[j])
+                    break;
+            if (j == mlast) {
+                /* got a match! */
+                if (mode != FAST_COUNT)
+                    return i;
+                count++;
+                i = i + mlast;
+                continue;
+            }
+            /* miss: check if next character is part of pattern */
+            if (!(mask & (1 << (s[i+m] & 0x1F))))
+                i = i + m;
+            else {
+                i = i + skip;
+                continue;
+            }
+        } else {
+            /* skip: check if next character is part of pattern */
+            if (!(mask & (1 << (s[i+m] & 0x1F))))
+                i = i + m;
+        }
+    }
+
+    if (mode != FAST_COUNT)
+        return -1;
+    return count;
+}
+
+LOCAL(Py_ssize_t) count(PyUnicodeObject *self,
 		 Py_ssize_t start,
 		 Py_ssize_t end,
 		 PyUnicodeObject *substring)
@@ -3813,6 +3971,14 @@
     if (substring->length == 0)
 	return (end - start + 1);
 
+#ifdef USE_FAST
+    count = fastsearch(
+        PyUnicode_AS_UNICODE(self) + start, end - start,
+        substring->str, substring->length, FAST_COUNT
+        );
+    if (count < 0)
+        count = 0; /* no match */
+#else    
     end -= substring->length;
 
     while (start <= end)
@@ -3821,6 +3987,7 @@
             start += substring->length;
         } else
             start++;
+#endif
 
     return count;
 }
@@ -3850,8 +4017,7 @@
     return result;
 }
 
-static
-Py_ssize_t findstring(PyUnicodeObject *self,
+static Py_ssize_t findstring(PyUnicodeObject *self,
 	       PyUnicodeObject *substring,
 	       Py_ssize_t start,
 	       Py_ssize_t end,
@@ -3872,6 +4038,18 @@
     if (substring->length == 0)
 	return (direction > 0) ? start : end;
 
+#ifdef USE_FAST
+    if (direction > 0) {
+        Py_ssize_t pos = fastsearch(
+            PyUnicode_AS_UNICODE(self) + start, end - start,
+            substring->str, substring->length, FAST_SEARCH
+            );
+        if (pos < 0)
+            return pos;
+        return pos + start;
+    }
+#endif
+
     end -= substring->length;
 
     if (direction < 0) {
@@ -3974,22 +4152,6 @@
     return result;
 }
 
-static
-const Py_UNICODE *findchar(const Py_UNICODE *s,
-		     Py_ssize_t size,
-		     Py_UNICODE ch)
-{
-    /* like wcschr, but doesn't stop at NULL characters */
-
-    while (size-- > 0) {
-        if (*s == ch)
-            return s;
-        s++;
-    }
-
-    return NULL;
-}
-
 /* Apply fixfct filter to the Unicode object self and return a
    reference to the modified object */
 
@@ -4332,17 +4494,6 @@
         else								\
             Py_DECREF(str);
 
-#define SPLIT_INSERT(data, left, right)					\
-	str = PyUnicode_FromUnicode((data) + (left), (right) - (left));	\
-	if (!str)							\
-	    goto onError;						\
-	if (PyList_Insert(list, 0, str)) {				\
-	    Py_DECREF(str);						\
-	    goto onError;						\
-	}								\
-        else								\
-            Py_DECREF(str);
-
 static
 PyObject *split_whitespace(PyUnicodeObject *self,
 			   PyObject *list,
@@ -4403,7 +4554,7 @@
 	Py_ssize_t eol;
 
 	/* Find a line and append it */
-	while (i < len && !Py_UNICODE_ISLINEBREAK(data[i]))
+	while (i < len && !BLOOM_LINEBREAK(data[i]))
 	    i++;
 
 	/* Skip the line break reading CRLF as one line break */
@@ -4514,15 +4665,17 @@
 	if (j > i) {
 	    if (maxcount-- <= 0)
 		break;
-	    SPLIT_INSERT(self->str, i + 1, j + 1);
+	    SPLIT_APPEND(self->str, i + 1, j + 1);
 	    while (i >= 0 && Py_UNICODE_ISSPACE(self->str[i]))
 		i--;
 	    j = i;
 	}
     }
     if (j >= 0) {
-	SPLIT_INSERT(self->str, 0, j + 1);
+	SPLIT_APPEND(self->str, 0, j + 1);
     }
+    if (PyList_Reverse(list) < 0)
+        goto onError;
     return list;
 
  onError:
@@ -4545,14 +4698,16 @@
 	if (self->str[i] == ch) {
 	    if (maxcount-- <= 0)
 		break;
-	    SPLIT_INSERT(self->str, i + 1, j + 1);
+	    SPLIT_APPEND(self->str, i + 1, j + 1);
 	    j = i = i - 1;
 	} else
 	    i--;
     }
     if (j >= -1) {
-	SPLIT_INSERT(self->str, 0, j + 1);
+	SPLIT_APPEND(self->str, 0, j + 1);
     }
+    if (PyList_Reverse(list) < 0)
+        goto onError;
     return list;
 
  onError:
@@ -4576,15 +4731,17 @@
 	if (Py_UNICODE_MATCH(self, i, substring)) {
 	    if (maxcount-- <= 0)
 		break;
-	    SPLIT_INSERT(self->str, i + sublen, j);
+	    SPLIT_APPEND(self->str, i + sublen, j);
 	    j = i;
 	    i -= sublen;
 	} else
 	    i--;
     }
     if (j >= 0) {
-	SPLIT_INSERT(self->str, 0, j);
+	SPLIT_APPEND(self->str, 0, j);
     }
+    if (PyList_Reverse(list) < 0)
+        goto onError;
     return list;
 
  onError:
@@ -4593,7 +4750,6 @@
 }
 
 #undef SPLIT_APPEND
-#undef SPLIT_INSERT
 
 static
 PyObject *split(PyUnicodeObject *self,
@@ -4664,36 +4820,47 @@
     if (maxcount < 0)
 	maxcount = PY_SSIZE_T_MAX;
 
-    if (str1->length == 1 && str2->length == 1) {
+    if (str1->length == str2->length) {
+        /* same length */
         Py_ssize_t i;
-
-        /* replace characters */
-        if (!findchar(self->str, self->length, str1->str[0]) &&
-            PyUnicode_CheckExact(self)) {
-            /* nothing to replace, return original string */
-            Py_INCREF(self);
-            u = self;
+        if (str1->length == 1) {
+            /* replace characters */
+            Py_UNICODE u1, u2;
+            if (!findchar(self->str, self->length, str1->str[0]))
+                goto nothing;
+            u = (PyUnicodeObject*) PyUnicode_FromUnicode(NULL, self->length);
+            if (!u)
+                return NULL;
+            Py_UNICODE_COPY(u->str, self->str, self->length);
+            u1 = str1->str[0];
+            u2 = str2->str[0];
+            for (i = 0; i < u->length; i++)
+                if (u->str[i] == u1) {
+                    if (--maxcount < 0)
+                        break;
+                    u->str[i] = u2;
+                }
         } else {
-	    Py_UNICODE u1 = str1->str[0];
-	    Py_UNICODE u2 = str2->str[0];
-
-            u = (PyUnicodeObject*) PyUnicode_FromUnicode(
-                NULL,
-                self->length
+            i = fastsearch(
+                self->str, self->length, str1->str, str1->length, FAST_SEARCH
                 );
-            if (u != NULL) {
-		Py_UNICODE_COPY(u->str, self->str,
-				self->length);
-                for (i = 0; i < u->length; i++)
-                    if (u->str[i] == u1) {
-                        if (--maxcount < 0)
-                            break;
-                        u->str[i] = u2;
-                    }
+            if (i < 0)
+                goto nothing;
+            u = (PyUnicodeObject*) PyUnicode_FromUnicode(NULL, self->length);
+            if (!u)
+                return NULL;
+            Py_UNICODE_COPY(u->str, self->str, self->length);
+            while (i <= self->length - str1->length)
+                if (Py_UNICODE_MATCH(self, i, str1)) {
+                    if (--maxcount < 0)
+                        break;
+                    Py_UNICODE_COPY(u->str+i, str2->str, str2->length);
+                    i += str1->length;
+                } else
+                    i++;
         }
-        }
-
     } else {
+
         Py_ssize_t n, i;
         Py_UNICODE *p;
 
@@ -4701,51 +4868,47 @@
         n = count(self, 0, self->length, str1);
         if (n > maxcount)
             n = maxcount;
-        if (n == 0) {
-            /* nothing to replace, return original string */
-            if (PyUnicode_CheckExact(self)) {
-                Py_INCREF(self);
-                u = self;
-            }
-            else {
-                u = (PyUnicodeObject *)
-                    PyUnicode_FromUnicode(self->str, self->length);
-	    }
-        } else {
-            u = _PyUnicode_New(
-                self->length + n * (str2->length - str1->length));
-            if (u) {
-                i = 0;
-                p = u->str;
-                if (str1->length > 0) {
-                    while (i <= self->length - str1->length)
-                        if (Py_UNICODE_MATCH(self, i, str1)) {
-                            /* replace string segment */
-                            Py_UNICODE_COPY(p, str2->str, str2->length);
-                            p += str2->length;
-                            i += str1->length;
-                            if (--n <= 0) {
-                                /* copy remaining part */
-                                Py_UNICODE_COPY(p, self->str+i, self->length-i);
-                                break;
-                            }
-                        } else
-                            *p++ = self->str[i++];
-                } else {
-                    while (n > 0) {
-                        Py_UNICODE_COPY(p, str2->str, str2->length);
-                        p += str2->length;
-                        if (--n <= 0)
-                            break;
-                        *p++ = self->str[i++];
+        if (n == 0)
+            goto nothing;
+        u = _PyUnicode_New(self->length + n * (str2->length - str1->length));
+        if (!u)
+            return NULL;
+        i = 0;
+        p = u->str;
+        if (str1->length > 0) {
+            while (i <= self->length - str1->length)
+                if (Py_UNICODE_MATCH(self, i, str1)) {
+                    /* replace string segment */
+                    Py_UNICODE_COPY(p, str2->str, str2->length);
+                    p += str2->length;
+                    i += str1->length;
+                    if (--n <= 0) {
+                        /* copy remaining part */
+                        Py_UNICODE_COPY(p, self->str+i, self->length-i);
+                        break;
                     }
-                    Py_UNICODE_COPY(p, self->str+i, self->length-i);
-                }
+                } else
+                    *p++ = self->str[i++];
+        } else {
+            while (n > 0) {
+                Py_UNICODE_COPY(p, str2->str, str2->length);
+                p += str2->length;
+                if (--n <= 0)
+                    break;
+                *p++ = self->str[i++];
             }
+            Py_UNICODE_COPY(p, self->str+i, self->length-i);
         }
     }
-
     return (PyObject *) u;
+
+nothing:
+    /* nothing to replace; return original string (when possible) */
+    if (PyUnicode_CheckExact(self)) {
+        Py_INCREF(self);
+        return (PyObject *) self;
+    }
+    return PyUnicode_FromUnicode(self->str, self->length);
 }
 
 /* --- Unicode Object Methods --------------------------------------------- */
@@ -4982,54 +5145,67 @@
 int PyUnicode_Contains(PyObject *container,
 		       PyObject *element)
 {
-    PyUnicodeObject *u = NULL, *v = NULL;
+    PyUnicodeObject *u, *v;
     int result;
     Py_ssize_t size;
-    register const Py_UNICODE *lhs, *end, *rhs;
+#ifdef USE_FAST
+    Py_ssize_t pos;
+#endif
 
     /* Coerce the two arguments */
-    v = (PyUnicodeObject *)PyUnicode_FromObject(element);
-    if (v == NULL) {
+    v = (PyUnicodeObject *) PyUnicode_FromObject(element);
+    if (!v) {
 	PyErr_SetString(PyExc_TypeError,
 	    "'in <string>' requires string as left operand");
-	goto onError;
+        return -1;
+    }
+
+    u = (PyUnicodeObject *) PyUnicode_FromObject(container);
+    if (!u) {
+        Py_DECREF(v);
+        return -1;
     }
-    u = (PyUnicodeObject *)PyUnicode_FromObject(container);
-    if (u == NULL)
-	goto onError;
 
     size = PyUnicode_GET_SIZE(v);
-    rhs = PyUnicode_AS_UNICODE(v);
-    lhs = PyUnicode_AS_UNICODE(u);
+    if (!size) {
+        result = 1;
+        goto done;
+    }
 
+#ifdef USE_FAST
+    pos = fastsearch(
+        PyUnicode_AS_UNICODE(u), PyUnicode_GET_SIZE(u),
+        PyUnicode_AS_UNICODE(v), size, FAST_SEARCH
+        );
+    result = (pos != -1);
+#else    
     result = 0;
+
     if (size == 1) {
-	end = lhs + PyUnicode_GET_SIZE(u);
-	while (lhs < end) {
-	    if (*lhs++ == *rhs) {
-		result = 1;
-		break;
-	    }
-	}
-    }
-    else {
-	end = lhs + (PyUnicode_GET_SIZE(u) - size);
-	while (lhs <= end) {
-	    if (memcmp(lhs++, rhs, size * sizeof(Py_UNICODE)) == 0) {
+        Py_UNICODE chr = PyUnicode_AS_UNICODE(v)[0];
+        Py_UNICODE* ptr = PyUnicode_AS_UNICODE(u);
+	Py_UNICODE* end = ptr + PyUnicode_GET_SIZE(u);
+	for (; ptr < end; ptr++) {
+	    if (*ptr == chr) {
 		result = 1;
 		break;
 	    }
 	}
+    } else {
+        Py_ssize_t start = 0;
+        Py_ssize_t end = PyUnicode_GET_SIZE(u) - size;
+        for (; start <= end; start++)
+            if (Py_UNICODE_MATCH(u, start, v)) {
+                result = 1;
+                break;
+            }
     }
+#endif
 
+done:
     Py_DECREF(u);
     Py_DECREF(v);
     return result;
-
-onError:
-    Py_XDECREF(u);
-    Py_XDECREF(v);
-    return -1;
 }
 
 /* Concat to string or Unicode object giving a new Unicode object. */
@@ -5701,16 +5877,6 @@
 
 #define STRIPNAME(i) (stripformat[i]+3)
 
-static const Py_UNICODE *
-unicode_memchr(const Py_UNICODE *s, Py_UNICODE c, size_t n)
-{
-	size_t i;
-	for (i = 0; i < n; ++i)
-		if (s[i] == c)
-			return s+i;
-	return NULL;
-}
-
 /* externally visible for str.strip(unicode) */
 PyObject *
 _PyUnicode_XStrip(PyUnicodeObject *self, int striptype, PyObject *sepobj)
@@ -5721,27 +5887,29 @@
 	Py_ssize_t seplen = PyUnicode_GET_SIZE(sepobj);
 	Py_ssize_t i, j;
 
+        BLOOM_MASK sepmask = make_bloom_mask(sep, seplen);
+
 	i = 0;
 	if (striptype != RIGHTSTRIP) {
-		while (i < len && unicode_memchr(sep, s[i], seplen)) {
-			i++;
-		}
+            while (i < len && BLOOM_MEMBER(sepmask, s[i], sep, seplen)) {
+                i++;
+            }
 	}
 
 	j = len;
 	if (striptype != LEFTSTRIP) {
-		do {
-			j--;
-		} while (j >= i && unicode_memchr(sep, s[j], seplen));
-		j++;
+            do {
+                j--;
+            } while (j >= i && BLOOM_MEMBER(sepmask, s[j], sep, seplen));
+            j++;
 	}
 
 	if (i == 0 && j == len && PyUnicode_CheckExact(self)) {
-		Py_INCREF(self);
-		return (PyObject*)self;
+            Py_INCREF(self);
+            return (PyObject*)self;
 	}
 	else
-		return PyUnicode_FromUnicode(s+i, j-i);
+            return PyUnicode_FromUnicode(s+i, j-i);
 }
 
 
@@ -7385,6 +7553,18 @@
 {
     int i;
 
+    /* XXX - move this array to unicodectype.c ? */
+    Py_UNICODE linebreak[] = {
+        0x000A, /* LINE FEED */
+        0x000D, /* CARRIAGE RETURN */
+        0x001C, /* FILE SEPARATOR */
+        0x001D, /* GROUP SEPARATOR */
+        0x001E, /* RECORD SEPARATOR */
+        0x0085, /* NEXT LINE */
+        0x2028, /* LINE SEPARATOR */
+        0x2029, /* PARAGRAPH SEPARATOR */
+    };
+
     /* Init the implementation */
     unicode_freelist = NULL;
     unicode_freelist_size = 0;
@@ -7394,6 +7574,11 @@
 	unicode_latin1[i] = NULL;
     if (PyType_Ready(&PyUnicode_Type) < 0)
 	Py_FatalError("Can't initialize 'unicode'");
+
+    /* initialize the linebreak bloom filter */
+    bloom_linebreak = make_bloom_mask(
+        linebreak, sizeof(linebreak) / sizeof(linebreak[0])
+        );
 }
 
 /* Finalize the Unicode implementation */

Modified: python/branches/blais-bytebuf/PC/config.c
==============================================================================
--- python/branches/blais-bytebuf/PC/config.c	(original)
+++ python/branches/blais-bytebuf/PC/config.c	Wed May 24 20:30:42 2006
@@ -28,7 +28,6 @@
 extern void init_sha256(void);
 extern void init_sha512(void);
 extern void initstrop(void);
-extern void initstruct(void);
 extern void inittime(void);
 extern void initthread(void);
 extern void initcStringIO(void);
@@ -53,6 +52,7 @@
 extern void init_sre(void);
 extern void initparser(void);
 extern void init_winreg(void);
+extern void init_struct(void);
 extern void initdatetime(void);
 extern void initfunctional(void);
 extern void initzlib(void);
@@ -102,7 +102,6 @@
         {"_sha256", init_sha256},
         {"_sha512", init_sha512},
         {"strop", initstrop},
-        {"struct", initstruct},
         {"time", inittime},
 #ifdef WITH_THREAD
         {"thread", initthread},
@@ -131,6 +130,7 @@
 	{"_sre", init_sre},
 	{"parser", initparser},
 	{"_winreg", init_winreg},
+	{"_struct", init_struct},
 	{"datetime", initdatetime},
 	{"functional", initfunctional},
 

Modified: python/branches/blais-bytebuf/PCbuild/pythoncore.vcproj
==============================================================================
--- python/branches/blais-bytebuf/PCbuild/pythoncore.vcproj	(original)
+++ python/branches/blais-bytebuf/PCbuild/pythoncore.vcproj	Wed May 24 20:30:42 2006
@@ -344,6 +344,9 @@
 			RelativePath="..\Modules\_bisectmodule.c">
 		</File>
 		<File
+			RelativePath="..\Modules\_struct.c">
+		</File>
+		<File
 			RelativePath="..\Modules\cjkcodecs\_codecs_cn.c">
 		</File>
 		<File
@@ -746,9 +749,6 @@
 			RelativePath="..\Python\structmember.c">
 		</File>
 		<File
-			RelativePath="..\Modules\structmodule.c">
-		</File>
-		<File
 			RelativePath="..\Objects\structseq.c">
 		</File>
 		<File

Modified: python/branches/blais-bytebuf/Python/ceval.c
==============================================================================
--- python/branches/blais-bytebuf/Python/ceval.c	(original)
+++ python/branches/blais-bytebuf/Python/ceval.c	Wed May 24 20:30:42 2006
@@ -654,11 +654,11 @@
 #ifdef LLTRACE
 #define PUSH(v)		{ (void)(BASIC_PUSH(v), \
                                lltrace && prtrace(TOP(), "push")); \
-                               assert(STACK_LEVEL() <= f->f_stacksize); }
+                               assert(STACK_LEVEL() <= co->co_stacksize); }
 #define POP()		((void)(lltrace && prtrace(TOP(), "pop")), BASIC_POP())
 #define STACKADJ(n)	{ (void)(BASIC_STACKADJ(n), \
                                lltrace && prtrace(TOP(), "stackadj")); \
-                               assert(STACK_LEVEL() <= f->f_stacksize); }
+                               assert(STACK_LEVEL() <= co->co_stacksize); }
 #define EXT_POP(STACK_POINTER) (lltrace && prtrace(*(STACK_POINTER), "ext_pop"), *--(STACK_POINTER))
 #else
 #define PUSH(v)		BASIC_PUSH(v)
@@ -729,7 +729,7 @@
 	names = co->co_names;
 	consts = co->co_consts;
 	fastlocals = f->f_localsplus;
-	freevars = f->f_localsplus + f->f_nlocals;
+	freevars = f->f_localsplus + co->co_nlocals;
 	first_instr = (unsigned char*) PyString_AS_STRING(co->co_code);
 	/* An explanation is in order for the next line.
 
@@ -780,7 +780,7 @@
 		READ_TIMESTAMP(loop0);
 #endif
 		assert(stack_pointer >= f->f_valuestack); /* else underflow */
-		assert(STACK_LEVEL() <= f->f_stacksize);  /* else overflow */
+		assert(STACK_LEVEL() <= co->co_stacksize);  /* else overflow */
 
 		/* Do periodic things.  Doing this every time through
 		   the loop would add too much overhead, so we do it
@@ -1916,17 +1916,17 @@
 			/* Don't stomp existing exception */
 			if (PyErr_Occurred())
 				break;
-			if (oparg < f->f_ncells) {
-				v = PyTuple_GetItem(co->co_cellvars,
+			if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) {
+				v = PyTuple_GET_ITEM(co->co_cellvars,
 						       oparg);
 			       format_exc_check_arg(
 				       PyExc_UnboundLocalError,
 				       UNBOUNDLOCAL_ERROR_MSG,
 				       v);
 			} else {
-			       v = PyTuple_GetItem(
+			       v = PyTuple_GET_ITEM(
 					      co->co_freevars,
-					      oparg - f->f_ncells);
+					      oparg - PyTuple_GET_SIZE(co->co_cellvars));
 			       format_exc_check_arg(
 				       PyExc_NameError,
 				       UNBOUNDFREE_ERROR_MSG,
@@ -2610,7 +2610,7 @@
 		return NULL;
 
 	fastlocals = f->f_localsplus;
-	freevars = f->f_localsplus + f->f_nlocals;
+	freevars = f->f_localsplus + co->co_nlocals;
 
 	if (co->co_argcount > 0 ||
 	    co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) {
@@ -2746,7 +2746,7 @@
 	}
 	/* Allocate and initialize storage for cell vars, and copy free
 	   vars into frame.  This isn't too efficient right now. */
-	if (f->f_ncells) {
+	if (PyTuple_GET_SIZE(co->co_cellvars)) {
 		int i = 0, j = 0, nargs, found;
 		char *cellname, *argname;
 		PyObject *c;
@@ -2764,7 +2764,7 @@
 		   that are arguments at the beginning of the cellvars
 		   list so that we can march over it more efficiently?
 		*/
-		for (i = 0; i < f->f_ncells; ++i) {
+		for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) {
 			cellname = PyString_AS_STRING(
 				PyTuple_GET_ITEM(co->co_cellvars, i));
 			found = 0;
@@ -2775,7 +2775,7 @@
 					c = PyCell_New(GETLOCAL(j));
 					if (c == NULL)
 						goto fail;
-					GETLOCAL(f->f_nlocals + i) = c;
+					GETLOCAL(co->co_nlocals + i) = c;
 					found = 1;
 					break;
 				}
@@ -2784,16 +2784,16 @@
 				c = PyCell_New(NULL);
 				if (c == NULL)
 					goto fail;
-				SETLOCAL(f->f_nlocals + i, c);
+				SETLOCAL(co->co_nlocals + i, c);
 			}
 		}
 	}
-	if (f->f_nfreevars) {
+	if (PyTuple_GET_SIZE(co->co_freevars)) {
 		int i;
-		for (i = 0; i < f->f_nfreevars; ++i) {
+		for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
 			PyObject *o = PyTuple_GET_ITEM(closure, i);
 			Py_INCREF(o);
-			freevars[f->f_ncells + i] = o;
+			freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
 		}
 	}
 
@@ -4214,7 +4214,7 @@
 		}
 		case STORE_DEREF:
 		{
-			PyObject **freevars = f->f_localsplus + f->f_nlocals;
+			PyObject **freevars = f->f_localsplus + f->f_code->co_nlocals;
 			PyObject *c = freevars[PEEKARG()];
 			if (PyCell_GET(c) == v)
 				PyCell_Set(c, NULL);

Modified: python/branches/blais-bytebuf/Python/errors.c
==============================================================================
--- python/branches/blais-bytebuf/Python/errors.c	(original)
+++ python/branches/blais-bytebuf/Python/errors.c	Wed May 24 20:30:42 2006
@@ -527,6 +527,7 @@
 }
 
 
+
 PyObject *
 PyErr_NewException(char *name, PyObject *base, PyObject *dict)
 {
@@ -559,9 +560,15 @@
 	classname = PyString_FromString(dot+1);
 	if (classname == NULL)
 		goto failure;
-	bases = PyTuple_Pack(1, base);
-	if (bases == NULL)
-		goto failure;
+	if (PyTuple_Check(base)) {
+		bases = base;
+		/* INCREF as we create a new ref in the else branch */
+		Py_INCREF(bases);
+	} else {
+		bases = PyTuple_Pack(1, base);
+		if (bases == NULL)
+			goto failure;
+	}
 	result = PyClass_New(bases, dict, classname);
   failure:
 	Py_XDECREF(bases);

Modified: python/branches/blais-bytebuf/Python/mystrtoul.c
==============================================================================
--- python/branches/blais-bytebuf/Python/mystrtoul.c	(original)
+++ python/branches/blais-bytebuf/Python/mystrtoul.c	Wed May 24 20:30:42 2006
@@ -15,6 +15,94 @@
 
 /* strtol and strtoul, renamed to avoid conflicts */
 
+
+#include <ctype.h>
+#ifndef DONT_HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+/* Static overflow check values for bases 2 through 36.
+ * smallmax[base] is the largest unsigned long i such that
+ * i * base doesn't overflow unsigned long.
+ */
+static unsigned long smallmax[] = {
+	0, /* bases 0 and 1 are invalid */
+	0,
+	ULONG_MAX / 2,
+	ULONG_MAX / 3,
+	ULONG_MAX / 4,
+	ULONG_MAX / 5,
+	ULONG_MAX / 6,
+	ULONG_MAX / 7,
+	ULONG_MAX / 8,
+	ULONG_MAX / 9,
+	ULONG_MAX / 10,
+	ULONG_MAX / 11,
+	ULONG_MAX / 12,
+	ULONG_MAX / 13,
+	ULONG_MAX / 14,
+	ULONG_MAX / 15,
+	ULONG_MAX / 16,
+	ULONG_MAX / 17,
+	ULONG_MAX / 18,
+	ULONG_MAX / 19,
+	ULONG_MAX / 20,
+	ULONG_MAX / 21,
+	ULONG_MAX / 22,
+	ULONG_MAX / 23,
+	ULONG_MAX / 24,
+	ULONG_MAX / 25,
+	ULONG_MAX / 26,
+	ULONG_MAX / 27,
+	ULONG_MAX / 28,
+	ULONG_MAX / 29,
+	ULONG_MAX / 30,
+	ULONG_MAX / 31,
+	ULONG_MAX / 32,
+	ULONG_MAX / 33,
+	ULONG_MAX / 34,
+	ULONG_MAX / 35,
+	ULONG_MAX / 36,
+};
+
+/* maximum digits that can't ever overflow for bases 2 through 36,
+ * calculated by [int(math.floor(math.log(2**32, i))) for i in range(2, 37)].
+ * Note that this is pessimistic if sizeof(long) > 4.
+ */
+static int digitlimit[] = {
+	0,  0, 32, 20, 16, 13, 12, 11, 10, 10,  /*  0 -  9 */
+	9,  9,  8,  8,  8,  8,  8,  7,  7,  7,  /* 10 - 19 */
+	7,  7,  7,  7,  6,  6,  6,  6,  6,  6,  /* 20 - 29 */
+	6,  6,  6,  6,  6,  6,  6};             /* 30 - 36 */
+
+/* char-to-digit conversion for bases 2-36; all non-digits are 37 */
+static int digitlookup[] = {
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  37, 37, 37, 37, 37, 37,
+	37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+	25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37,
+	37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+	25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37
+};
+
 /*
 **	strtoul
 **		This is a general purpose routine for converting
@@ -28,98 +116,100 @@
 **		Errors due to bad pointers will probably result in
 **		exceptions - we don't check for them.
 */
-
-#include <ctype.h>
-#ifndef DONT_HAVE_ERRNO_H
-#include <errno.h>
-#endif
-
 unsigned long
 PyOS_strtoul(register char *str, char **ptr, int base)
 {
-    register unsigned long	result;	/* return value of the function */
-    register int		c;	/* current input character */
-    register unsigned long	temp;	/* used in overflow testing */
-    int				ovf;	/* true if overflow occurred */
-
-    result = 0;
-    ovf = 0;
-
-/* catch silly bases */
-    if (base != 0 && (base < 2 || base > 36))
-    {
-	if (ptr)
-	    *ptr = str;
-	return 0;
-    }
-
-/* skip leading white space */
-    while (*str && isspace(Py_CHARMASK(*str)))
-	str++;
-
-/* check for leading 0 or 0x for auto-base or base 16 */
-    switch (base)
-    {
-    case 0:		/* look for leading 0, 0x or 0X */
-	if (*str == '0')
-	{
-	    str++;
-	    if (*str == 'x' || *str == 'X')
-	    {
-		str++;
-		base = 16;
-	    }
-	    else
-		base = 8;
-	}
-	else
-	    base = 10;
-	break;
-
-    case 16:	/* skip leading 0x or 0X */
-	if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
-	    str += 2;
-	break;
-    }
-
-/* do the conversion */
-    while ((c = Py_CHARMASK(*str)) != '\0')
-    {
-	if (isdigit(c) && c - '0' < base)
-	    c -= '0';
-	else
-	{
-	    if (isupper(c))
-		c = tolower(c);
-	    if (c >= 'a' && c <= 'z')
-		c -= 'a' - 10;
-	    else	/* non-"digit" character */
-		break;
-	    if (c >= base)	/* non-"digit" character */
-		break;
+	register unsigned long result = 0; /* return value of the function */
+	register int c;	 	/* current input character */
+	register int ovlimit; 	/* required digits to overflow */
+
+	/* skip leading white space */
+	while (*str && isspace(Py_CHARMASK(*str)))
+		++str;
+
+	/* check for leading 0 or 0x for auto-base or base 16 */
+	switch (base) {
+		case 0:		/* look for leading 0, 0x or 0X */
+			if (*str == '0') {
+				++str;
+				if (*str == 'x' || *str == 'X') {
+					++str;
+					base = 16;
+				}
+				else
+					base = 8;
+			}
+			else
+				base = 10;
+			break;
+
+		case 16:	/* skip leading 0x or 0X */
+			if (*str == '0') {
+				++str;
+				if (*str == 'x' || *str == 'X')
+					++str;
+			}
+			break;
 	}
-	temp = result;
-	result = result * base + c;
-	if(base == 10) {
-		if(((long)(result - c) / base != (long)temp))	/* overflow */
-			ovf = 1;
+
+	/* catch silly bases */
+	if (base < 2 || base > 36) {
+		if (ptr)
+			*ptr = str;
+		return 0;
 	}
-	else {
-		if ((result - c) / base != temp)	/* overflow */
-			ovf = 1;
+
+	/* skip leading zeroes */
+	while (*str == '0')
+		++str;
+
+	/* base is guaranteed to be in [2, 36] at this point */
+	ovlimit = digitlimit[base];
+
+	/* do the conversion until non-digit character encountered */
+	while ((c = digitlookup[Py_CHARMASK(*str)]) < base) {
+		if (ovlimit > 0) /* no overflow check required */
+			result = result * base + c;
+		else { /* requires overflow check */
+			register unsigned long temp_result;
+
+			if (ovlimit < 0) /* guaranteed overflow */
+				goto overflowed;
+
+			/* there could be an overflow */
+			/* check overflow just from shifting */
+			if (result > smallmax[base])
+				goto overflowed;
+
+			result *= base;
+
+			/* check overflow from the digit's value */
+			temp_result = result + c;
+			if (temp_result < result)
+				goto overflowed;
+
+			result = temp_result;
+		}
+
+		++str;
+		--ovlimit;
 	}
-	str++;
-    }
 
-/* set pointer to point to the last character scanned */
-    if (ptr)
-	*ptr = str;
-    if (ovf)
-    {
-	result = (unsigned long) ~0L;
+	/* set pointer to point to the last character scanned */
+	if (ptr)
+		*ptr = str;
+
+	return result;
+
+overflowed:
+	if (ptr) {
+		/* spool through remaining digit characters */
+		while (digitlookup[Py_CHARMASK(*str)] < base)
+			++str;
+		*ptr = str;
+	}
 	errno = ERANGE;
-    }
-    return result;
+	return (unsigned long)-1;
 }
 
 long
@@ -127,25 +217,25 @@
 {
 	long result;
 	char sign;
-	
+
 	while (*str && isspace(Py_CHARMASK(*str)))
 		str++;
-	
+
 	sign = *str;
 	if (sign == '+' || sign == '-')
 		str++;
-	
+
 	result = (long) PyOS_strtoul(str, ptr, base);
-	
+
 	/* Signal overflow if the result appears negative,
 	   except for the largest negative integer */
 	if (result < 0 && !(sign == '-' && result == -result)) {
 		errno = ERANGE;
 		result = 0x7fffffff;
 	}
-	
+
 	if (sign == '-')
 		result = -result;
-	
+
 	return result;
 }

Modified: python/branches/blais-bytebuf/setup.py
==============================================================================
--- python/branches/blais-bytebuf/setup.py	(original)
+++ python/branches/blais-bytebuf/setup.py	Wed May 24 20:30:42 2006
@@ -1448,7 +1448,7 @@
                       'install_lib':PyBuildInstallLib},
           # The struct module is defined here, because build_ext won't be
           # called unless there's at least one extension module defined.
-          ext_modules=[Extension('struct', ['structmodule.c'])],
+          ext_modules=[Extension('_struct', ['_struct.c'])],
 
           # Scripts to install
           scripts = ['Tools/scripts/pydoc', 'Tools/scripts/idle',


More information about the Python-checkins mailing list