Skip to content

Commit 95c1c48

Browse files
committed
Speed up base64.urlsafe_{en,de}code().
1 parent 9436361 commit 95c1c48

2 files changed

Lines changed: 13 additions & 13 deletions

File tree

Lib/base64.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,6 @@ def _bytes_from_decode_data(s):
4040
else:
4141
raise TypeError("argument should be bytes or ASCII string, not %s" % s.__class__.__name__)
4242

43-
def _translate(s, altchars):
44-
if not isinstance(s, bytes_types):
45-
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
46-
translation = bytearray(range(256))
47-
for k, v in altchars.items():
48-
translation[ord(k)] = v[0]
49-
return s.translate(translation)
50-
5143

5244

5345
# Base64 encoding/decoding uses binascii
@@ -71,7 +63,7 @@ def b64encode(s, altchars=None):
7163
raise TypeError("expected bytes, not %s"
7264
% altchars.__class__.__name__)
7365
assert len(altchars) == 2, repr(altchars)
74-
return _translate(encoded, {'+': altchars[0:1], '/': altchars[1:2]})
66+
return encoded.translate(bytes.maketrans(b'+/', altchars))
7567
return encoded
7668

7769

@@ -93,7 +85,7 @@ def b64decode(s, altchars=None, validate=False):
9385
if altchars is not None:
9486
altchars = _bytes_from_decode_data(altchars)
9587
assert len(altchars) == 2, repr(altchars)
96-
s = _translate(s, {chr(altchars[0]): b'+', chr(altchars[1]): b'/'})
88+
s = s.translate(bytes.maketrans(altchars, b'+/'))
9789
if validate and not re.match(b'^[A-Za-z0-9+/]*={0,2}$', s):
9890
raise binascii.Error('Non-base64 digit found')
9991
return binascii.a2b_base64(s)
@@ -116,14 +108,18 @@ def standard_b64decode(s):
116108
"""
117109
return b64decode(s)
118110

111+
112+
_urlsafe_encode_translation = bytes.maketrans(b'+/', b'-_')
113+
_urlsafe_decode_translation = bytes.maketrans(b'-_', b'+/')
114+
119115
def urlsafe_b64encode(s):
120116
"""Encode a byte string using a url-safe Base64 alphabet.
121117
122118
s is the byte string to encode. The encoded byte string is
123119
returned. The alphabet uses '-' instead of '+' and '_' instead of
124120
'/'.
125121
"""
126-
return b64encode(s, b'-_')
122+
return b64encode(s).translate(_urlsafe_encode_translation)
127123

128124
def urlsafe_b64decode(s):
129125
"""Decode a byte string encoded with the standard Base64 alphabet.
@@ -135,7 +131,9 @@ def urlsafe_b64decode(s):
135131
136132
The alphabet uses '-' instead of '+' and '_' instead of '/'.
137133
"""
138-
return b64decode(s, b'-_')
134+
s = _bytes_from_decode_data(s)
135+
s = s.translate(_urlsafe_decode_translation)
136+
return b64decode(s)
139137

140138

141139

@@ -228,7 +226,7 @@ def b32decode(s, casefold=False, map01=None):
228226
if map01 is not None:
229227
map01 = _bytes_from_decode_data(map01)
230228
assert len(map01) == 1, repr(map01)
231-
s = _translate(s, {b'0': b'O', b'1': map01})
229+
s = s.translate(bytes.maketrans(b'01', b'O' + map01))
232230
if casefold:
233231
s = s.upper()
234232
# Strip off pad characters from the right. We need to count the pad

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ Core and Builtins
4040
Library
4141
-------
4242

43+
- Issue: #15138: base64.urlsafe_{en,de}code() are now 3-4x faster.
44+
4345
- Issue #9527: datetime.astimezone() method will now supply a class
4446
timezone instance corresponding to the system local timezone when
4547
called with no arguments.

0 commit comments

Comments
 (0)