]> granicus.if.org Git - python/commitdiff
It's Official: for LONG1/LONG4, a "byte count" of 0 is taken as a
authorTim Peters <tim.peters@gmail.com>
Fri, 31 Jan 2003 16:43:39 +0000 (16:43 +0000)
committerTim Peters <tim.peters@gmail.com>
Fri, 31 Jan 2003 16:43:39 +0000 (16:43 +0000)
shortcut meaning 0L.  This allows LONG1 to encode 0L in two bytes
total.

Lib/pickle.py
Lib/pickletools.py

index 399e4ab99d0fbe2f60c2ec4017bed03d624b6da8..5106ec99328732cf484a5a3d630a040bc77545c6 100644 (file)
@@ -1291,6 +1291,11 @@ import binascii as _binascii
 
 def encode_long(x):
     r"""Encode a long to a two's complement little-endian binary string.
+    Note that 0L is a special case, returning an empty string, to save a
+    byte in the LONG1 pickling context.
+
+    >>> encode_long(0L)
+    ''
     >>> encode_long(255L)
     '\xff\x00'
     >>> encode_long(32767L)
@@ -1307,7 +1312,7 @@ def encode_long(x):
     """
 
     if x == 0:
-        return '\x00'
+        return ''
     if x > 0:
         ashex = hex(x)
         assert ashex.startswith("0x")
@@ -1316,7 +1321,7 @@ def encode_long(x):
         if nibbles & 1:
             # need an even # of nibbles for unhexlify
             ashex = "0x0" + ashex[2:]
-        elif ashex[2] >= '8':
+        elif int(ashex[2], 16) >= 8:
             # "looks negative", so need a byte of sign bits
             ashex = "0x00" + ashex[2:]
     else:
@@ -1330,11 +1335,11 @@ def encode_long(x):
         if nibbles & 1:
             # need an even # of nibbles for unhexlify
             nibbles += 1
-        nbytes = nibbles >> 1
-        x += 1L << (nbytes * 8)
+        nbits = nibbles * 4
+        x += 1L << nbits
         assert x > 0
         ashex = hex(x)
-        if x >> (nbytes * 8 - 1) == 0:
+        if x >> (nbits - 1) == 0:
             # "looks positive", so need a byte of sign bits
             ashex = "0xff" + x[2:]
 
@@ -1348,6 +1353,9 @@ def encode_long(x):
 
 def decode_long(data):
     r"""Decode a long from a two's complement little-endian binary string.
+
+    >>> decode_long('')
+    0L
     >>> decode_long("\xff\x00")
     255L
     >>> decode_long("\xff\x7f")
@@ -1362,10 +1370,13 @@ def decode_long(data):
     127L
     """
 
+    nbytes = len(data)
+    if nbytes == 0:
+        return 0L
     ashex = _binascii.hexlify(data[::-1])
     n = long(ashex, 16)
     if data[-1] >= '\x80':
-        n -= 1L << (len(data) * 8)
+        n -= 1L << (nbytes * 8)
     return n
 
 # Shorthands
index 74ba8d964f923b91c34687ff20576e489eb584dd..f9ef8df95e39577b85d0f6e8b9503ef6934db4a1 100644 (file)
@@ -620,6 +620,8 @@ from pickle import decode_long
 def read_long1(f):
     r"""
     >>> import StringIO
+    >>> read_long1(StringIO.StringIO("\x00"))
+    0L
     >>> read_long1(StringIO.StringIO("\x02\xff\x00"))
     255L
     >>> read_long1(StringIO.StringIO("\x02\xff\x7f"))
@@ -628,7 +630,6 @@ def read_long1(f):
     -256L
     >>> read_long1(StringIO.StringIO("\x02\x00\x80"))
     -32768L
-    >>>
     """
 
     n = read_uint1(f)
@@ -645,6 +646,7 @@ long1 = ArgumentDescriptor(
 
     This first reads one byte as an unsigned size, then reads that
     many bytes and interprets them as a little-endian 2's-complement long.
+    If the size is 0, that's taken as a shortcut for the long 0L.
     """)
 
 def read_long4(f):
@@ -658,7 +660,8 @@ def read_long4(f):
     -256L
     >>> read_long4(StringIO.StringIO("\x02\x00\x00\x00\x00\x80"))
     -32768L
-    >>>
+    >>> read_long1(StringIO.StringIO("\x00\x00\x00\x00"))
+    0L
     """
 
     n = read_int4(f)
@@ -677,7 +680,9 @@ long4 = ArgumentDescriptor(
 
     This first reads four bytes as a signed size (but requires the
     size to be >= 0), then reads that many bytes and interprets them
-    as a little-endian 2's-complement long.
+    as a little-endian 2's-complement long.  If the size is 0, that's taken
+    as a shortcut for the long 0L, although LONG1 should really be used
+    then instead (and in any case where # of bytes < 256).
     """)