Skip to content

Commit 4227a7c

Browse files
committed
some tweaking
1 parent ff37fa8 commit 4227a7c

File tree

10 files changed

+337
-241
lines changed

10 files changed

+337
-241
lines changed

README.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,24 @@ used in major JavaScript runtimes (Node.js and Bun) to C#. It would complete the
1111

1212
## Requirements
1313

14-
We recommend you install .NET 9 or better: https://dotnet.microsoft.com/en-us/download/dotnet/9.0
14+
We require .NET 9 or better: https://dotnet.microsoft.com/en-us/download/dotnet/9.0
15+
16+
17+
## Usage
18+
19+
The library only provides Base64 decoding functions, because the .NET library already has
20+
fast Base64 encoding functions.
21+
22+
```c#
23+
string base64 = "SGVsbG8sIFdvcmxkIQ==";
24+
byte[] buffer = new byte[SimdBase64.Base64.MaximalBinaryLengthFromBase64(base64.AsSpan())];
25+
int bytesConsumed; // gives you the number of characters consumed
26+
int bytesWritten; // gives you the
27+
var result = SimdBase64.Base64.DecodeFromBase64(base64.AsSpan(), buffer, out bytesConsumed, out bytesWritten, false); // false is for regular base64, true for base64url
28+
// result == OperationStatus.Done
29+
// Encoding.UTF8.GetString(buffer.AsSpan().Slice(0, bytesWritten)) == "Hello, World!"
30+
31+
```
1532

1633

1734
## Running tests

benchmark/Benchmark.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ public unsafe void RunScalarDecodingBenchmarkUTF8(string[] data, int[] lengths)
238238
byte[] dataoutput = output[i];
239239
int bytesConsumed = 0;
240240
int bytesWritten = 0;
241-
SimdBase64.Base64.Base64WithWhiteSpaceToBinaryScalar(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
241+
SimdBase64.Scalar.Base64.Base64WithWhiteSpaceToBinaryScalar(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
242242
if (bytesWritten != lengths[i])
243243
{
244244
Console.WriteLine($"Error: {bytesWritten} != {lengths[i]}");
@@ -257,7 +257,7 @@ public unsafe void RunScalarDecodingBenchmarkUTF16(string[] data, int[] lengths)
257257
byte[] dataoutput = output[i];
258258
int bytesConsumed = 0;
259259
int bytesWritten = 0;
260-
SimdBase64.Base64.Base64WithWhiteSpaceToBinaryScalar(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
260+
SimdBase64.Scalar.Base64.Base64WithWhiteSpaceToBinaryScalar(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
261261
if (bytesWritten != lengths[i])
262262
{
263263
Console.WriteLine($"Error: {bytesWritten} != {lengths[i]}");
@@ -276,7 +276,7 @@ public unsafe void RunSSEDecodingBenchmarkUTF8(string[] data, int[] lengths)
276276
byte[] dataoutput = output[i];
277277
int bytesConsumed = 0;
278278
int bytesWritten = 0;
279-
SimdBase64.Base64.DecodeFromBase64SSE(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
279+
SimdBase64.SSE.Base64.DecodeFromBase64SSE(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
280280
if (bytesWritten != lengths[i])
281281
{
282282
Console.WriteLine($"Error: {bytesWritten} != {lengths[i]}");
@@ -295,7 +295,7 @@ public unsafe void RunSSEDecodingBenchmarkUTF16(string[] data, int[] lengths)
295295
byte[] dataoutput = output[i];
296296
int bytesConsumed = 0;
297297
int bytesWritten = 0;
298-
SimdBase64.Base64.DecodeFromBase64SSE(base64, dataoutput, out bytesConsumed, out bytesWritten, false);
298+
SimdBase64.SSE.Base64.DecodeFromBase64SSE(base64, dataoutput, out bytesConsumed, out bytesWritten, false);
299299
if (bytesWritten != lengths[i])
300300
{
301301
Console.WriteLine($"Error: {bytesWritten} != {lengths[i]}");
@@ -312,10 +312,10 @@ public unsafe void RunSSEDecodingBenchmarkWithAllocUTF8(string[] data, int[] len
312312
for (int i = 0; i < FileContent.Length; i++)
313313
{
314314
byte[] base64 = input[i];
315-
byte[] dataoutput = new byte[SimdBase64.Base64.MaximalBinaryLengthFromBase64Scalar<byte>(base64.AsSpan())];
315+
byte[] dataoutput = new byte[SimdBase64.Scalar.Base64.MaximalBinaryLengthFromBase64Scalar<byte>(base64.AsSpan())];
316316
int bytesConsumed = 0;
317317
int bytesWritten = 0;
318-
SimdBase64.Base64.DecodeFromBase64SSE(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
318+
SimdBase64.SSE.Base64.DecodeFromBase64SSE(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
319319
if (bytesWritten != lengths[i])
320320
{
321321
Console.WriteLine($"Error: {bytesWritten} != {lengths[i]}");
@@ -331,10 +331,10 @@ public unsafe void RunSSEDecodingBenchmarkWithAllocUTF16(string[] data, int[] le
331331
{
332332
string s = FileContent[i];
333333
char[] base64 = input16[i];
334-
byte[] dataoutput = new byte[SimdBase64.Base64.MaximalBinaryLengthFromBase64Scalar<char>(base64.AsSpan())];
334+
byte[] dataoutput = new byte[SimdBase64.Scalar.Base64.MaximalBinaryLengthFromBase64Scalar<char>(base64.AsSpan())];
335335
int bytesConsumed = 0;
336336
int bytesWritten = 0;
337-
SimdBase64.Base64.DecodeFromBase64SSE(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
337+
SimdBase64.SSE.Base64.DecodeFromBase64SSE(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
338338
if (bytesWritten != lengths[i])
339339
{
340340
Console.WriteLine($"Error: {bytesWritten} != {lengths[i]}");
@@ -390,7 +390,7 @@ public unsafe void RunARMDecodingBenchmarkWithAllocUTF8(string[] data, int[] len
390390
for (int i = 0; i < FileContent.Length; i++)
391391
{
392392
byte[] base64 = input[i];
393-
byte[] dataoutput = new byte[SimdBase64.Base64.MaximalBinaryLengthFromBase64Scalar<byte>(base64.AsSpan())];
393+
byte[] dataoutput = new byte[SimdBase64.Scalar.Base64.MaximalBinaryLengthFromBase64Scalar<byte>(base64.AsSpan())];
394394
int bytesConsumed = 0;
395395
int bytesWritten = 0;
396396
SimdBase64.Arm.Base64.DecodeFromBase64ARM(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);
@@ -409,7 +409,7 @@ public unsafe void RunARMDecodingBenchmarkWithAllocUTF16(string[] data, int[] le
409409
{
410410
string s = FileContent[i];
411411
char[] base64 = input16[i];
412-
byte[] dataoutput = new byte[SimdBase64.Base64.MaximalBinaryLengthFromBase64Scalar<char>(base64.AsSpan())];
412+
byte[] dataoutput = new byte[SimdBase64.Scalar.Base64.MaximalBinaryLengthFromBase64Scalar<char>(base64.AsSpan())];
413413
int bytesConsumed = 0;
414414
int bytesWritten = 0;
415415
SimdBase64.Arm.Base64.DecodeFromBase64ARM(base64.AsSpan(), dataoutput, out bytesConsumed, out bytesWritten, false);

src/Base64.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using System;
2+
using System.Buffers;
3+
using System.Runtime.CompilerServices;
4+
using System.Runtime.Intrinsics;
5+
using System.Runtime.Intrinsics.Arm;
6+
using System.Runtime.Intrinsics.X86;
7+
8+
9+
namespace SimdBase64
10+
{
11+
public static class Base64 {
12+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
13+
public static int MaximalBinaryLengthFromBase64<T>(ReadOnlySpan<T> input)
14+
{
15+
return Scalar.Base64.MaximalBinaryLengthFromBase64Scalar(input);
16+
}
17+
public unsafe static OperationStatus DecodeFromBase64(ReadOnlySpan<byte> source, Span<byte> dest, out int bytesConsumed, out int bytesWritten, bool isUrl = false) {
18+
19+
if (AdvSimd.Arm64.IsSupported && BitConverter.IsLittleEndian)
20+
{
21+
return Arm.Base64.DecodeFromBase64ARM(source, dest, out bytesConsumed, out bytesWritten, isUrl);
22+
}
23+
// To be comleted
24+
//if (Vector512.IsHardwareAccelerated && Avx512Vbmi.IsSupported)
25+
//{
26+
// return GetPointerToFirstInvalidByteAvx512(pInputBuffer, inputLength, out Utf16CodeUnitCountAdjustment, out ScalarCodeUnitCountAdjustment);
27+
//}
28+
//if (Avx2.IsSupported)
29+
//{
30+
// return GetPointerToFirstInvalidByteAvx2(pInputBuffer, inputLength, out Utf16CodeUnitCountAdjustment, out ScalarCodeUnitCountAdjustment);
31+
//}
32+
if (Ssse3.IsSupported && Popcnt.IsSupported)
33+
{
34+
return SSE.Base64.DecodeFromBase64SSE(source, dest, out bytesConsumed, out bytesWritten, isUrl);
35+
}
36+
37+
return Scalar.Base64.DecodeFromBase64Scalar(source, dest, out bytesConsumed, out bytesWritten, isUrl);
38+
39+
}
40+
41+
public unsafe static OperationStatus DecodeFromBase64(ReadOnlySpan<char> source, Span<byte> dest, out int bytesConsumed, out int bytesWritten, bool isUrl = false) {
42+
43+
if (AdvSimd.Arm64.IsSupported && BitConverter.IsLittleEndian)
44+
{
45+
return Arm.Base64.DecodeFromBase64ARM(source, dest, out bytesConsumed, out bytesWritten, isUrl);
46+
}
47+
// To be comleted
48+
//if (Vector512.IsHardwareAccelerated && Avx512Vbmi.IsSupported)
49+
//{
50+
// return GetPointerToFirstInvalidByteAvx512(pInputBuffer, inputLength, out Utf16CodeUnitCountAdjustment, out ScalarCodeUnitCountAdjustment);
51+
//}
52+
//if (Avx2.IsSupported)
53+
//{
54+
// return GetPointerToFirstInvalidByteAvx2(pInputBuffer, inputLength, out Utf16CodeUnitCountAdjustment, out ScalarCodeUnitCountAdjustment);
55+
//}
56+
if (Ssse3.IsSupported && Popcnt.IsSupported)
57+
{
58+
return SSE.Base64.DecodeFromBase64SSE(source, dest, out bytesConsumed, out bytesWritten, isUrl);
59+
}
60+
61+
return Scalar.Base64.DecodeFromBase64Scalar(source, dest, out bytesConsumed, out bytesWritten, isUrl);
62+
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)