mirror of
https://github.com/python/cpython.git
synced 2025-09-27 18:59:43 +00:00
Linear-time implementations of {encode,decode}_long.
This commit is contained in:
parent
1a17704ff1
commit
91149821d3
1 changed files with 50 additions and 19 deletions
|
@ -1285,10 +1285,12 @@ class Unpickler:
|
||||||
class _EmptyClass:
|
class _EmptyClass:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Encode/decode longs.
|
# Encode/decode longs in linear time.
|
||||||
|
|
||||||
|
import binascii as _binascii
|
||||||
|
|
||||||
def encode_long(x):
|
def encode_long(x):
|
||||||
r"""Encode a long to a two's complement little-ending binary string.
|
r"""Encode a long to a two's complement little-endian binary string.
|
||||||
>>> encode_long(255L)
|
>>> encode_long(255L)
|
||||||
'\xff\x00'
|
'\xff\x00'
|
||||||
>>> encode_long(32767L)
|
>>> encode_long(32767L)
|
||||||
|
@ -1303,14 +1305,46 @@ def encode_long(x):
|
||||||
'\x7f'
|
'\x7f'
|
||||||
>>>
|
>>>
|
||||||
"""
|
"""
|
||||||
# XXX This is still a quadratic algorithm.
|
|
||||||
# Should use hex() to get started.
|
if x == 0:
|
||||||
digits = []
|
return '\x00'
|
||||||
while not -128 <= x < 128:
|
if x > 0:
|
||||||
digits.append(x & 0xff)
|
ashex = hex(x)
|
||||||
x >>= 8
|
assert ashex.startswith("0x")
|
||||||
digits.append(x & 0xff)
|
njunkchars = 2 + ashex.endswith('L')
|
||||||
return "".join(map(chr, digits))
|
nibbles = len(ashex) - njunkchars
|
||||||
|
if nibbles & 1:
|
||||||
|
# need an even # of nibbles for unhexlify
|
||||||
|
ashex = "0x0" + ashex[2:]
|
||||||
|
elif ashex[2] >= '8':
|
||||||
|
# "looks negative", so need a byte of sign bits
|
||||||
|
ashex = "0x00" + ashex[2:]
|
||||||
|
else:
|
||||||
|
# Build the 256's-complement: (1L << nbytes) + x. The trick is
|
||||||
|
# to find the number of bytes in linear time (although that should
|
||||||
|
# really be a constant-time task).
|
||||||
|
ashex = hex(-x)
|
||||||
|
assert ashex.startswith("0x")
|
||||||
|
njunkchars = 2 + ashex.endswith('L')
|
||||||
|
nibbles = len(ashex) - njunkchars
|
||||||
|
if nibbles & 1:
|
||||||
|
# need an even # of nibbles for unhexlify
|
||||||
|
nibbles += 1
|
||||||
|
nbytes = nibbles >> 1
|
||||||
|
x += 1L << (nbytes * 8)
|
||||||
|
assert x > 0
|
||||||
|
ashex = hex(x)
|
||||||
|
if x >> (nbytes * 8 - 1) == 0:
|
||||||
|
# "looks positive", so need a byte of sign bits
|
||||||
|
ashex = "0xff" + x[2:]
|
||||||
|
|
||||||
|
if ashex.endswith('L'):
|
||||||
|
ashex = ashex[2:-1]
|
||||||
|
else:
|
||||||
|
ashex = ashex[2:]
|
||||||
|
assert len(ashex) & 1 == 0
|
||||||
|
binary = _binascii.unhexlify(ashex)
|
||||||
|
return binary[::-1]
|
||||||
|
|
||||||
def decode_long(data):
|
def decode_long(data):
|
||||||
r"""Decode a long from a two's complement little-endian binary string.
|
r"""Decode a long from a two's complement little-endian binary string.
|
||||||
|
@ -1327,15 +1361,12 @@ def decode_long(data):
|
||||||
>>> decode_long("\x7f")
|
>>> decode_long("\x7f")
|
||||||
127L
|
127L
|
||||||
"""
|
"""
|
||||||
# XXX This is quadratic too.
|
|
||||||
x = 0L
|
ashex = _binascii.hexlify(data[::-1])
|
||||||
i = 0L
|
n = long(ashex, 16)
|
||||||
for c in data:
|
if data[-1] >= '\x80':
|
||||||
x |= long(ord(c)) << i
|
n -= 1L << (len(data) * 8)
|
||||||
i += 8L
|
return n
|
||||||
if data and ord(c) >= 0x80:
|
|
||||||
x -= 1L << i
|
|
||||||
return x
|
|
||||||
|
|
||||||
# Shorthands
|
# Shorthands
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue