summaryrefslogtreecommitdiff
path: root/Lib
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2003-01-31 16:43:39 +0000
committerTim Peters <tim.peters@gmail.com>2003-01-31 16:43:39 +0000
commit4b23f2b44bdd13758eab6808d6a08b951fbfc4dd (patch)
treeee634c414cbf8b678189feb2031e4e6b8e8030ea /Lib
parent757246c1894b49bd79b3b6ec86782662e6872601 (diff)
downloadcpython-git-4b23f2b44bdd13758eab6808d6a08b951fbfc4dd.tar.gz
It's Official: for LONG1/LONG4, a "byte count" of 0 is taken as a
shortcut meaning 0L. This allows LONG1 to encode 0L in two bytes total.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/pickle.py23
-rw-r--r--Lib/pickletools.py11
2 files changed, 25 insertions, 9 deletions
diff --git a/Lib/pickle.py b/Lib/pickle.py
index 399e4ab99d..5106ec9932 100644
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -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
diff --git a/Lib/pickletools.py b/Lib/pickletools.py
index 74ba8d964f..f9ef8df95e 100644
--- a/Lib/pickletools.py
+++ b/Lib/pickletools.py
@@ -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).
""")