Skip to content

Commit c5a6761

Browse files
authored
Merge branch 'main' into copy_paste
2 parents f45b4c6 + 16dba17 commit c5a6761

File tree

3 files changed

+129
-85
lines changed

3 files changed

+129
-85
lines changed

.github/workflows/dotnet.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
name: .NET
2+
3+
on: [pull_request] # add push later
4+
5+
jobs:
6+
build:
7+
name: Build and test on ${{ matrix.os }}
8+
runs-on: ${{ matrix.os }}
9+
strategy:
10+
fail-fast: false
11+
matrix:
12+
os: [ubuntu-latest] # add later:, windows-latest, macos-latest]
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Setup .NET 8.0
17+
uses: actions/setup-dotnet@v4
18+
with:
19+
dotnet-version: '8.0.x'
20+
- name: Restore dependencies
21+
run: dotnet restore
22+
- name: Build
23+
run: dotnet build --no-restore
24+
- name: Unit tests
25+
run: dotnet test --verbosity m --no-build
26+
continue-on-error: false

src/Base64SSE.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ private static ushort ToBase64Mask(bool base64Url, ref Vector128<byte> src, ref
8181
: Vector128.Create(0x00, 0x00, 0x00, 0x13, 0x04, 0xBF, 0xBF, 0xB9, 0xB9, 0x00, 0x10, 0xC3, 0xBF, 0xBF, 0xB9, 0xB9);
8282

8383
Vector128<sbyte> checkAsso = base64Url
84-
? Vector128.Create(0xD, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x7, 0xB, 0x6, 0xB, 0x12)
84+
? Vector128.Create(0xD, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x7, 0xB, 0xE, 0xB, 0x6)
8585
: Vector128.Create(0xD, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x7, 0xB, 0xB, 0xB, 0xF);
8686

8787
Vector128<byte> checkValues = base64Url
88-
? Vector128.Create(0x00, 0x80, 0x80, 0x80, 0xCF, 0xBF, 0xD3, 0xA6, 0xB5, 0x86, 0xD0, 0x80, 0xB0, 0x80, 0x00, 0x00)
88+
? Vector128.Create(0x80, 0x80, 0x80, 0x80, 0xCF, 0xBF, 0xB6, 0xA6, 0xB5, 0xA1, 0x0, 0x80, 0x0, 0x80, 0x0, 0x80)
8989
: Vector128.Create(0x80, 0x80, 0x80, 0x80, 0xCF, 0xBF, 0xD5, 0xA6, 0xB5, 0x86, 0xD1, 0x80, 0xB1, 0x80, 0x91, 0x80);
9090

9191
Vector128<Int32> shifted = Sse2.ShiftRightLogical(src.AsInt32(), 3);

test/Base64DecodingTests.cs

Lines changed: 101 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ private static bool IsSystemSupported(TestSystemRequirements requiredSystems)
114114
case Architecture.X64:
115115
return (requiredSystems.HasFlag(TestSystemRequirements.X64Avx512) && Vector512.IsHardwareAccelerated && System.Runtime.Intrinsics.X86.Avx512F.IsSupported) ||
116116
(requiredSystems.HasFlag(TestSystemRequirements.X64Avx2) && System.Runtime.Intrinsics.X86.Avx2.IsSupported) ||
117-
(requiredSystems.HasFlag(TestSystemRequirements.X64Sse) && System.Runtime.Intrinsics.X86.Sse.IsSupported);
117+
(requiredSystems.HasFlag(TestSystemRequirements.X64Sse) && System.Runtime.Intrinsics.X86.Ssse3.IsSupported && System.Runtime.Intrinsics.X86.Popcnt.IsSupported);
118118
default:
119119
return false;
120120
}
@@ -168,11 +168,11 @@ protected static void DecodeBase64Cases(DecodeFromBase64DelegateFnc DecodeFromBa
168168
[Trait("Category", "scalar")]
169169
public void DecodeBase64CasesScalar()
170170
{
171-
DecodeBase64Cases(Base64.DecodeFromBase64SSE, Base64.MaximalBinaryLengthFromBase64Scalar);
171+
DecodeBase64Cases(Base64.DecodeFromBase64Scalar, Base64.MaximalBinaryLengthFromBase64Scalar);
172172
}
173173

174-
[Fact]
175-
[Trait("Category", "SSE")]
174+
[Trait("Category", "sse")]
175+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
176176
public void DecodeBase64CasesSSE()
177177
{
178178
DecodeBase64Cases(Base64.DecodeFromBase64SSE, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -238,88 +238,107 @@ public void CompleteDecodeBase64CasesScalar()
238238
CompleteDecodeBase64Cases(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
239239
}
240240

241-
[Fact]
242241
[Trait("Category", "sse")]
242+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
243243
public void CompleteDecodeBase64CasesSSE()
244244
{
245245
CompleteDecodeBase64Cases(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
246246
}
247247

248248

249-
protected static void MoreDecodeTests(Base64WithWhiteSpaceToBinary Base64WithWhiteSpaceToBinary, DecodeFromBase64DelegateSafe DecodeFromBase64DelegateSafe, MaxBase64ToBinaryLengthDelegateFnc MaxBase64ToBinaryLengthDelegate)
250-
{
251-
if (Base64WithWhiteSpaceToBinary == null || DecodeFromBase64DelegateSafe == null || MaxBase64ToBinaryLengthDelegate == null)
252-
{
253-
#pragma warning disable CA2208
254-
throw new ArgumentNullException("Unexpected null parameter");
255-
}
256-
List<(string decoded, string base64)> cases = new List<(string, string)>
257-
{
258-
("Hello, World!", "SGVsbG8sIFdvcmxkIQ=="),
259-
("GeeksforGeeks", "R2Vla3Nmb3JHZWVrcw=="),
260-
("123456", "MTIzNDU2"),
261-
("Base64 Encoding", "QmFzZTY0IEVuY29kaW5n"),
262-
("!R~J2jL&mI]O)3=c:G3Mo)oqmJdxoprTZDyxEvU0MI.'Ww5H{G>}y;;+B8E_Ah,Ed[ PdBqY'^N>O$4:7LK1<:|7)btV@|{YWR$$Er59-XjVrFl4L}~yzTEd4'E[@k", "IVJ+SjJqTCZtSV1PKTM9YzpHM01vKW9xbUpkeG9wclRaRHl4RXZVME1JLidXdzVIe0c+fXk7OytCOEVfQWgsRWRbIFBkQnFZJ15OPk8kNDo3TEsxPDp8NylidFZAfHtZV1IkJEVyNTktWGpWckZsNEx9fnl6VEVkNCdFW0Br")
263-
};
264-
265-
foreach (var (decoded, base64) in cases)
266-
{
267-
268-
269-
byte[] base64Bytes = Encoding.UTF8.GetBytes(base64);
270-
ReadOnlySpan<byte> base64Span = new ReadOnlySpan<byte>(base64Bytes);
271-
int bytesConsumed;
272-
int bytesWritten;
273-
274-
byte[] buffer = new byte[MaxBase64ToBinaryLengthDelegate(base64Span)];
275-
var result = Base64WithWhiteSpaceToBinary(base64Span, buffer, out bytesConsumed, out bytesWritten, false);
276-
Assert.Equal(OperationStatus.Done, result);
277-
Assert.True(OperationStatus.Done == result, $"Decoding string {decoded} with Length {decoded.Length} bytes went wrong");
278-
for (int i = 0; i < bytesWritten; i++)
279-
{
280-
Assert.True(decoded[i] == (char)buffer[i], $"Decoded character not equal to source at location {i}: \n Actual: {(char)buffer[i]} ,\n Expected: {decoded[i]},\n Actual string: {BitConverter.ToString(buffer)},\n Expected string :{decoded} ");
281-
}
282-
Assert.Equal(decoded.Length, bytesWritten);
283-
Assert.Equal(base64.Length, bytesConsumed);
284-
285-
}
286-
287-
foreach (var (decoded, base64) in cases)
288-
{
289-
byte[] base64Bytes = Encoding.UTF8.GetBytes(base64);
290-
ReadOnlySpan<byte> base64Span = new ReadOnlySpan<byte>(base64Bytes);
291-
int bytesConsumed;
292-
int bytesWritten;
293-
294-
byte[] buffer = new byte[MaxBase64ToBinaryLengthDelegate(base64Span)];
295-
var result = DecodeFromBase64DelegateSafe(base64Span, buffer, out bytesConsumed, out bytesWritten, false);
296-
Assert.Equal(OperationStatus.Done, result);
297-
Assert.Equal(decoded.Length, bytesWritten);
298-
Assert.Equal(base64.Length, bytesConsumed);
299-
300-
for (int i = 0; i < bytesWritten; i++)
301-
{
302-
Assert.Equal(decoded[i], (char)buffer[i]);
303-
}
304-
}
249+
protected static void Issue511(Base64WithWhiteSpaceToBinary Base64WithWhiteSpaceToBinary)
250+
{
251+
ArgumentNullException.ThrowIfNull(Base64WithWhiteSpaceToBinary);
252+
253+
byte[] base64Bytes = [0x7f,
254+
0x57,
255+
0x5a,
256+
0x5a,
257+
0x5a,
258+
0x5a,
259+
0x5a,
260+
0x5a,
261+
0x5a,
262+
0x5a,
263+
0x5a,
264+
0x5a,
265+
0x57,
266+
0x57,
267+
0x57,
268+
0x57,
269+
0x57,
270+
0x57,
271+
0x57,
272+
0x57,
273+
0x57,
274+
0x57,
275+
0x57,
276+
0x57,
277+
0x57,
278+
0x57,
279+
0x57,
280+
0x57,
281+
0x57,
282+
0x57,
283+
0x57,
284+
0x57,
285+
0x57,
286+
0x57,
287+
0x20,
288+
0x20,
289+
0x20,
290+
0x20,
291+
0x20,
292+
0x20,
293+
0x20,
294+
0x20,
295+
0x20,
296+
0x20,
297+
0x20,
298+
0x20,
299+
0x20,
300+
0x20,
301+
0x20,
302+
0x20,
303+
0x20,
304+
0x20,
305+
0x20,
306+
0x20,
307+
0x20,
308+
0x20,
309+
0x20,
310+
0x20,
311+
0x20,
312+
0x5a,
313+
0x20,
314+
0x5a,
315+
0x5a,
316+
0x5a];
317+
ReadOnlySpan<byte> base64Span = new ReadOnlySpan<byte>(base64Bytes);
318+
int bytesConsumed;
319+
int bytesWritten;
320+
byte[] buffer = new byte[48];
321+
var result = Base64WithWhiteSpaceToBinary(base64Span, buffer, out bytesConsumed, out bytesWritten, true);
322+
Assert.Equal(OperationStatus.InvalidData, result);
305323

306324
}
307325

308326
[Fact]
309327
[Trait("Category", "scalar")]
310-
public void MoreDecodeTestsScalar()
328+
public void Issue511Scalar()
311329
{
312-
MoreDecodeTests(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
330+
Issue511(Base64.Base64WithWhiteSpaceToBinaryScalar);
313331
}
314332

315333

316-
[Fact]
317334
[Trait("Category", "SSE")]
318-
public void MoreDecodeTestsSSE()
335+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
336+
public void Issue511SSE()
319337
{
320-
MoreDecodeTests(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
338+
Issue511(Base64.DecodeFromBase64SSE);
321339
}
322340

341+
323342
protected static void MoreDecodeTestsUrl(Base64WithWhiteSpaceToBinary Base64WithWhiteSpaceToBinary, DecodeFromBase64DelegateSafe DecodeFromBase64DelegateSafe, MaxBase64ToBinaryLengthDelegateFnc MaxBase64ToBinaryLengthDelegate)
324343
{
325344
if (Base64WithWhiteSpaceToBinary == null || DecodeFromBase64DelegateSafe == null || MaxBase64ToBinaryLengthDelegate == null)
@@ -375,8 +394,8 @@ protected static void MoreDecodeTestsUrl(Base64WithWhiteSpaceToBinary Base64With
375394
}
376395
}
377396

378-
[Fact]
379397
[Trait("Category", "sse")]
398+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
380399
public void MoreDecodeTestsUrlSSE()
381400
{
382401
MoreDecodeTestsUrl(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -427,8 +446,8 @@ public void RoundtripBase64Scalar()
427446
}
428447

429448

430-
[Fact]
431449
[Trait("Category", "sse")]
450+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
432451
public void RoundtripBase64SSE()
433452
{
434453
RoundtripBase64(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -471,8 +490,8 @@ public void RoundtripBase64UrlScalar()
471490
}
472491

473492

474-
[Fact]
475493
[Trait("Category", "sse")]
494+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
476495
public void RoundtripBase64UrlSSE()
477496
{
478497
RoundtripBase64Url(Base64.DecodeFromBase64SSE, Base64.DecodeFromBase64SSE, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -598,8 +617,8 @@ public void BadPaddingBase64Scalar()
598617
BadPaddingBase64(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
599618
}
600619

601-
[Fact]
602620
[Trait("Category", "sse")]
621+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
603622
public void BadPaddingBase64SSE()
604623
{
605624
BadPaddingBase64(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -658,8 +677,8 @@ public void DoomedBase64RoundtripScalar()
658677
DoomedBase64Roundtrip(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
659678
}
660679

661-
[Fact]
662680
[Trait("Category", "sse")]
681+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
663682
public void DoomedBase64RoundtripSSE()
664683
{
665684
DoomedBase64Roundtrip(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -719,8 +738,8 @@ public void TruncatedDoomedBase64RoundtripScalar()
719738
TruncatedDoomedBase64Roundtrip(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
720739
}
721740

722-
[Fact]
723741
[Trait("Category", "sse")]
742+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
724743
public void TruncatedDoomedBase64RoundtripSSE()
725744
{
726745
TruncatedDoomedBase64Roundtrip(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -785,8 +804,8 @@ public void RoundtripBase64WithSpacesScalar()
785804
RoundtripBase64WithSpaces(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
786805
}
787806

788-
[Fact]
789807
[Trait("Category", "sse")]
808+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
790809
public void RoundtripBase64WithSpacesSSE()
791810
{
792811
RoundtripBase64WithSpaces(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -853,8 +872,8 @@ public void AbortedSafeRoundtripBase64Scalar()
853872
AbortedSafeRoundtripBase64(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
854873
}
855874

856-
[Fact]
857875
[Trait("Category", "sse")]
876+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
858877
public void AbortedSafeRoundtripBase64SSE()
859878
{
860879
AbortedSafeRoundtripBase64(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -921,9 +940,8 @@ public void AbortedSafeRoundtripBase64WithSpacesScalar()
921940
AbortedSafeRoundtripBase64WithSpaces(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
922941
}
923942

924-
925-
[Fact]
926943
[Trait("Category", "sse")]
944+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
927945
public void AbortedSafeRoundtripBase64WithSpacesSSE()
928946
{
929947
AbortedSafeRoundtripBase64WithSpaces(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -994,8 +1012,8 @@ public void StreamingBase64RoundtripScalar()
9941012
}
9951013

9961014

997-
[Fact]
9981015
[Trait("Category", "sse")]
1016+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
9991017
public void StreamingBase64RoundtripSSE()
10001018
{
10011019
StreamingBase64Roundtrip(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -1064,8 +1082,8 @@ public void ReadmeTestScalar()
10641082
}
10651083

10661084

1067-
[Fact]
10681085
[Trait("Category", "sse")]
1086+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
10691087
public void ReadmeTestSSE()
10701088
{
10711089
ReadmeTest(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -1112,8 +1130,8 @@ public void ReadmeTestSafeScalar()
11121130
}
11131131

11141132

1115-
[Fact]
11161133
[Trait("Category", "sse")]
1134+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
11171135
public void ReadmeTestSafeSSE()
11181136
{
11191137
ReadmeTestSafe(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -1182,8 +1200,8 @@ public void DoomedBase64AtPos0Scalar()
11821200
DoomedBase64AtPos0(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
11831201
}
11841202

1185-
[Fact]
11861203
[Trait("Category", "sse")]
1204+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
11871205
public void DoomedBase64AtPos0SSE()
11881206
{
11891207
DoomedBase64AtPos0(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -1228,8 +1246,8 @@ public void EnronFilesTestScalar()
12281246
EnronFilesTest(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
12291247
}
12301248

1231-
[Fact]
12321249
[Trait("Category", "sse")]
1250+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
12331251
public void EnronFilesTestSSE()
12341252
{
12351253
EnronFilesTest(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -1271,8 +1289,8 @@ public void SwedenZoneBaseFileTestScalar()
12711289
SwedenZoneBaseFileTest(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
12721290
}
12731291

1274-
[Fact]
12751292
[Trait("Category", "sse")]
1293+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
12761294
public void SwedenZoneBaseFileTestSSE()
12771295
{
12781296
SwedenZoneBaseFileTest(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
@@ -1351,8 +1369,8 @@ public void DoomedPartialBufferScalar()
13511369
DoomedPartialBuffer(Base64.Base64WithWhiteSpaceToBinaryScalar, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);
13521370
}
13531371

1354-
[Fact]
13551372
[Trait("Category", "sse")]
1373+
[FactOnSystemRequirementAttribute(TestSystemRequirements.X64Sse)]
13561374
public void DoomedPartialBufferSSE()
13571375
{
13581376
DoomedPartialBuffer(Base64.DecodeFromBase64SSE, Base64.SafeBase64ToBinaryWithWhiteSpace, Base64.MaximalBinaryLengthFromBase64Scalar);

0 commit comments

Comments
 (0)