mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
net/netip: export Prefix.Compare, fix ordering
Fixes #61642 Co-authored-by: David Anderson <dave@natulte.net> Change-Id: I54795763bdc5f62da469c2ae20618c36b64396f3 Reviewed-on: https://go-review.googlesource.com/c/go/+/700355 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Damien Neil <dneil@google.com> Auto-Submit: Michael Pratt <mpratt@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
731e546166
commit
e8f9127d1f
5 changed files with 76 additions and 11 deletions
1
api/next/61642.txt
Normal file
1
api/next/61642.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
pkg net/netip, method (Prefix) Compare(Prefix) int #61642
|
||||
1
doc/next/6-stdlib/99-minor/net/netip/61642.md
Normal file
1
doc/next/6-stdlib/99-minor/net/netip/61642.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
The new [Prefix.Compare] method compares two prefixes.
|
||||
|
|
@ -34,5 +34,3 @@ var TestAppendToMarshal = testAppendToMarshal
|
|||
|
||||
func (a Addr) IsZero() bool { return a.isZero() }
|
||||
func (p Prefix) IsZero() bool { return p.isZero() }
|
||||
|
||||
func (p Prefix) Compare(p2 Prefix) int { return p.compare(p2) }
|
||||
|
|
|
|||
|
|
@ -1330,21 +1330,23 @@ func (p Prefix) isZero() bool { return p == Prefix{} }
|
|||
// IsSingleIP reports whether p contains exactly one IP.
|
||||
func (p Prefix) IsSingleIP() bool { return p.IsValid() && p.Bits() == p.ip.BitLen() }
|
||||
|
||||
// compare returns an integer comparing two prefixes.
|
||||
// Compare returns an integer comparing two prefixes.
|
||||
// The result will be 0 if p == p2, -1 if p < p2, and +1 if p > p2.
|
||||
// Prefixes sort first by validity (invalid before valid), then
|
||||
// address family (IPv4 before IPv6), then prefix length, then
|
||||
// address.
|
||||
//
|
||||
// Unexported for Go 1.22 because we may want to compare by p.Addr first.
|
||||
// See post-acceptance discussion on go.dev/issue/61642.
|
||||
func (p Prefix) compare(p2 Prefix) int {
|
||||
if c := cmp.Compare(p.Addr().BitLen(), p2.Addr().BitLen()); c != 0 {
|
||||
// address family (IPv4 before IPv6), then masked prefix address, then
|
||||
// prefix length, then unmasked address.
|
||||
func (p Prefix) Compare(p2 Prefix) int {
|
||||
// Aside from sorting based on the masked address, this use of
|
||||
// Addr.Compare also enforces the valid vs. invalid and address
|
||||
// family ordering for the prefix.
|
||||
if c := p.Masked().Addr().Compare(p2.Masked().Addr()); c != 0 {
|
||||
return c
|
||||
}
|
||||
|
||||
if c := cmp.Compare(p.Bits(), p2.Bits()); c != 0 {
|
||||
return c
|
||||
}
|
||||
|
||||
return p.Addr().Compare(p2.Addr())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1123,6 +1123,9 @@ func TestPrefixCompare(t *testing.T) {
|
|||
{mustPrefix("fe80::/48"), mustPrefix("fe80::/64"), -1},
|
||||
|
||||
{mustPrefix("1.2.3.0/24"), mustPrefix("fe80::/8"), -1},
|
||||
|
||||
{mustPrefix("1.2.3.0/24"), mustPrefix("1.2.3.4/24"), -1},
|
||||
{mustPrefix("1.2.3.0/24"), mustPrefix("1.2.3.0/28"), -1},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := tt.a.Compare(tt.b)
|
||||
|
|
@ -1148,10 +1151,70 @@ func TestPrefixCompare(t *testing.T) {
|
|||
Prefix{},
|
||||
mustPrefix("fe80::/48"),
|
||||
mustPrefix("1.2.0.0/24"),
|
||||
mustPrefix("1.2.3.4/24"),
|
||||
mustPrefix("1.2.3.0/28"),
|
||||
}
|
||||
slices.SortFunc(values, Prefix.Compare)
|
||||
got := fmt.Sprintf("%s", values)
|
||||
want := `[invalid Prefix 1.2.0.0/16 1.2.0.0/24 1.2.3.0/24 fe80::/48 fe80::/64 fe90::/64]`
|
||||
want := `[invalid Prefix 1.2.0.0/16 1.2.0.0/24 1.2.3.0/24 1.2.3.4/24 1.2.3.0/28 fe80::/48 fe80::/64 fe90::/64]`
|
||||
if got != want {
|
||||
t.Errorf("unexpected sort\n got: %s\nwant: %s\n", got, want)
|
||||
}
|
||||
|
||||
// Lists from
|
||||
// https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml and
|
||||
// https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml,
|
||||
// to verify that the sort order matches IANA's conventional
|
||||
// ordering.
|
||||
values = []Prefix{
|
||||
mustPrefix("0.0.0.0/8"),
|
||||
mustPrefix("127.0.0.0/8"),
|
||||
mustPrefix("10.0.0.0/8"),
|
||||
mustPrefix("203.0.113.0/24"),
|
||||
mustPrefix("169.254.0.0/16"),
|
||||
mustPrefix("192.0.0.0/24"),
|
||||
mustPrefix("240.0.0.0/4"),
|
||||
mustPrefix("192.0.2.0/24"),
|
||||
mustPrefix("192.0.0.170/32"),
|
||||
mustPrefix("198.18.0.0/15"),
|
||||
mustPrefix("192.0.0.8/32"),
|
||||
mustPrefix("0.0.0.0/32"),
|
||||
mustPrefix("192.0.0.9/32"),
|
||||
mustPrefix("198.51.100.0/24"),
|
||||
mustPrefix("192.168.0.0/16"),
|
||||
mustPrefix("192.0.0.10/32"),
|
||||
mustPrefix("192.175.48.0/24"),
|
||||
mustPrefix("192.52.193.0/24"),
|
||||
mustPrefix("100.64.0.0/10"),
|
||||
mustPrefix("255.255.255.255/32"),
|
||||
mustPrefix("192.31.196.0/24"),
|
||||
mustPrefix("172.16.0.0/12"),
|
||||
mustPrefix("192.0.0.0/29"),
|
||||
mustPrefix("192.88.99.0/24"),
|
||||
mustPrefix("fec0::/10"),
|
||||
mustPrefix("6000::/3"),
|
||||
mustPrefix("fe00::/9"),
|
||||
mustPrefix("8000::/3"),
|
||||
mustPrefix("0000::/8"),
|
||||
mustPrefix("0400::/6"),
|
||||
mustPrefix("f800::/6"),
|
||||
mustPrefix("e000::/4"),
|
||||
mustPrefix("ff00::/8"),
|
||||
mustPrefix("a000::/3"),
|
||||
mustPrefix("fc00::/7"),
|
||||
mustPrefix("1000::/4"),
|
||||
mustPrefix("0800::/5"),
|
||||
mustPrefix("4000::/3"),
|
||||
mustPrefix("0100::/8"),
|
||||
mustPrefix("c000::/3"),
|
||||
mustPrefix("fe80::/10"),
|
||||
mustPrefix("0200::/7"),
|
||||
mustPrefix("f000::/5"),
|
||||
mustPrefix("2000::/3"),
|
||||
}
|
||||
slices.SortFunc(values, func(a, b Prefix) int { return a.Compare(b) })
|
||||
got = fmt.Sprintf("%s", values)
|
||||
want = `[0.0.0.0/8 0.0.0.0/32 10.0.0.0/8 100.64.0.0/10 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.0.0.0/24 192.0.0.0/29 192.0.0.8/32 192.0.0.9/32 192.0.0.10/32 192.0.0.170/32 192.0.2.0/24 192.31.196.0/24 192.52.193.0/24 192.88.99.0/24 192.168.0.0/16 192.175.48.0/24 198.18.0.0/15 198.51.100.0/24 203.0.113.0/24 240.0.0.0/4 255.255.255.255/32 ::/8 100::/8 200::/7 400::/6 800::/5 1000::/4 2000::/3 4000::/3 6000::/3 8000::/3 a000::/3 c000::/3 e000::/4 f000::/5 f800::/6 fc00::/7 fe00::/9 fe80::/10 fec0::/10 ff00::/8]`
|
||||
if got != want {
|
||||
t.Errorf("unexpected sort\n got: %s\nwant: %s\n", got, want)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue