ipbits.go 1.1 KB

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