var dbuf [4]byte
dlen := 4
+ // Lift the nil check outside of the loop.
+ _ = enc.decodeMap
+
for j := 0; j < len(dbuf); j++ {
if len(src) == si {
switch {
return 0, nil
}
+ // Lift the nil check outside of the loop. enc.decodeMap is directly
+ // used later in this function, to let the compiler know that the
+ // receiver can't be nil.
+ _ = enc.decodeMap
+
si := 0
for strconv.IntSize >= 64 && len(src)-si >= 8 && len(dst)-n >= 8 {
- if dn, ok := enc.decode64(src[si:]); ok {
+ if dn, ok := assemble64(
+ enc.decodeMap[src[si+0]],
+ enc.decodeMap[src[si+1]],
+ enc.decodeMap[src[si+2]],
+ enc.decodeMap[src[si+3]],
+ enc.decodeMap[src[si+4]],
+ enc.decodeMap[src[si+5]],
+ enc.decodeMap[src[si+6]],
+ enc.decodeMap[src[si+7]],
+ ); ok {
binary.BigEndian.PutUint64(dst[n:], dn)
n += 6
si += 8
}
for len(src)-si >= 4 && len(dst)-n >= 4 {
- if dn, ok := enc.decode32(src[si:]); ok {
+ if dn, ok := assemble32(
+ enc.decodeMap[src[si+0]],
+ enc.decodeMap[src[si+1]],
+ enc.decodeMap[src[si+2]],
+ enc.decodeMap[src[si+3]],
+ ); ok {
binary.BigEndian.PutUint32(dst[n:], dn)
n += 3
si += 4
return n, err
}
-// decode32 tries to decode 4 base64 characters into 3 bytes, and returns those
-// bytes. len(src) must be >= 4.
-// Returns (0, false) if decoding failed.
-func (enc *Encoding) decode32(src []byte) (dn uint32, ok bool) {
- var n uint32
- _ = src[3]
- if n = uint32(enc.decodeMap[src[0]]); n == 0xff {
- return 0, false
- }
- dn |= n << 26
- if n = uint32(enc.decodeMap[src[1]]); n == 0xff {
- return 0, false
- }
- dn |= n << 20
- if n = uint32(enc.decodeMap[src[2]]); n == 0xff {
+// assemble32 assembles 4 base64 digits into 3 bytes.
+// Each digit comes from the decode map, and will be 0xff
+// if it came from an invalid character.
+func assemble32(n1, n2, n3, n4 byte) (dn uint32, ok bool) {
+ // Check that all the digits are valid. If any of them was 0xff, their
+ // bitwise OR will be 0xff.
+ if n1|n2|n3|n4 == 0xff {
return 0, false
}
- dn |= n << 14
- if n = uint32(enc.decodeMap[src[3]]); n == 0xff {
- return 0, false
- }
- dn |= n << 8
- return dn, true
+ return uint32(n1)<<26 |
+ uint32(n2)<<20 |
+ uint32(n3)<<14 |
+ uint32(n4)<<8,
+ true
}
-// decode64 tries to decode 8 base64 characters into 6 bytes, and returns those
-// bytes. len(src) must be >= 8.
-// Returns (0, false) if decoding failed.
-func (enc *Encoding) decode64(src []byte) (dn uint64, ok bool) {
- var n uint64
- _ = src[7]
- if n = uint64(enc.decodeMap[src[0]]); n == 0xff {
- return 0, false
- }
- dn |= n << 58
- if n = uint64(enc.decodeMap[src[1]]); n == 0xff {
- return 0, false
- }
- dn |= n << 52
- if n = uint64(enc.decodeMap[src[2]]); n == 0xff {
- return 0, false
- }
- dn |= n << 46
- if n = uint64(enc.decodeMap[src[3]]); n == 0xff {
- return 0, false
- }
- dn |= n << 40
- if n = uint64(enc.decodeMap[src[4]]); n == 0xff {
- return 0, false
- }
- dn |= n << 34
- if n = uint64(enc.decodeMap[src[5]]); n == 0xff {
- return 0, false
- }
- dn |= n << 28
- if n = uint64(enc.decodeMap[src[6]]); n == 0xff {
- return 0, false
- }
- dn |= n << 22
- if n = uint64(enc.decodeMap[src[7]]); n == 0xff {
+// assemble64 assembles 8 base64 digits into 6 bytes.
+// Each digit comes from the decode map, and will be 0xff
+// if it came from an invalid character.
+func assemble64(n1, n2, n3, n4, n5, n6, n7, n8 byte) (dn uint64, ok bool) {
+ // Check that all the digits are valid. If any of them was 0xff, their
+ // bitwise OR will be 0xff.
+ if n1|n2|n3|n4|n5|n6|n7|n8 == 0xff {
return 0, false
}
- dn |= n << 16
- return dn, true
+ return uint64(n1)<<58 |
+ uint64(n2)<<52 |
+ uint64(n3)<<46 |
+ uint64(n4)<<40 |
+ uint64(n5)<<34 |
+ uint64(n6)<<28 |
+ uint64(n7)<<22 |
+ uint64(n8)<<16,
+ true
}
type newlineFilteringReader struct {