-
Notifications
You must be signed in to change notification settings - Fork 18.7k
/
ipbits.go
41 lines (38 loc) · 1.06 KB
/
ipbits.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Package ipbits contains utilities for manipulating [netip.Addr] values as
// numbers or bitfields.
package ipbits
import (
"encoding/binary"
"net/netip"
)
// Add returns ip + (x << shift).
func Add(ip netip.Addr, x uint64, shift uint) netip.Addr {
if ip.Is4() {
a := ip.As4()
addr := binary.BigEndian.Uint32(a[:])
addr += uint32(x) << shift
binary.BigEndian.PutUint32(a[:], addr)
return netip.AddrFrom4(a)
} else {
a := ip.As16()
addr := uint128From16(a)
addr = addr.add(uint128From(x).lsh(shift))
addr.fill16(&a)
return netip.AddrFrom16(a)
}
}
// Field returns the value of the bitfield [u, v] in ip as an integer,
// where bit 0 is the most-significant bit of ip.
//
// The result is undefined if u > v, if v-u > 64, or if u or v is larger than
// ip.BitLen().
func Field(ip netip.Addr, u, v uint) uint64 {
if ip.Is4() {
mask := ^uint32(0) >> u
a := ip.As4()
return uint64((binary.BigEndian.Uint32(a[:]) & mask) >> (32 - v))
} else {
mask := uint128From(0).not().rsh(u)
return uint128From16(ip.As16()).and(mask).rsh(128 - v).uint64()
}
}