Skip to content

Commit 0673e8c

Browse files
authored
feat/operator-add-int (#365)
* Feat: operator add IPNetwork, int * Feat: operation -minus * Fix: edge case with overflow
1 parent e4829c1 commit 0673e8c

File tree

5 files changed

+298
-83
lines changed

5 files changed

+298
-83
lines changed

src/System.Net.IPNetwork/IPNetwork2Members.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public IPAddress Broadcast
9393
return ToIPAddress(this.InternalBroadcast, this.family);
9494
}
9595
}
96-
96+
9797
/// <summary>
9898
/// Gets first usable IPAddress in Network.
9999
/// </summary>
@@ -127,7 +127,31 @@ public IPAddress LastUsable
127127
return ToIPAddress(last, this.family);
128128
}
129129
}
130-
130+
131+
/// <summary>
132+
/// Gets first IPAddress in Network.
133+
/// </summary>
134+
public IPAddress First
135+
{
136+
get
137+
{
138+
BigInteger first = this.InternalNetwork;
139+
return ToIPAddress(first, this.family);
140+
}
141+
}
142+
143+
/// <summary>
144+
/// Gets last IPAddress in Network.
145+
/// </summary>
146+
public IPAddress Last
147+
{
148+
get
149+
{
150+
BigInteger last = this.InternalBroadcast;
151+
return ToIPAddress(last, this.family);
152+
}
153+
}
154+
131155
/// <summary>
132156
/// Gets number of usable IPAddress in Network.
133157
///

src/System.Net.IPNetwork/IPNetwork2Operators.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,80 @@ public sealed partial class IPNetwork2
103103
}
104104
return [left, right];
105105
}
106+
107+
/// <summary>
108+
/// Behavior
109+
/// The addition operator (+) performs the following operations:
110+
/// Network Expansion: Adds the specified number of IP addresses to the network range
111+
/// Optimal Grouping: Attempts to create the most efficient network representation
112+
/// Multiple Networks: When a single contiguous network cannot represent the result, returns multiple networks
113+
/// CIDR Optimization: Automatically calculates the appropriate subnet mask for the expanded range
114+
/// </summary>
115+
/// <param name="left">left instance.</param>
116+
/// <param name="add">number.</param>
117+
/// <returns>Adds the specified number of IP addresses to the network range.</returns>
118+
public static IEnumerable<IPNetwork2> operator +(IPNetwork2 left, int add)
119+
{
120+
if (add < 0)
121+
{
122+
return left - (add * -1);
123+
}
124+
if (add == 0)
125+
{
126+
return new[] { left };
127+
}
128+
var start = ToBigInteger(left.First);
129+
var last = ToBigInteger(left.Last);
130+
var end = last+ add;
131+
132+
if (end < start)
133+
{
134+
return [];
135+
}
136+
137+
var startIp = ToIPAddress(start, left.AddressFamily);
138+
var endIp = ToIPAddress(end, left.AddressFamily);
139+
140+
var uintStart = ToBigInteger(startIp);
141+
var uintEnd = ToBigInteger(endIp);
142+
143+
if (uintEnd <= uintStart)
144+
{
145+
throw new OverflowException("IPNetwork overflow");
146+
}
147+
InternalParseRange(true, startIp, endIp, out IEnumerable<IPNetwork2> networks);
148+
return networks;
149+
}
150+
151+
/// <summary>
152+
/// Add IPNetwork.
153+
/// </summary>
154+
/// <param name="left">left instance.</param>
155+
/// <param name="subtract">number.</param>
156+
/// <returns>Try to supernet two consecutive cidr equal subnet into a single one, otherwise return both netowkrs.</returns>
157+
public static IEnumerable<IPNetwork2> operator -(IPNetwork2 left, int subtract)
158+
{
159+
if (subtract < 0)
160+
{
161+
return left + (subtract * -1);
162+
}
163+
if (subtract == 0)
164+
{
165+
return new[] { left };
166+
}
167+
var start = ToBigInteger(left.First);
168+
var last = ToBigInteger(left.Last);
169+
var end = last- subtract;
170+
171+
if (end < start)
172+
{
173+
return [];
174+
}
175+
176+
var startIp = ToIPAddress(start, left.AddressFamily);
177+
var endIp = ToIPAddress(end, left.AddressFamily);
178+
179+
InternalParseRange(true, startIp, endIp, out IEnumerable<IPNetwork2> networks);
180+
return networks;
181+
}
106182
}

src/TestProject/BigIntegerToUnitTest.cs

Lines changed: 61 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -16,136 +16,136 @@ public class BigIntegerToUnitTest
1616
[TestMethod]
1717
public void TestToOctalString1()
1818
{
19-
byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
20-
var convertme = new BigInteger(bytes);
21-
string result = convertme.ToOctalString();
19+
byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
20+
var convertme = new BigInteger(bytes);
21+
string result = convertme.ToOctalString();
2222

23-
Assert.AreEqual("037777777777", result);
24-
}
23+
Assert.AreEqual("037777777777", result);
24+
}
2525

2626
/// <summary>
2727
/// Test.
2828
/// </summary>
2929
[TestMethod]
3030
public void TestToOctalString3()
3131
{
32-
var bigi = BigInteger.Parse("1048576");
33-
bigi++;
34-
string result = bigi.ToOctalString();
32+
var bigi = BigInteger.Parse("1048576");
33+
bigi++;
34+
string result = bigi.ToOctalString();
3535

36-
Assert.AreEqual("04000001", result);
37-
}
36+
Assert.AreEqual("04000001", result);
37+
}
3838

3939
/// <summary>
4040
/// Test.
4141
/// </summary>
4242
[TestMethod]
4343
public void TestToOctalString01()
4444
{
45-
BigInteger bigi = BigInteger.Zero;
46-
bigi++;
47-
string result = bigi.ToOctalString();
45+
BigInteger bigi = BigInteger.Zero;
46+
bigi++;
47+
string result = bigi.ToOctalString();
4848

49-
Assert.AreEqual("01", result);
50-
}
49+
Assert.AreEqual("01", result);
50+
}
5151

5252
/// <summary>
5353
/// Test.
5454
/// </summary>
5555
[TestMethod]
5656
public void TestToOctalString02()
5757
{
58-
BigInteger bigi = BigInteger.Zero;
59-
bigi--;
60-
string result = bigi.ToOctalString();
58+
BigInteger bigi = BigInteger.Zero;
59+
bigi--;
60+
string result = bigi.ToOctalString();
6161

62-
Assert.AreEqual("377", result);
63-
}
62+
Assert.AreEqual("377", result);
63+
}
6464

6565
/// <summary>
6666
/// Test.
6767
/// </summary>
6868
[TestMethod]
6969
public void TestToOctalString03()
7070
{
71-
BigInteger bigi = BigInteger.Zero;
72-
bigi--;
73-
bigi--;
74-
bigi--;
75-
bigi--;
76-
bigi--;
77-
bigi--;
78-
bigi--;
79-
string result = bigi.ToOctalString();
80-
81-
Assert.AreEqual("371", result);
82-
}
71+
BigInteger bigi = BigInteger.Zero;
72+
bigi--;
73+
bigi--;
74+
bigi--;
75+
bigi--;
76+
bigi--;
77+
bigi--;
78+
bigi--;
79+
string result = bigi.ToOctalString();
80+
81+
Assert.AreEqual("371", result);
82+
}
8383

8484
/// <summary>
8585
/// Test.
8686
/// </summary>
8787
[TestMethod]
8888
public void TestToHexadecimalString1()
8989
{
90-
byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
91-
var convertme = new BigInteger(bytes);
92-
string result = convertme.ToHexadecimalString();
90+
byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
91+
var convertme = new BigInteger(bytes);
92+
string result = convertme.ToHexadecimalString();
9393

94-
Assert.AreEqual("0FFFFFFFF", result);
95-
}
94+
Assert.AreEqual("0FFFFFFFF", result);
95+
}
9696

9797
/// <summary>
9898
/// Test.
9999
/// </summary>
100100
[TestMethod]
101101
public void TestToBinaryString1()
102102
{
103-
byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
104-
var convertme = new BigInteger(bytes);
105-
string result = convertme.ToBinaryString();
103+
byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
104+
var convertme = new BigInteger(bytes);
105+
string result = convertme.ToBinaryString();
106106

107-
Assert.AreEqual("011111111111111111111111111111111", result);
108-
}
107+
Assert.AreEqual("011111111111111111111111111111111", result);
108+
}
109109

110110
/// <summary>
111111
/// Test.
112112
/// </summary>
113113
[TestMethod]
114114
public void TestToBinaryString01()
115115
{
116-
BigInteger bigi = BigInteger.Zero;
117-
bigi++;
118-
string result = bigi.ToBinaryString();
116+
BigInteger bigi = BigInteger.Zero;
117+
bigi++;
118+
string result = bigi.ToBinaryString();
119119

120-
Assert.AreEqual("01", result);
121-
}
120+
Assert.AreEqual("01", result);
121+
}
122122

123123
/// <summary>
124124
/// Test.
125125
/// </summary>
126126
[TestMethod]
127127
public void TestToBinaryString2()
128128
{
129-
var convertme = new BigInteger(-1);
130-
string result = convertme.ToBinaryString();
129+
var convertme = new BigInteger(-1);
130+
string result = convertme.ToBinaryString();
131131

132-
Assert.AreEqual("11111111", result);
133-
}
132+
Assert.AreEqual("11111111", result);
133+
}
134134

135135
/// <summary>
136136
/// Test.
137137
/// </summary>
138138
[TestMethod]
139139
public void TestToBinaryString3()
140140
{
141-
byte[] bytes =
142-
[
143-
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
144-
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
145-
];
146-
var convertme = new BigInteger(bytes);
147-
string result = convertme.ToBinaryString();
148-
149-
Assert.AreEqual("11111111", result);
150-
}
141+
byte[] bytes =
142+
[
143+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
144+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
145+
];
146+
var convertme = new BigInteger(bytes);
147+
string result = convertme.ToBinaryString();
148+
149+
Assert.AreEqual("11111111", result);
150+
}
151151
}

src/TestProject/IPAddressTest.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace TestProject;
2+
3+
/// <summary>
4+
/// Test IPAddress Behaviour on MacOS
5+
/// </summary>
6+
[TestClass]
7+
public class IPAddressTest
8+
{
9+
/// <summary>
10+
/// Mixed IPv6 / IPvç notation
11+
/// Why This Happens
12+
/// .NET automatically uses mixed notation for IPv6 addresses when:
13+
/// The first 96 bits are zero (IPv4-compatible)
14+
/// The first 80 bits are zero and bits 81-96 are either all zeros or all ones (IPv4-mapped)
15+
/// The pattern suggests an embedded IPv4 address
16+
/// Your bytes ::0.1.0.0 are being interpreted as an IPv4-compatible IPv6 address.
17+
/// </summary>
18+
[TestMethod]
19+
public void TestIPAddress()
20+
{
21+
byte[] bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0];
22+
var ip = new IPAddress(bytes);
23+
Assert.AreEqual("::0.1.0.0", ip.ToString());
24+
}
25+
}

0 commit comments

Comments
 (0)