• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lduchosal / ipnetwork / 22803352265

07 Mar 2026 05:07PM UTC coverage: 91.848% (-1.3%) from 93.118%
22803352265

push

travis-pro

web-flow
Merge pull request #383 from lduchosal/feat/v4-nullable

feat/v4-nullable

651 of 721 branches covered (90.29%)

Branch coverage included in aggregate %.

111 of 147 new or added lines in 26 files covered. (75.51%)

5 existing lines in 3 files now uncovered.

1929 of 2088 relevant lines covered (92.39%)

574342.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.81
/src/System.Net.IPNetwork/IPNetwork2Substract.cs
1
// <copyright file="IPNetwork2Supernet.cs" company="IPNetwork">
2
// Copyright (c) IPNetwork. All rights reserved.
3
// </copyright>
4

5
using System.Collections.Generic;
6
using System.Diagnostics.CodeAnalysis;
7
using System.Linq;
8

9
namespace System.Net;
10

11
/// <summary>
12
/// Subtract.
13
/// </summary>
14
public sealed partial class IPNetwork2
15
{
16
    /// <summary>
17
    /// Implementation for IP network symmetric difference (subtraction)
18
    /// 0.0.0.0/0 - 10.0.0.1/32 = [
19
    ///     0.0.0.0/5, 8.0.0.0/7, 10.0.0.0/32, 10.0.0.2/31, 10.0.0.4/30, 10.0.0.8/29,
20
    ///     10.0.0.16/28, 10.0.0.32/27, 10.0.0.64/26, 10.0.0.128/25, 10.0.1.0/24, 10.0.2.0/23,
21
    ///     10.0.4.0/22, 10.0.8.0/21, 10.0.16.0/20, 10.0.32.0/19, 10.0.64.0/18, 10.0.128.0/17,
22
    ///     10.1.0.0/16, 10.2.0.0/15, 10.4.0.0/14, 10.8.0.0/13, 10.16.0.0/12, 10.32.0.0/11,
23
    ///     10.64.0.0/10, 10.128.0.0/9, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3,
24
    ///     64.0.0.0/2, 128.0.0.0/1
25
    /// ].
26
    /// </summary>
27
    /// <param name="network2">The network to subtract.</param>
28
    /// <returns>A list of IP Network.</returns>
29
    public List<IPNetwork2> Subtract(IPNetwork2 network2)
30
    {
38✔
31
        if (!InternalSubtract(false, this, network2, out List<IPNetwork2>? result))
38!
NEW
32
        {
×
NEW
33
            throw new InvalidOperationException("Subtract failed");
×
34
        }
35

36
        return result;
36✔
37
    }
36✔
38

39
    /// <summary>
40
    /// Implementation for IP network symmetric difference (subtraction)
41
    /// 0.0.0.0/0 - 10.0.0.1/32 = [
42
    ///     0.0.0.0/5, 8.0.0.0/7, 10.0.0.0/32, 10.0.0.2/31, 10.0.0.4/30, 10.0.0.8/29,
43
    ///     10.0.0.16/28, 10.0.0.32/27, 10.0.0.64/26, 10.0.0.128/25, 10.0.1.0/24, 10.0.2.0/23,
44
    ///     10.0.4.0/22, 10.0.8.0/21, 10.0.16.0/20, 10.0.32.0/19, 10.0.64.0/18, 10.0.128.0/17,
45
    ///     10.1.0.0/16, 10.2.0.0/15, 10.4.0.0/14, 10.8.0.0/13, 10.16.0.0/12, 10.32.0.0/11,
46
    ///     10.64.0.0/10, 10.128.0.0/9, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3,
47
    ///     64.0.0.0/2, 128.0.0.0/1
48
    /// ].
49
    /// </summary>
50
    /// <param name="network2">The network to supernet with.</param>
51
    /// <param name="result">The resulting IPNetwork.</param>
52
    /// <returns>true if network2 was subtracted successfully; otherwise, false.</returns>
53
    public bool TrySubtract(IPNetwork2 network2, [NotNullWhen(true)] out List<IPNetwork2>? result)
54
    {
11✔
55
        bool parsed = InternalSubtract(true, this, network2, out result);
11✔
56
        return parsed;
11✔
57
    }
11✔
58

59
    /// <summary>
60
    /// Attempts to merge two adjacent IP networks with equal CIDR values into a single supernet.
61
    /// </summary>
62
    /// <param name="trySubtract">If true, suppresses exceptions on failure; otherwise, throws.</param>
63
    /// <param name="network1">The first IP network.</param>
64
    /// <param name="network2">The second IP network.</param>
65
    /// <param name="result">The resulting subtracted.</param>
66
    internal static bool InternalSubtract(
67
        bool trySubtract,
68
        IPNetwork2 network1,
69
        IPNetwork2 network2,
70
        [NotNullWhen(true)] out List<IPNetwork2>? result)
71
    {
49✔
72
        // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
73
        if (network1 == null)
49!
74
        {
×
75
            if (!trySubtract)
×
76
            {
×
77
                throw new ArgumentNullException(nameof(network1));
×
78
            }
79

80
            result = null;
×
81
            return false;
×
82
        }
83

84
        if (network2 == null)
49✔
85
        {
3✔
86
            if (!trySubtract)
3✔
87
            {
2✔
88
                throw new ArgumentNullException(nameof(network2));
2✔
89
            }
90

91
            result = null;
1✔
92
            return false;
1✔
93
        }
94

95
        // If network2 completely contains network1, return empty
96
        if (network2.Contains(network1))
46✔
97
        {
13✔
98
            result = [];
13✔
99
            return true;
13✔
100
        }
101

102
        // If networks don't overlap, return original network
103
        if (!network1.Contains(network2))
33✔
104
        {
8✔
105
            var copy = new IPNetwork2(network1.InternalNetwork, network1.family, network1.Cidr);
8✔
106
            result = [copy];
8✔
107
            return true;
8✔
108
        }
109

110
        // If network1 completely contains network2, we need to split
111
        result = network1.SplitAroundSubnet(network2);
25✔
112
        return true;
25✔
113
    }
47✔
114
    
115
    private List<IPNetwork2> SplitAroundSubnet(IPNetwork2 network2)
116
    {
25✔
117
        var result = new List<IPNetwork2>();
25✔
118
        var queue = new Queue<IPNetwork2>();
25✔
119
        queue.Enqueue(this);
25✔
120
        
121
        while (queue.Count > 0)
766✔
122
        {
741✔
123
            var current = queue.Dequeue();
741✔
124
            
125
            // If current doesn't overlap with hole, add it to result
126
            if (!current.Overlap(network2))
741✔
127
            {
358✔
128
                result.Add(current);
358✔
129
                continue;
358✔
130
            }
131
            
132
            // If hole completely contains current, skip it
133
            if (network2.Contains(current))
383✔
134
            {
25✔
135
                continue;
25✔
136
            }
137
            
138
            // If current is same size or smaller than hole and overlaps, we need to split
139
            var split = current.Subnet((byte)(current.Cidr + 1));
358✔
140
            var leftHalf = split[0];
358✔
141
            var rightHalf = split[1];
358✔
142
            
143
            queue.Enqueue(leftHalf);
358✔
144
            queue.Enqueue(rightHalf);
358✔
145
        }
358✔
146
        
147
        return result.OrderBy(n => n.ipaddress).ToList();
378✔
148
    }
25✔
149
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc