Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 0029b32

Browse files
Paxxistephentoub
authored andcommitted
Implement Span overloads for IPAddress class
See issue #22607 This adds public IPAddress(ReadOnlySpan<byte> address) public IPAddress(ReadOnlySpan<byte> address, long scopeid) public bool TryWriteBytes(Span<byte> destination, out int bytesWritten) public static IPAddress Parse(ReadOnlySpan<char> ipSpan) public static bool TryParse(ReadOnlySpan<char> ipSpan, out IPAddress address) public static bool TryFormat(Span<char> destination, out int bytesWritten)
1 parent 7a67354 commit 0029b32

16 files changed

+915
-352
lines changed

src/System.Net.Primitives/ref/System.Net.Primitives.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ public partial class IPAddress
191191
public static readonly System.Net.IPAddress Loopback;
192192
public static readonly System.Net.IPAddress None;
193193
public IPAddress(byte[] address) { }
194+
public IPAddress(ReadOnlySpan<byte> address) { }
194195
public IPAddress(byte[] address, long scopeid) { }
196+
public IPAddress(ReadOnlySpan<byte> address, long scopeid) { }
195197
public IPAddress(long newAddress) { }
196198
public System.Net.Sockets.AddressFamily AddressFamily { get { throw null; } }
197199
public bool IsIPv4MappedToIPv6 { get { throw null; } }
@@ -202,6 +204,7 @@ public IPAddress(long newAddress) { }
202204
public long ScopeId { get { throw null; } set { } }
203205
public override bool Equals(object comparand) { throw null; }
204206
public byte[] GetAddressBytes() { throw null; }
207+
public bool TryWriteBytes(Span<byte> destination, out int bytesWritten) { throw null; }
205208
public override int GetHashCode() { throw null; }
206209
public static short HostToNetworkOrder(short host) { throw null; }
207210
public static int HostToNetworkOrder(int host) { throw null; }
@@ -213,8 +216,11 @@ public IPAddress(long newAddress) { }
213216
public static int NetworkToHostOrder(int network) { throw null; }
214217
public static long NetworkToHostOrder(long network) { throw null; }
215218
public static System.Net.IPAddress Parse(string ipString) { throw null; }
219+
public static System.Net.IPAddress Parse(ReadOnlySpan<char> ipString) { throw null; }
216220
public override string ToString() { throw null; }
221+
public bool TryFormat(Span<char> destination, out int charsWritten) { throw null; }
217222
public static bool TryParse(string ipString, out System.Net.IPAddress address) { throw null; }
223+
public static bool TryParse(ReadOnlySpan<char> ipString, out System.Net.IPAddress address) { throw null; }
218224
[Obsolete("This property has been deprecated. It is address family dependent. Please use IPAddress.Equals method to perform comparisons. http://go.microsoft.com/fwlink/?linkid=14202")]
219225
public long Address { get { throw null; } set { } }
220226
}

src/System.Net.Primitives/ref/System.Net.Primitives.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
</ItemGroup>
1414
<ItemGroup>
1515
<ProjectReference Include="..\..\Microsoft.Win32.Primitives\ref\Microsoft.Win32.Primitives.csproj" />
16+
<ProjectReference Include="..\..\System.Memory\ref\System.Memory.csproj" />
1617
<ProjectReference Include="..\..\System.Runtime\ref\System.Runtime.csproj" />
1718
<ProjectReference Include="..\..\System.Runtime.InteropServices\ref\System.Runtime.InteropServices.csproj" />
1819
<ProjectReference Include="..\..\System.Runtime.Handles\ref\System.Runtime.Handles.csproj" />
1920
</ItemGroup>
2021
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
21-
</Project>
22+
</Project>

src/System.Net.Primitives/src/System.Net.Primitives.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@
198198
<Reference Include="System.Diagnostics.Debug" />
199199
<Reference Include="System.Diagnostics.Tracing" />
200200
<Reference Include="System.Resources.ResourceManager" />
201+
<Reference Include="System.Memory" />
201202
<Reference Include="System.Runtime" />
202203
<Reference Include="System.Runtime.Extensions" />
203204
<Reference Include="System.Runtime.InteropServices" />

src/System.Net.Primitives/src/System/Net/IPAddress.cs

Lines changed: 87 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,13 @@ public IPAddress(long newAddress)
121121
/// Constructor for an IPv6 Address with a specified Scope.
122122
/// </para>
123123
/// </devdoc>
124-
public IPAddress(byte[] address, long scopeid)
124+
public IPAddress(byte[] address, long scopeid) :
125+
this(new ReadOnlySpan<byte>(address ?? throw new ArgumentNullException(nameof(address))), scopeid)
125126
{
126-
if (address == null)
127-
{
128-
throw new ArgumentNullException(nameof(address));
129-
}
127+
}
130128

129+
public IPAddress(ReadOnlySpan<byte> address, long scopeid)
130+
{
131131
if (address.Length != IPAddressParserStatics.IPv6AddressBytes)
132132
{
133133
throw new ArgumentException(SR.dns_bad_ip_address, nameof(address));
@@ -200,12 +200,13 @@ private IPAddress(ushort[] numbers, uint scopeid)
200200
/// Constructor for IPv4 and IPv6 Address.
201201
/// </para>
202202
/// </devdoc>
203-
public IPAddress(byte[] address)
203+
public IPAddress(byte[] address) :
204+
this(new ReadOnlySpan<byte>(address ?? throw new ArgumentNullException(nameof(address))))
205+
{
206+
}
207+
208+
public IPAddress(ReadOnlySpan<byte> address)
204209
{
205-
if (address == null)
206-
{
207-
throw new ArgumentNullException(nameof(address));
208-
}
209210
if (address.Length != IPAddressParserStatics.IPv4AddressBytes && address.Length != IPAddressParserStatics.IPv6AddressBytes)
210211
{
211212
throw new ArgumentException(SR.dns_bad_ip_address, nameof(address));
@@ -262,48 +263,99 @@ internal IPAddress(int newAddress)
262263
/// </devdoc>
263264
public static bool TryParse(string ipString, out IPAddress address)
264265
{
265-
address = IPAddressParser.Parse(ipString, true);
266+
if (ipString == null)
267+
{
268+
address = null;
269+
return false;
270+
}
271+
272+
address = IPAddressParser.Parse(ipString, tryParse: true);
273+
return (address != null);
274+
}
275+
276+
public static bool TryParse(ReadOnlySpan<char> ipSpan, out IPAddress address)
277+
{
278+
address = IPAddressParser.Parse(ipSpan, tryParse: true);
266279
return (address != null);
267280
}
268281

269282
public static IPAddress Parse(string ipString)
270283
{
271-
return IPAddressParser.Parse(ipString, false);
284+
if (ipString == null)
285+
{
286+
throw new ArgumentNullException(nameof(ipString));
287+
}
288+
289+
return IPAddressParser.Parse(ipString, tryParse: false);
272290
}
273291

274-
/// <devdoc>
275-
/// <para>
276-
/// Provides a copy of the IPAddress internals as an array of bytes.
277-
/// </para>
278-
/// </devdoc>
279-
public byte[] GetAddressBytes()
292+
public static IPAddress Parse(ReadOnlySpan<char> ipSpan)
293+
{
294+
return IPAddressParser.Parse(ipSpan, tryParse: false);
295+
}
296+
297+
public bool TryWriteBytes(Span<byte> destination, out int bytesWritten)
280298
{
281-
byte[] bytes;
282299
if (IsIPv6)
283300
{
284301
Debug.Assert(_numbers != null && _numbers.Length == NumberOfLabels);
285302

286-
bytes = new byte[IPAddressParserStatics.IPv6AddressBytes];
303+
if (destination.Length < IPAddressParserStatics.IPv6AddressBytes)
304+
{
305+
bytesWritten = 0;
306+
return false;
307+
}
308+
287309
int j = 0;
288310
for (int i = 0; i < NumberOfLabels; i++)
289311
{
290-
bytes[j++] = (byte)((_numbers[i] >> 8) & 0xFF);
291-
bytes[j++] = (byte)((_numbers[i]) & 0xFF);
312+
destination[j++] = (byte)((_numbers[i] >> 8) & 0xFF);
313+
destination[j++] = (byte)((_numbers[i]) & 0xFF);
292314
}
315+
316+
bytesWritten = IPAddressParserStatics.IPv6AddressBytes;
293317
}
294318
else
295319
{
296-
uint address = PrivateAddress;
297-
bytes = new byte[IPAddressParserStatics.IPv4AddressBytes];
320+
if (destination.Length < IPAddressParserStatics.IPv4AddressBytes)
321+
{
322+
bytesWritten = 0;
323+
return false;
324+
}
298325

326+
uint address = PrivateAddress;
299327
unchecked
300328
{
301-
bytes[0] = (byte)(address);
302-
bytes[1] = (byte)(address >> 8);
303-
bytes[2] = (byte)(address >> 16);
304-
bytes[3] = (byte)(address >> 24);
329+
destination[0] = (byte)(address);
330+
destination[1] = (byte)(address >> 8);
331+
destination[2] = (byte)(address >> 16);
332+
destination[3] = (byte)(address >> 24);
305333
}
334+
335+
bytesWritten = IPAddressParserStatics.IPv4AddressBytes;
336+
}
337+
338+
return true;
339+
}
340+
/// <devdoc>
341+
/// <para>
342+
/// Provides a copy of the IPAddress internals as an array of bytes.
343+
/// </para>
344+
/// </devdoc>
345+
public byte[] GetAddressBytes()
346+
{
347+
if (IsIPv6)
348+
{
349+
Debug.Assert(_numbers != null && _numbers.Length == NumberOfLabels);
306350
}
351+
352+
int length = IsIPv6 ? IPAddressParserStatics.IPv6AddressBytes : IPAddressParserStatics.IPv4AddressBytes;
353+
var bytes = new byte[length];
354+
355+
bool result = TryWriteBytes(new Span<byte>(bytes), out int bytesWritten);
356+
357+
Debug.Assert(result);
358+
307359
return bytes;
308360
}
309361

@@ -369,6 +421,13 @@ public override string ToString()
369421
return _toString;
370422
}
371423

424+
public bool TryFormat(Span<char> destination, out int charsWritten)
425+
{
426+
return IsIPv4 ?
427+
IPAddressParser.IPv4AddressToString(PrivateAddress, destination, out charsWritten) :
428+
IPAddressParser.IPv6AddressToString(_numbers, PrivateScopeId, destination, out charsWritten);
429+
}
430+
372431
public static long HostToNetworkOrder(long host)
373432
{
374433
#if BIGENDIAN

0 commit comments

Comments
 (0)