diff --git a/apiCount.include.md b/apiCount.include.md index 9512f8bc..90cae835 100644 --- a/apiCount.include.md +++ b/apiCount.include.md @@ -1,28 +1,28 @@ -**API count: 1151** +**API count: 1153** ### Per Target Framework | Target | APIs | | -- | -- | -| `net461` | 1059 | -| `net462` | 1059 | -| `net47` | 1058 | -| `net471` | 1057 | -| `net472` | 1053 | -| `net48` | 1053 | -| `net481` | 1053 | -| `netstandard2.0` | 1055 | -| `netstandard2.1` | 888 | -| `netcoreapp2.0` | 978 | -| `netcoreapp2.1` | 899 | -| `netcoreapp2.2` | 899 | -| `netcoreapp3.0` | 860 | -| `netcoreapp3.1` | 859 | -| `net5.0` | 737 | -| `net6.0` | 633 | -| `net7.0` | 492 | -| `net8.0` | 371 | -| `net9.0` | 241 | +| `net461` | 1061 | +| `net462` | 1061 | +| `net47` | 1060 | +| `net471` | 1059 | +| `net472` | 1055 | +| `net48` | 1055 | +| `net481` | 1055 | +| `netstandard2.0` | 1057 | +| `netstandard2.1` | 890 | +| `netcoreapp2.0` | 980 | +| `netcoreapp2.1` | 901 | +| `netcoreapp2.2` | 901 | +| `netcoreapp3.0` | 862 | +| `netcoreapp3.1` | 861 | +| `net5.0` | 739 | +| `net6.0` | 635 | +| `net7.0` | 494 | +| `net8.0` | 373 | +| `net9.0` | 243 | | `net10.0` | 182 | | `net11.0` | 58 | -| `uap10.0` | 1045 | +| `uap10.0` | 1047 | diff --git a/api_list.include.md b/api_list.include.md index 4100cb2d..faa11269 100644 --- a/api_list.include.md +++ b/api_list.include.md @@ -711,9 +711,17 @@ #### IPAddress + * `bool IsValid(ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.isvalid?view=net-11.0) + * Note: Copies the span to a string first, so this allocates where the BCL works straight from the span. + * `bool IsValidUtf8(ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.isvalidutf8?view=net-11.0) + * Note: Decodes the bytes to a string first, so this allocates where the BCL works straight from the UTF-8. * `IPAddress Parse(ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.parse?view=net-11.0#system-net-ipaddress-parse(system-readonlyspan((system-char)))) + * Note: Copies the span to a string first, so this allocates where the BCL works straight from the span. * `bool TryParse(ReadOnlySpan, IPAddress?)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.tryparse?view=net-11.0#system-net-ipaddress-tryparse(system-readonlyspan((system-byte))-system-net-ipaddress@)) + * Note: Decodes the bytes to a string first, so this allocates where the BCL works straight from the UTF-8. + * Note: The matching Parse(ReadOnlySpan) is not polyfilled, since it would collide with Guid.Parse(ReadOnlySpan); two static extension members with the same signature cannot coexist on one class. * `bool TryParse(ReadOnlySpan, IPAddress?)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.tryparse?view=net-11.0#system-net-ipaddress-tryparse(system-readonlyspan((system-char))-system-net-ipaddress@)) + * Note: Copies the span to a string first, so this allocates where the BCL works straight from the span. #### IReadOnlyDictionary diff --git a/assemblySize.include.md b/assemblySize.include.md index 0721e35c..c9383394 100644 --- a/assemblySize.include.md +++ b/assemblySize.include.md @@ -2,25 +2,25 @@ | | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability | |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------| -| netstandard2.0 | 8.0KB | 383.5KB | +375.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| netstandard2.1 | 8.5KB | 339.0KB | +330.5KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | -| net461 | 8.5KB | 382.5KB | +374.0KB | +8.5KB | +6.0KB | +8.5KB | +13.0KB | -| net462 | 7.0KB | 386.0KB | +379.0KB | +8.5KB | +6.5KB | +9.0KB | +13.0KB | -| net47 | 7.0KB | 385.5KB | +378.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net471 | 8.5KB | 384.5KB | +376.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net472 | 8.5KB | 383.5KB | +375.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| net48 | 8.5KB | 383.5KB | +375.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| net481 | 8.5KB | 383.5KB | +375.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| netcoreapp2.0 | 9.0KB | 362.5KB | +353.5KB | +7.5KB | +5.5KB | +8.0KB | +12.5KB | -| netcoreapp2.1 | 9.0KB | 342.0KB | +333.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | -| netcoreapp2.2 | 9.0KB | 342.0KB | +333.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | -| netcoreapp3.0 | 9.5KB | 340.5KB | +331.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| netcoreapp3.1 | 9.5KB | 338.5KB | +329.0KB | +9.0KB | +6.5KB | +9.5KB | +14.0KB | -| net5.0 | 9.5KB | 304.5KB | +295.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| net6.0 | 10.0KB | 245.5KB | +235.5KB | +9.5KB | +6.5KB | +512bytes | +3.0KB | -| net7.0 | 10.0KB | 214.0KB | +204.0KB | +9.5KB | +5.5KB | +512bytes | +3.5KB | -| net8.0 | 9.5KB | 184.5KB | +175.0KB | +8.5KB | +512bytes | +512bytes | +3.5KB | -| net9.0 | 9.5KB | 116.5KB | +107.0KB | +8.5KB | | +512bytes | +3.5KB | +| netstandard2.0 | 8.0KB | 384.0KB | +376.0KB | +8.5KB | +6.0KB | +8.5KB | +13.0KB | +| netstandard2.1 | 8.5KB | 339.5KB | +331.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net461 | 8.5KB | 382.5KB | +374.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net462 | 7.0KB | 386.0KB | +379.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net47 | 7.0KB | 386.0KB | +379.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | +| net471 | 8.5KB | 385.0KB | +376.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net472 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net48 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net481 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp2.0 | 9.0KB | 363.0KB | +354.0KB | +7.5KB | +5.0KB | +7.5KB | +12.0KB | +| netcoreapp2.1 | 9.0KB | 342.5KB | +333.5KB | +8.5KB | +6.0KB | +9.0KB | +13.5KB | +| netcoreapp2.2 | 9.0KB | 342.5KB | +333.5KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp3.0 | 9.5KB | 340.5KB | +331.0KB | +9.0KB | +6.5KB | +9.5KB | +14.0KB | +| netcoreapp3.1 | 9.5KB | 339.0KB | +329.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net5.0 | 9.5KB | 304.5KB | +295.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | +| net6.0 | 10.0KB | 245.5KB | +235.5KB | +9.5KB | +7.0KB | +512bytes | +3.5KB | +| net7.0 | 10.0KB | 214.0KB | +204.0KB | +9.5KB | +6.0KB | +512bytes | +3.5KB | +| net8.0 | 9.5KB | 185.0KB | +175.5KB | +8.0KB | | +512bytes | +3.0KB | +| net9.0 | 9.5KB | 117.0KB | +107.5KB | +8.0KB | | +512bytes | +3.0KB | | net10.0 | 10.0KB | 93.5KB | +83.5KB | +8.5KB | | +512bytes | +3.0KB | | net11.0 | 10.0KB | 21.0KB | +11.0KB | +9.0KB | | +512bytes | +3.5KB | @@ -29,24 +29,24 @@ | | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability | |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------| -| netstandard2.0 | 8.0KB | 558.5KB | +550.5KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| netstandard2.1 | 8.5KB | 486.9KB | +478.4KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | -| net461 | 8.5KB | 558.5KB | +550.0KB | +16.2KB | +7.7KB | +13.4KB | +18.4KB | -| net462 | 7.0KB | 562.0KB | +555.0KB | +16.2KB | +8.2KB | +13.9KB | +18.4KB | -| net47 | 7.0KB | 561.3KB | +554.3KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net471 | 8.5KB | 559.9KB | +551.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net472 | 8.5KB | 557.8KB | +549.3KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| net48 | 8.5KB | 557.8KB | +549.3KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| net481 | 8.5KB | 557.8KB | +549.3KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| netcoreapp2.0 | 9.0KB | 526.9KB | +517.9KB | +15.2KB | +7.2KB | +12.9KB | +17.9KB | -| netcoreapp2.1 | 9.0KB | 493.6KB | +484.6KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | -| netcoreapp2.2 | 9.0KB | 493.6KB | +484.6KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | -| netcoreapp3.0 | 9.5KB | 485.5KB | +476.0KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| netcoreapp3.1 | 9.5KB | 483.4KB | +473.9KB | +16.7KB | +8.2KB | +14.4KB | +19.4KB | -| net5.0 | 9.5KB | 432.0KB | +422.5KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| net6.0 | 10.0KB | 352.8KB | +342.8KB | +17.2KB | +8.2KB | +1.1KB | +3.7KB | -| net7.0 | 10.0KB | 304.5KB | +294.5KB | +17.1KB | +6.9KB | +1.1KB | +4.2KB | -| net8.0 | 9.5KB | 261.2KB | +251.7KB | +16.0KB | +811bytes | +1.1KB | +4.2KB | -| net9.0 | 9.5KB | 168.5KB | +159.0KB | +16.0KB | | +1.1KB | +4.2KB | +| netstandard2.0 | 8.0KB | 559.0KB | +551.0KB | +16.2KB | +7.7KB | +13.4KB | +18.4KB | +| netstandard2.1 | 8.5KB | 487.5KB | +479.0KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net461 | 8.5KB | 558.6KB | +550.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net462 | 7.0KB | 562.1KB | +555.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net47 | 7.0KB | 561.8KB | +554.8KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | +| net471 | 8.5KB | 560.5KB | +552.0KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net472 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net48 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net481 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp2.0 | 9.0KB | 527.5KB | +518.5KB | +15.2KB | +6.7KB | +12.4KB | +17.4KB | +| netcoreapp2.1 | 9.0KB | 494.2KB | +485.2KB | +16.2KB | +7.7KB | +13.9KB | +18.9KB | +| netcoreapp2.2 | 9.0KB | 494.2KB | +485.2KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp3.0 | 9.5KB | 485.6KB | +476.1KB | +16.7KB | +8.2KB | +14.4KB | +19.4KB | +| netcoreapp3.1 | 9.5KB | 484.0KB | +474.5KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net5.0 | 9.5KB | 432.1KB | +422.6KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | +| net6.0 | 10.0KB | 352.9KB | +342.9KB | +17.2KB | +8.7KB | +1.1KB | +4.2KB | +| net7.0 | 10.0KB | 304.6KB | +294.6KB | +17.1KB | +7.4KB | +1.1KB | +4.2KB | +| net8.0 | 9.5KB | 261.8KB | +252.3KB | +15.5KB | +299bytes | +1.1KB | +3.7KB | +| net9.0 | 9.5KB | 169.1KB | +159.6KB | +15.5KB | | +1.1KB | +3.7KB | | net10.0 | 10.0KB | 136.1KB | +126.1KB | +16.0KB | | +1.1KB | +3.7KB | | net11.0 | 10.0KB | 30.9KB | +20.9KB | +16.5KB | | +1.1KB | +4.2KB | diff --git a/readme.md b/readme.md index db34cd43..c602df7c 100644 --- a/readme.md +++ b/readme.md @@ -13,34 +13,34 @@ The package targets `netstandard2.0` and is designed to support the following ru * `uap10` -**API count: 1151** +**API count: 1153** ### Per Target Framework | Target | APIs | | -- | -- | -| `net461` | 1059 | -| `net462` | 1059 | -| `net47` | 1058 | -| `net471` | 1057 | -| `net472` | 1053 | -| `net48` | 1053 | -| `net481` | 1053 | -| `netstandard2.0` | 1055 | -| `netstandard2.1` | 888 | -| `netcoreapp2.0` | 978 | -| `netcoreapp2.1` | 899 | -| `netcoreapp2.2` | 899 | -| `netcoreapp3.0` | 860 | -| `netcoreapp3.1` | 859 | -| `net5.0` | 737 | -| `net6.0` | 633 | -| `net7.0` | 492 | -| `net8.0` | 371 | -| `net9.0` | 241 | +| `net461` | 1061 | +| `net462` | 1061 | +| `net47` | 1060 | +| `net471` | 1059 | +| `net472` | 1055 | +| `net48` | 1055 | +| `net481` | 1055 | +| `netstandard2.0` | 1057 | +| `netstandard2.1` | 890 | +| `netcoreapp2.0` | 980 | +| `netcoreapp2.1` | 901 | +| `netcoreapp2.2` | 901 | +| `netcoreapp3.0` | 862 | +| `netcoreapp3.1` | 861 | +| `net5.0` | 739 | +| `net6.0` | 635 | +| `net7.0` | 494 | +| `net8.0` | 373 | +| `net9.0` | 243 | | `net10.0` | 182 | | `net11.0` | 58 | -| `uap10.0` | 1045 | +| `uap10.0` | 1047 | @@ -96,25 +96,25 @@ This project uses features from the newest stable SDK and C# language. As such c | | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability | |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------| -| netstandard2.0 | 8.0KB | 383.5KB | +375.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| netstandard2.1 | 8.5KB | 339.0KB | +330.5KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | -| net461 | 8.5KB | 382.5KB | +374.0KB | +8.5KB | +6.0KB | +8.5KB | +13.0KB | -| net462 | 7.0KB | 386.0KB | +379.0KB | +8.5KB | +6.5KB | +9.0KB | +13.0KB | -| net47 | 7.0KB | 385.5KB | +378.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net471 | 8.5KB | 384.5KB | +376.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| net472 | 8.5KB | 383.5KB | +375.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| net48 | 8.5KB | 383.5KB | +375.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| net481 | 8.5KB | 383.5KB | +375.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| netcoreapp2.0 | 9.0KB | 362.5KB | +353.5KB | +7.5KB | +5.5KB | +8.0KB | +12.5KB | -| netcoreapp2.1 | 9.0KB | 342.0KB | +333.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | -| netcoreapp2.2 | 9.0KB | 342.0KB | +333.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | -| netcoreapp3.0 | 9.5KB | 340.5KB | +331.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | -| netcoreapp3.1 | 9.5KB | 338.5KB | +329.0KB | +9.0KB | +6.5KB | +9.5KB | +14.0KB | -| net5.0 | 9.5KB | 304.5KB | +295.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | -| net6.0 | 10.0KB | 245.5KB | +235.5KB | +9.5KB | +6.5KB | +512bytes | +3.0KB | -| net7.0 | 10.0KB | 214.0KB | +204.0KB | +9.5KB | +5.5KB | +512bytes | +3.5KB | -| net8.0 | 9.5KB | 184.5KB | +175.0KB | +8.5KB | +512bytes | +512bytes | +3.5KB | -| net9.0 | 9.5KB | 116.5KB | +107.0KB | +8.5KB | | +512bytes | +3.5KB | +| netstandard2.0 | 8.0KB | 384.0KB | +376.0KB | +8.5KB | +6.0KB | +8.5KB | +13.0KB | +| netstandard2.1 | 8.5KB | 339.5KB | +331.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net461 | 8.5KB | 382.5KB | +374.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net462 | 7.0KB | 386.0KB | +379.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net47 | 7.0KB | 386.0KB | +379.0KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | +| net471 | 8.5KB | 385.0KB | +376.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net472 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net48 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net481 | 8.5KB | 383.5KB | +375.0KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp2.0 | 9.0KB | 363.0KB | +354.0KB | +7.5KB | +5.0KB | +7.5KB | +12.0KB | +| netcoreapp2.1 | 9.0KB | 342.5KB | +333.5KB | +8.5KB | +6.0KB | +9.0KB | +13.5KB | +| netcoreapp2.2 | 9.0KB | 342.5KB | +333.5KB | +8.5KB | +6.5KB | +9.0KB | +13.5KB | +| netcoreapp3.0 | 9.5KB | 340.5KB | +331.0KB | +9.0KB | +6.5KB | +9.5KB | +14.0KB | +| netcoreapp3.1 | 9.5KB | 339.0KB | +329.5KB | +9.0KB | +6.5KB | +9.0KB | +13.5KB | +| net5.0 | 9.5KB | 304.5KB | +295.0KB | +9.0KB | +6.5KB | +9.0KB | +14.0KB | +| net6.0 | 10.0KB | 245.5KB | +235.5KB | +9.5KB | +7.0KB | +512bytes | +3.5KB | +| net7.0 | 10.0KB | 214.0KB | +204.0KB | +9.5KB | +6.0KB | +512bytes | +3.5KB | +| net8.0 | 9.5KB | 185.0KB | +175.5KB | +8.0KB | | +512bytes | +3.0KB | +| net9.0 | 9.5KB | 117.0KB | +107.5KB | +8.0KB | | +512bytes | +3.0KB | | net10.0 | 10.0KB | 93.5KB | +83.5KB | +8.5KB | | +512bytes | +3.0KB | | net11.0 | 10.0KB | 21.0KB | +11.0KB | +9.0KB | | +512bytes | +3.5KB | @@ -123,25 +123,25 @@ This project uses features from the newest stable SDK and C# language. As such c | | Empty Assembly | With Polyfill | Diff | Ensure | ArgumentExceptions | StringInterpolation | Nullability | |----------------|----------------|---------------|-----------|-----------|--------------------|---------------------|-------------| -| netstandard2.0 | 8.0KB | 558.5KB | +550.5KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| netstandard2.1 | 8.5KB | 486.9KB | +478.4KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | -| net461 | 8.5KB | 558.5KB | +550.0KB | +16.2KB | +7.7KB | +13.4KB | +18.4KB | -| net462 | 7.0KB | 562.0KB | +555.0KB | +16.2KB | +8.2KB | +13.9KB | +18.4KB | -| net47 | 7.0KB | 561.3KB | +554.3KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net471 | 8.5KB | 559.9KB | +551.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| net472 | 8.5KB | 557.8KB | +549.3KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| net48 | 8.5KB | 557.8KB | +549.3KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| net481 | 8.5KB | 557.8KB | +549.3KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| netcoreapp2.0 | 9.0KB | 526.9KB | +517.9KB | +15.2KB | +7.2KB | +12.9KB | +17.9KB | -| netcoreapp2.1 | 9.0KB | 493.6KB | +484.6KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | -| netcoreapp2.2 | 9.0KB | 493.6KB | +484.6KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | -| netcoreapp3.0 | 9.5KB | 485.5KB | +476.0KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | -| netcoreapp3.1 | 9.5KB | 483.4KB | +473.9KB | +16.7KB | +8.2KB | +14.4KB | +19.4KB | -| net5.0 | 9.5KB | 432.0KB | +422.5KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | -| net6.0 | 10.0KB | 352.8KB | +342.8KB | +17.2KB | +8.2KB | +1.1KB | +3.7KB | -| net7.0 | 10.0KB | 304.5KB | +294.5KB | +17.1KB | +6.9KB | +1.1KB | +4.2KB | -| net8.0 | 9.5KB | 261.2KB | +251.7KB | +16.0KB | +811bytes | +1.1KB | +4.2KB | -| net9.0 | 9.5KB | 168.5KB | +159.0KB | +16.0KB | | +1.1KB | +4.2KB | +| netstandard2.0 | 8.0KB | 559.0KB | +551.0KB | +16.2KB | +7.7KB | +13.4KB | +18.4KB | +| netstandard2.1 | 8.5KB | 487.5KB | +479.0KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net461 | 8.5KB | 558.6KB | +550.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net462 | 7.0KB | 562.1KB | +555.1KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net47 | 7.0KB | 561.8KB | +554.8KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | +| net471 | 8.5KB | 560.5KB | +552.0KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net472 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net48 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net481 | 8.5KB | 557.9KB | +549.4KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp2.0 | 9.0KB | 527.5KB | +518.5KB | +15.2KB | +6.7KB | +12.4KB | +17.4KB | +| netcoreapp2.1 | 9.0KB | 494.2KB | +485.2KB | +16.2KB | +7.7KB | +13.9KB | +18.9KB | +| netcoreapp2.2 | 9.0KB | 494.2KB | +485.2KB | +16.2KB | +8.2KB | +13.9KB | +18.9KB | +| netcoreapp3.0 | 9.5KB | 485.6KB | +476.1KB | +16.7KB | +8.2KB | +14.4KB | +19.4KB | +| netcoreapp3.1 | 9.5KB | 484.0KB | +474.5KB | +16.7KB | +8.2KB | +13.9KB | +18.9KB | +| net5.0 | 9.5KB | 432.1KB | +422.6KB | +16.7KB | +8.2KB | +13.9KB | +19.4KB | +| net6.0 | 10.0KB | 352.9KB | +342.9KB | +17.2KB | +8.7KB | +1.1KB | +4.2KB | +| net7.0 | 10.0KB | 304.6KB | +294.6KB | +17.1KB | +7.4KB | +1.1KB | +4.2KB | +| net8.0 | 9.5KB | 261.8KB | +252.3KB | +15.5KB | +299bytes | +1.1KB | +3.7KB | +| net9.0 | 9.5KB | 169.1KB | +159.6KB | +15.5KB | | +1.1KB | +3.7KB | | net10.0 | 10.0KB | 136.1KB | +126.1KB | +16.0KB | | +1.1KB | +3.7KB | | net11.0 | 10.0KB | 30.9KB | +20.9KB | +16.5KB | | +1.1KB | +4.2KB | @@ -1326,9 +1326,17 @@ The class `Polyfill` includes the following extension methods: #### IPAddress + * `bool IsValid(ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.isvalid?view=net-11.0) + * Note: Copies the span to a string first, so this allocates where the BCL works straight from the span. + * `bool IsValidUtf8(ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.isvalidutf8?view=net-11.0) + * Note: Decodes the bytes to a string first, so this allocates where the BCL works straight from the UTF-8. * `IPAddress Parse(ReadOnlySpan)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.parse?view=net-11.0#system-net-ipaddress-parse(system-readonlyspan((system-char)))) + * Note: Copies the span to a string first, so this allocates where the BCL works straight from the span. * `bool TryParse(ReadOnlySpan, IPAddress?)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.tryparse?view=net-11.0#system-net-ipaddress-tryparse(system-readonlyspan((system-byte))-system-net-ipaddress@)) + * Note: Decodes the bytes to a string first, so this allocates where the BCL works straight from the UTF-8. + * Note: The matching Parse(ReadOnlySpan) is not polyfilled, since it would collide with Guid.Parse(ReadOnlySpan); two static extension members with the same signature cannot coexist on one class. * `bool TryParse(ReadOnlySpan, IPAddress?)` [reference](https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.tryparse?view=net-11.0#system-net-ipaddress-tryparse(system-readonlyspan((system-char))-system-net-ipaddress@)) + * Note: Copies the span to a string first, so this allocates where the BCL works straight from the span. #### IReadOnlyDictionary @@ -2560,7 +2568,7 @@ void ObjectDisposedExceptionExample(bool isDisposed) ObjectDisposedException.ThrowIf(isDisposed, typeof(Consume)); } ``` -snippet source | anchor +snippet source | anchor @@ -2579,7 +2587,7 @@ void EnsureExample(Order order, Customer customer, string customerId, string ema this.quantity = Ensure.NotNegativeOrZero(quantity); } ``` -snippet source | anchor +snippet source | anchor diff --git a/src/Consume/Consume.cs b/src/Consume/Consume.cs index f74a06b0..4fd2d0e5 100644 --- a/src/Consume/Consume.cs +++ b/src/Consume/Consume.cs @@ -228,6 +228,8 @@ void IPAddressUsage() ReadOnlySpan byteSpan = default; result = IPAddress.TryParse(byteSpan, out address); + result = IPAddress.IsValid(charSpan); + result = IPAddress.IsValidUtf8(byteSpan); } #endif diff --git a/src/Polyfill/IPAddressPolyfill.cs b/src/Polyfill/IPAddressPolyfill.cs index 7ee9df5c..e450452f 100644 --- a/src/Polyfill/IPAddressPolyfill.cs +++ b/src/Polyfill/IPAddressPolyfill.cs @@ -17,6 +17,7 @@ static partial class Polyfill /// Converts an IP address represented as a character span to an instance. /// //Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.parse?view=net-11.0#system-net-ipaddress-parse(system-readonlyspan((system-char))) + //Note: Copies the span to a string first, so this allocates where the BCL works straight from the span. public static IPAddress Parse(ReadOnlySpan ipString) => IPAddress.Parse(ipString.ToString()); @@ -24,6 +25,7 @@ public static IPAddress Parse(ReadOnlySpan ipString) => /// Determines whether a span of characters is a valid IP address. /// //Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.tryparse?view=net-11.0#system-net-ipaddress-tryparse(system-readonlyspan((system-char))-system-net-ipaddress@) + //Note: Copies the span to a string first, so this allocates where the BCL works straight from the span. public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out IPAddress? address) => IPAddress.TryParse(ipString.ToString(), out address); @@ -35,9 +37,27 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// Tries to parse a span of UTF-8 characters into a value. /// //Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.tryparse?view=net-11.0#system-net-ipaddress-tryparse(system-readonlyspan((system-byte))-system-net-ipaddress@) + //Note: Decodes the bytes to a string first, so this allocates where the BCL works straight from the UTF-8. + //Note: The matching Parse(ReadOnlySpan) is not polyfilled, since it would collide with Guid.Parse(ReadOnlySpan); two static extension members with the same signature cannot coexist on one class. public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + //Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.isvalid?view=net-11.0 + //Note: Copies the span to a string first, so this allocates where the BCL works straight from the span. + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + //Link: https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.isvalidutf8?view=net-11.0 + //Note: Decodes the bytes to a string first, so this allocates where the BCL works straight from the UTF-8. + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); + #endif } } diff --git a/src/Split/net461/IPAddressPolyfill.cs b/src/Split/net461/IPAddressPolyfill.cs index 5927c489..6ad306ca 100644 --- a/src/Split/net461/IPAddressPolyfill.cs +++ b/src/Split/net461/IPAddressPolyfill.cs @@ -25,6 +25,16 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net462/IPAddressPolyfill.cs b/src/Split/net462/IPAddressPolyfill.cs index 5927c489..6ad306ca 100644 --- a/src/Split/net462/IPAddressPolyfill.cs +++ b/src/Split/net462/IPAddressPolyfill.cs @@ -25,6 +25,16 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net47/IPAddressPolyfill.cs b/src/Split/net47/IPAddressPolyfill.cs index 5927c489..6ad306ca 100644 --- a/src/Split/net47/IPAddressPolyfill.cs +++ b/src/Split/net47/IPAddressPolyfill.cs @@ -25,6 +25,16 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net471/IPAddressPolyfill.cs b/src/Split/net471/IPAddressPolyfill.cs index 5927c489..6ad306ca 100644 --- a/src/Split/net471/IPAddressPolyfill.cs +++ b/src/Split/net471/IPAddressPolyfill.cs @@ -25,6 +25,16 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net472/IPAddressPolyfill.cs b/src/Split/net472/IPAddressPolyfill.cs index 5927c489..6ad306ca 100644 --- a/src/Split/net472/IPAddressPolyfill.cs +++ b/src/Split/net472/IPAddressPolyfill.cs @@ -25,6 +25,16 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net48/IPAddressPolyfill.cs b/src/Split/net48/IPAddressPolyfill.cs index 5927c489..6ad306ca 100644 --- a/src/Split/net48/IPAddressPolyfill.cs +++ b/src/Split/net48/IPAddressPolyfill.cs @@ -25,6 +25,16 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net481/IPAddressPolyfill.cs b/src/Split/net481/IPAddressPolyfill.cs index 5927c489..6ad306ca 100644 --- a/src/Split/net481/IPAddressPolyfill.cs +++ b/src/Split/net481/IPAddressPolyfill.cs @@ -25,6 +25,16 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net5.0/IPAddressPolyfill.cs b/src/Split/net5.0/IPAddressPolyfill.cs index de0e21ac..a268d5da 100644 --- a/src/Split/net5.0/IPAddressPolyfill.cs +++ b/src/Split/net5.0/IPAddressPolyfill.cs @@ -15,6 +15,16 @@ static partial class Polyfill /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net6.0/IPAddressPolyfill.cs b/src/Split/net6.0/IPAddressPolyfill.cs index de0e21ac..a268d5da 100644 --- a/src/Split/net6.0/IPAddressPolyfill.cs +++ b/src/Split/net6.0/IPAddressPolyfill.cs @@ -15,6 +15,16 @@ static partial class Polyfill /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net7.0/IPAddressPolyfill.cs b/src/Split/net7.0/IPAddressPolyfill.cs index de0e21ac..a268d5da 100644 --- a/src/Split/net7.0/IPAddressPolyfill.cs +++ b/src/Split/net7.0/IPAddressPolyfill.cs @@ -15,6 +15,16 @@ static partial class Polyfill /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net8.0/IPAddressPolyfill.cs b/src/Split/net8.0/IPAddressPolyfill.cs index de0e21ac..a268d5da 100644 --- a/src/Split/net8.0/IPAddressPolyfill.cs +++ b/src/Split/net8.0/IPAddressPolyfill.cs @@ -15,6 +15,16 @@ static partial class Polyfill /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/net9.0/IPAddressPolyfill.cs b/src/Split/net9.0/IPAddressPolyfill.cs index de0e21ac..a268d5da 100644 --- a/src/Split/net9.0/IPAddressPolyfill.cs +++ b/src/Split/net9.0/IPAddressPolyfill.cs @@ -15,6 +15,16 @@ static partial class Polyfill /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/netcoreapp2.0/IPAddressPolyfill.cs b/src/Split/netcoreapp2.0/IPAddressPolyfill.cs index 5927c489..6ad306ca 100644 --- a/src/Split/netcoreapp2.0/IPAddressPolyfill.cs +++ b/src/Split/netcoreapp2.0/IPAddressPolyfill.cs @@ -25,6 +25,16 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/netcoreapp2.1/IPAddressPolyfill.cs b/src/Split/netcoreapp2.1/IPAddressPolyfill.cs index de0e21ac..a268d5da 100644 --- a/src/Split/netcoreapp2.1/IPAddressPolyfill.cs +++ b/src/Split/netcoreapp2.1/IPAddressPolyfill.cs @@ -15,6 +15,16 @@ static partial class Polyfill /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/netcoreapp2.2/IPAddressPolyfill.cs b/src/Split/netcoreapp2.2/IPAddressPolyfill.cs index de0e21ac..a268d5da 100644 --- a/src/Split/netcoreapp2.2/IPAddressPolyfill.cs +++ b/src/Split/netcoreapp2.2/IPAddressPolyfill.cs @@ -15,6 +15,16 @@ static partial class Polyfill /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/netcoreapp3.0/IPAddressPolyfill.cs b/src/Split/netcoreapp3.0/IPAddressPolyfill.cs index de0e21ac..a268d5da 100644 --- a/src/Split/netcoreapp3.0/IPAddressPolyfill.cs +++ b/src/Split/netcoreapp3.0/IPAddressPolyfill.cs @@ -15,6 +15,16 @@ static partial class Polyfill /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/netcoreapp3.1/IPAddressPolyfill.cs b/src/Split/netcoreapp3.1/IPAddressPolyfill.cs index de0e21ac..a268d5da 100644 --- a/src/Split/netcoreapp3.1/IPAddressPolyfill.cs +++ b/src/Split/netcoreapp3.1/IPAddressPolyfill.cs @@ -15,6 +15,16 @@ static partial class Polyfill /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/netstandard2.0/IPAddressPolyfill.cs b/src/Split/netstandard2.0/IPAddressPolyfill.cs index 5927c489..6ad306ca 100644 --- a/src/Split/netstandard2.0/IPAddressPolyfill.cs +++ b/src/Split/netstandard2.0/IPAddressPolyfill.cs @@ -25,6 +25,16 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/netstandard2.1/IPAddressPolyfill.cs b/src/Split/netstandard2.1/IPAddressPolyfill.cs index de0e21ac..a268d5da 100644 --- a/src/Split/netstandard2.1/IPAddressPolyfill.cs +++ b/src/Split/netstandard2.1/IPAddressPolyfill.cs @@ -15,6 +15,16 @@ static partial class Polyfill /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Split/uap10.0/IPAddressPolyfill.cs b/src/Split/uap10.0/IPAddressPolyfill.cs index 5927c489..6ad306ca 100644 --- a/src/Split/uap10.0/IPAddressPolyfill.cs +++ b/src/Split/uap10.0/IPAddressPolyfill.cs @@ -25,6 +25,16 @@ public static bool TryParse(ReadOnlySpan ipString, [NotNullWhen(true)] out /// public static bool TryParse(ReadOnlySpan utf8Text, [NotNullWhen(true)] out IPAddress? result) => IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out result); + /// + /// Determines whether the specified character span represents a valid IP address. + /// + public static bool IsValid(ReadOnlySpan ipSpan) => + IPAddress.TryParse(ipSpan.ToString(), out _); + /// + /// Determines whether the specified UTF-8 span represents a valid IP address. + /// + public static bool IsValidUtf8(ReadOnlySpan utf8Text) => + IPAddress.TryParse(Encoding.UTF8.GetString(utf8Text), out _); } } #endif diff --git a/src/Tests/IPAddressPolyfillTests.cs b/src/Tests/IPAddressPolyfillTests.cs new file mode 100644 index 00000000..38fe3d6c --- /dev/null +++ b/src/Tests/IPAddressPolyfillTests.cs @@ -0,0 +1,99 @@ +#if FeatureMemory + +using System.Net; +using System.Text; + +// Runs on every target, so net10.0 and later validate the BCL and everything below the polyfill. +// IPAddress.TryParse(string) is the oracle: it has been on every framework Polyfill supports and +// the BCL's own IsValid agrees with it on every input tried here. +public class IPAddressPolyfillTests +{ + static string[] corpus = + [ + "", + " ", + "1.2.3.4", + " 1.2.3.4", + "1.2.3.4 ", + "1.2.3", + "1.2", + "1", + "0.0.0.0", + "255.255.255.255", + "256.1.1.1", + "1.2.3.4.5", + "01.02.03.04", + "1.2.3.-4", + "1..2.3", + "1.2.3.", + "::1", + "::", + "fe80::1", + "fe80::1%eth0", + "fe80::1%12", + "2001:db8::ff00:42:8329", + ":::", + "1:2:3:4:5:6:7:8:9", + "::ffff:1.2.3.4", + "[::1]", + "abc", + "1.2.3.4:80", + "999.999.999.999", + "١.٢.٣.٤", + "1.2.3.4" + ]; + + [Test] + public async Task IsValid_MatchesTryParse() + { + foreach (var value in corpus) + { + var expected = IPAddress.TryParse(value, out _); + await Assert.That(IsValid(value)).IsEqualTo(expected); + } + } + + [Test] + public async Task IsValidUtf8_MatchesIsValid() + { + foreach (var value in corpus) + { + var expected = IPAddress.TryParse(value, out _); + await Assert.That(IsValidUtf8(Encoding.UTF8.GetBytes(value))).IsEqualTo(expected); + } + } + + [Test] + public async Task IsValidUtf8_RejectsMalformedUtf8() + { + byte[][] malformed = + [ + [0xFF], + [0xC3], + [0xC3, 0x28], + [0x31, 0xFF, 0x2E], + [0xED, 0xA0, 0x80] + ]; + + foreach (var bytes in malformed) + { + await Assert.That(IsValidUtf8(bytes)).IsFalse(); + } + } + + [Test] + public async Task EmptySpansAreNotValid() + { + await Assert.That(IsValid(string.Empty)).IsFalse(); + await Assert.That(IsValidUtf8([])).IsFalse(); + } + + // the spans stay inside these helpers, so nothing ref struct shaped lives across an await + static bool IsValid(string value) => + IPAddress.IsValid(value.AsSpan()); + + static bool IsValidUtf8(byte[] utf8) => + IPAddress.IsValidUtf8(utf8); +} + +#endif