// 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() } }