Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
3a64443
trimming some unnecessary code
lemire Mar 20, 2024
3f9cb0f
fixing missing rvv implementation
lemire Mar 20, 2024
a9ea1c6
completing the base64 implementation.
lemire Mar 22, 2024
0f49240
adding ppc64
lemire Mar 22, 2024
5daa520
saving
Mar 22, 2024
151aa09
saturated.
lemire Mar 22, 2024
b917aa8
finishing...
Mar 22, 2024
ca17560
various fixes
Mar 27, 2024
94b7dac
Implemented bun benchmark
lemire Mar 27, 2024
c35d8df
Obvious fix.
lemire Mar 27, 2024
1a90f2a
documentation
lemire Mar 27, 2024
bd454ea
adding libbase64 competitor
lemire Mar 27, 2024
bdab72f
more documentation.
lemire Mar 27, 2024
65f933b
base64url (first steps)
lemire Mar 28, 2024
4aa837d
working through
lemire Mar 28, 2024
8dc79aa
implemented base64url for ARM.
lemire Mar 29, 2024
fe1138f
documentation.
lemire Mar 29, 2024
5d1d0d5
prototype base64url
Mar 30, 2024
21717c4
solved based64url
Mar 30, 2024
c96ac90
completing the base64 implementation.
lemire Mar 22, 2024
106e18c
adding ppc64
lemire Mar 22, 2024
d1c9cbc
saving
Mar 22, 2024
8606798
saturated.
lemire Mar 22, 2024
e7eae70
finishing...
Mar 22, 2024
9262b4b
various fixes
Mar 27, 2024
3444f4e
Implemented bun benchmark
lemire Mar 27, 2024
6949b2c
Obvious fix.
lemire Mar 27, 2024
381945b
documentation
lemire Mar 27, 2024
7b304d3
adding libbase64 competitor
lemire Mar 27, 2024
f51ffdf
more documentation.
lemire Mar 27, 2024
3d87826
base64url (first steps)
lemire Mar 28, 2024
c72079c
working through
lemire Mar 28, 2024
200b6bc
implemented base64url for ARM.
lemire Mar 29, 2024
4971bc2
documentation.
lemire Mar 29, 2024
c729247
prototype base64url
Mar 30, 2024
e32acc9
solved based64url
Mar 30, 2024
038ce51
Merge branch 'base64_part2' of github.com:simdutf/simdutf into base64…
Mar 30, 2024
9154818
fixing a missing func definition (bad signature)
lemire Mar 30, 2024
fd037f5
no such thing as version 4 of uraimo/run-on-arch-action
lemire Mar 30, 2024
0de753a
fixes
lemire Mar 30, 2024
ccdf51d
Update benchmarks/base64/benchmark_base64.cpp
lemire Mar 30, 2024
7ec70f2
Update benchmarks/base64/benchmark_base64.cpp
lemire Mar 30, 2024
18dc616
Update benchmarks/base64/libbase64_spaces.h
lemire Mar 30, 2024
aeb2f5f
Update include/simdutf/implementation.h
lemire Mar 30, 2024
e0ce663
Update src/haswell/avx2_base64.cpp
lemire Mar 30, 2024
bb9d1fc
various minor fixes (linting + comments)
Mar 30, 2024
f511d9a
adding another comment.
Mar 30, 2024
e2a224f
cleaning up the base64 benchmark flags
Mar 30, 2024
5e6a366
disabling Ubuntu rvv VLEN=1024 (clang 17) CI due to system failures
Mar 30, 2024
9a92c54
adding the option
Mar 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
working through
  • Loading branch information
lemire committed Mar 28, 2024
commit 4aa837d44b1126a32badaa9fc7971afbe23c46a6
33 changes: 33 additions & 0 deletions scripts/base64/neon_decode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
t='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
spaces=' \t\n\r'
lut_lo = [0x3a, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x61, 0xe1, 0xb4, 0xf4, 0xe5, 0xf4, 0xb4]
lut_hi = [0x11, 0x20, 0x42, 0x80, 0x8, 0x4, 0x8, 0x4, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20]
roll = [0x0, 0x10, 0x13, 0x4, 0xbf, 0xbf, 0xb9, 0xb9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
def decode(s):
low = s & 0xf
high = s >> 4
m = lut_lo[low] & lut_hi[high]
if(m > 0x3):
return (m, None)
if s == 0x2f:
off = roll[high - 1]
else:
off = roll[high]
return (m,(s + off)&0xff)

for i in range(256):
m,d = decode(i)
if d is None:
assert t.find(chr(i)) == -1
assert spaces.find(chr(i)) == -1
continue
if m == 0:
assert d >= 0
# we must have a base64 element
v = t.find(chr(i))
#print(i, chr(i), v, d)
assert v == d
else:
# we must have a space
v = spaces.find(chr(i))
assert v >= 0
16 changes: 12 additions & 4 deletions src/arm64/arm_base64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,15 @@ size_t encode_base64(char *dst, const char *src, size_t srclen, base64_options o
'5', 'K', 'a', 'q', '6', 'L', 'b', 'r', '7', 'M', 'c', 's', '8',
'N', 'd', 't', '9', 'O', 'e', 'u', '+', 'P', 'f', 'v', '/',
};
constexpr static uint8_t source_table_url[64] = {
'A', 'Q', 'g', 'w', 'B', 'R', 'h', 'x', 'C', 'S', 'i', 'y', 'D',
'T', 'j', 'z', 'E', 'U', 'k', '0', 'F', 'V', 'l', '1', 'G', 'W',
'm', '2', 'H', 'X', 'n', '3', 'I', 'Y', 'o', '4', 'J', 'Z', 'p',
'5', 'K', 'a', 'q', '6', 'L', 'b', 'r', '7', 'M', 'c', 's', '8',
'N', 'd', 't', '9', 'O', 'e', 'u', '-', 'P', 'f', 'v', '_',
};
const uint8x16_t v3f = vdupq_n_u8(0x3f);
const uint8x16x4_t table = vld4q_u8(source_table);
const uint8x16x4_t table = vld4q_u8((options&base64_url) ? source_table_url : source_table);
size_t i = 0;
for (; i + 16 * 3 <= srclen; i += 16 * 3) {
const uint8x16x3_t in = vld3q_u8((const uint8_t *)src + i);
Expand Down Expand Up @@ -94,6 +101,7 @@ struct block64 {
uint8x16_t chunks[4];
};
static_assert(sizeof(block64) == 64, "block64 is not 64 bytes");
template <bool base64_url>
uint64_t to_base64_mask(block64 *b, bool *error) {
uint8x16_t v0f = vdupq_n_u8(0xf);

Expand Down Expand Up @@ -235,9 +243,9 @@ void base64_decode_block(char *out, const char *src) {
vst3q_u8((uint8_t *)out, outvec);
}

template <typename char_type>
template <bool base64_url, typename char_type>
result compress_decode_base64(char *dst, const char_type *src, size_t srclen, base64_options options) {
const uint8_t *to_base64 = (options & base64_url) ? tables::base64::to_base64_url_value : tables::base64::to_base64_value;
const uint8_t *to_base64 = base64_url ? tables::base64::to_base64_url_value : tables::base64::to_base64_value;
size_t equalsigns = 0;
if (srclen > 0 && src[srclen - 1] == '=') {
srclen--;
Expand All @@ -261,7 +269,7 @@ result compress_decode_base64(char *dst, const char_type *src, size_t srclen, ba
load_block(&b, src);
src += 64;
bool error = false;
uint64_t badcharmask = to_base64_mask(&b, &error);
uint64_t badcharmask = to_base64_mask<base64_url>(&b, &error);
if (error) {
src -= 64;

Expand Down
4 changes: 2 additions & 2 deletions src/arm64/implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -840,15 +840,15 @@ simdutf_warn_unused size_t implementation::maximal_binary_length_from_base64(con
}

simdutf_warn_unused result implementation::base64_to_binary(const char * input, size_t length, char* output, base64_options options) const noexcept {
return compress_decode_base64(output, input, length, options);
return (options & base64_url) ? compress_decode_base64<true>(output, input, length, options) : compress_decode_base64<false>(output, input, length, options);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove the conditional and directly pass it to the template argument of the function. Removal of a branch is a good :-)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is indeed a runtime branch here, and it is not free, but pushing it down might not make disappear. A different option would be to have distinct functions for base64url and regular base64, but I thought it was not very nice from an API point of view.

}

simdutf_warn_unused size_t implementation::maximal_binary_length_from_base64(const char16_t * input, size_t length) const noexcept {
return scalar::base64::maximal_binary_length_from_base64(input, length);
}

simdutf_warn_unused result implementation::base64_to_binary(const char16_t * input, size_t length, char* output, base64_options options) const noexcept {
return compress_decode_base64(output, input, length, options);
return (options & base64_url) ? compress_decode_base64<true>(output, input, length, options) : compress_decode_base64<false>(output, input, length, options);
}

simdutf_warn_unused size_t implementation::base64_length_from_binary(size_t length) const noexcept {
Expand Down
4 changes: 2 additions & 2 deletions src/haswell/avx2_base64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,9 @@ static inline void base64_decode_block_safe(char *out, block64 *b) {
std::memcpy(out + 24, buffer, 24);
}

template <typename chartype>
template <bool base64_url, typename chartype>
result compress_decode_base64(char *dst, const chartype *src, size_t srclen, base64_options options) {
const uint8_t *to_base64 = (options & base64_url) ? tables::base64::to_base64_url_value : tables::base64::to_base64_value;
const uint8_t *to_base64 = base64_url ? tables::base64::to_base64_url_value : tables::base64::to_base64_value;
size_t equalsigns = 0;
if (srclen > 0 && src[srclen - 1] == '=') {
srclen--;
Expand Down
4 changes: 2 additions & 2 deletions src/haswell/implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,15 +783,15 @@ simdutf_warn_unused size_t implementation::maximal_binary_length_from_base64(con
}

simdutf_warn_unused result implementation::base64_to_binary(const char * input, size_t length, char* output, base64_options options) const noexcept {
return compress_decode_base64(output, input, length, options);
return (options & base64_url) ? compress_decode_base64<true>(output, input, length, options) : compress_decode_base64<false>(output, input, length, options);
}

simdutf_warn_unused size_t implementation::maximal_binary_length_from_base64(const char16_t * input, size_t length) const noexcept {
return scalar::base64::maximal_binary_length_from_base64(input, length);
}

simdutf_warn_unused result implementation::base64_to_binary(const char16_t * input, size_t length, char* output, base64_options options) const noexcept {
return compress_decode_base64(output, input, length, options);
return (options & base64_url) ? compress_decode_base64<true>(output, input, length, options) : compress_decode_base64<false>(output, input, length, options);
}

simdutf_warn_unused size_t implementation::base64_length_from_binary(size_t length) const noexcept {
Expand Down
4 changes: 2 additions & 2 deletions src/icelake/icelake_base64.inl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ static inline void base64_decode_block(char *out, block64 *b) {
base64_decode(out, b->chunks[0]);
}

template <typename chartype>
template <bool base64_url, typename chartype>
result compress_decode_base64(char *dst, const chartype *src, size_t srclen, base64_options options) {
const uint8_t *to_base64 = (options & base64_url) ? tables::base64::to_base64_url_value : tables::base64::to_base64_value;
const uint8_t *to_base64 = base64_url ? tables::base64::to_base64_url_value : tables::base64::to_base64_value;
size_t equalsigns = 0;
if (srclen > 0 && src[srclen - 1] == '=') {
srclen--;
Expand Down
4 changes: 2 additions & 2 deletions src/icelake/implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1369,15 +1369,15 @@ simdutf_warn_unused size_t implementation::maximal_binary_length_from_base64(con
}

simdutf_warn_unused result implementation::base64_to_binary(const char * input, size_t length, char* output, base64_options options) const noexcept {
return compress_decode_base64(output, input, length, options);
return (options & base64_url) ? compress_decode_base64<true>(output, input, length, options) : compress_decode_base64<false>(output, input, length, options);
}

simdutf_warn_unused size_t implementation::maximal_binary_length_from_base64(const char16_t * input, size_t length) const noexcept {
return scalar::base64::maximal_binary_length_from_base64(input, length);
}

simdutf_warn_unused result implementation::base64_to_binary(const char16_t * input, size_t length, char* output, base64_options options) const noexcept {
return compress_decode_base64(output, input, length, options);
return (options & base64_url) ? compress_decode_base64<true>(output, input, length, options) : compress_decode_base64<false>(output, input, length, options);
}


Expand Down
4 changes: 2 additions & 2 deletions src/westmere/implementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -784,15 +784,15 @@ simdutf_warn_unused size_t implementation::maximal_binary_length_from_base64(con
}

simdutf_warn_unused result implementation::base64_to_binary(const char * input, size_t length, char* output, base64_options options) const noexcept {
return compress_decode_base64(output, input, length, options);
return (options & base64_url) ? compress_decode_base64<true>(output, input, length, options) : compress_decode_base64<false>(output, input, length, options);
}

simdutf_warn_unused size_t implementation::maximal_binary_length_from_base64(const char16_t * input, size_t length, base64_options options) const noexcept {
return scalar::base64::maximal_binary_length_from_base64(input, length, options);
}

simdutf_warn_unused result implementation::base64_to_binary(const char16_t * input, size_t length, char* output, base64_options options) const noexcept {
return compress_decode_base64(output, input, length, options);
return (options & base64_url) ? compress_decode_base64<true>(output, input, length, options) : compress_decode_base64<false>(output, input, length, options);
}

simdutf_warn_unused size_t implementation::base64_length_from_binary(size_t length) const noexcept {
Expand Down
4 changes: 2 additions & 2 deletions src/westmere/sse_base64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,9 +338,9 @@ static inline void base64_decode_block_safe(char *out, block64 *b) {
std::memcpy(out + 36, buffer, 12);
}

template <typename chartype>
template <bool base64_url, typename chartype>
result compress_decode_base64(char *dst, const chartype *src, size_t srclen, base64_options options) {
const uint8_t *to_base64 = (options & base64_url) ? tables::base64::to_base64_url_value : tables::base64::to_base64_value;
const uint8_t *to_base64 = base64_url ? tables::base64::to_base64_url_value : tables::base64::to_base64_value;
size_t equalsigns = 0;
if (srclen > 0 && src[srclen - 1] == '=') {
srclen--;
Expand Down