# base85.py: pure python base85 codec
#
# Copyright (C) 2008 Brendan Cully <brendan@kublai.com>
#
# This software may be used and distributed according to the terms of
# the GNU General Public License, incorporated herein by reference.
import struct
_b85chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"
_b85dec = {}
def _mkb85dec():
for i in range(len(_b85chars)):
_b85dec[_b85chars[i]] = i
def b85encode(text, pad=False):
"""encode text in base85 format"""
l = len(text)
r = l % 4
if r:
text += '\0' * (4 - r)
longs = len(text) >> 2
out = []
words = struct.unpack('>' + 'L' * longs, text[0:longs*4])
for word in words:
rems = [0, 0, 0, 0, 0]
for i in range(4, -1, -1):
rems[i] = _b85chars[word % 85]
word /= 85
out.extend(rems)
out = ''.join(out)
if pad:
return out
# Trim padding
olen = l % 4
if olen:
olen += 1
olen += l / 4 * 5
return out[0:olen]
def b85decode(text):
"""decode base85-encoded text"""
if not _b85dec:
_mkb85dec()
l = len(text)
out = []
for i in range(0, len(text), 5):
chunk = text[i:i+5]
acc = 0
for j in range(len(chunk)):
try:
acc = acc * 85 + _b85dec[chunk[j]]
except KeyError:
raise TypeError('Bad base85 character at byte %d' % (i + j))
if acc > 4294967295:
raise OverflowError('Base85 overflow in hunk starting at byte %d' % i)
out.append(acc)
# Pad final chunk if necessary
cl = l % 5
if cl:
acc *= 85 ** (5 - cl)
if cl > 1:
acc += 0xffffff >> (cl - 2) * 8
out[-1] = acc
out = struct.pack('>' + 'L' * ((l + 4) / 5), *out)
if cl:
out = out[:-(5 - cl)]
return out
def perf85(ui, repo, f):
text = open(f).read()
import mercurial.base85
def d():
mercurial.base85.b85decode(mercurial.base85.b85encode(text))
timer(d)
# native code
% hg perf85 mercurial/commands.py
! wall 0.001472 comb 0.000000 user 0.000000 sys 0.000000 (best of 2020)
# python version
% hg perf85 mercurial/commands.py ~/dev/hg/crew
! wall 0.232690 comb 0.240000 user 0.230000 sys 0.010000 (best of 43)