Skip to content

Instantly share code, notes, and snippets.

@millken
Created March 20, 2025 14:25
Show Gist options
  • Save millken/838a528ede2c7f7f289f6a7e7197e0f0 to your computer and use it in GitHub Desktop.
Save millken/838a528ede2c7f7f289f6a7e7197e0f0 to your computer and use it in GitHub Desktop.
fast golang ip2long
//go:noinline
func IpToLong(ipStr string) uint32 {
ptr := unsafe.Pointer(unsafe.StringData(ipStr))
var (
n uint32
oct uint32
p = ptr
)
// 第一段: XXX.
for {
c := *(*byte)(p)
if c == '.' {
p = unsafe.Add(p, 1)
break
}
oct = oct*10 + uint32(c&0x0F) // 利用 ASCII 特性省去 -'0'
p = unsafe.Add(p, 1)
}
n = oct << 24
// 第二段: XXX.
oct = 0
for {
c := *(*byte)(p)
if c == '.' {
p = unsafe.Add(p, 1)
break
}
oct = oct*10 + uint32(c&0x0F)
p = unsafe.Add(p, 1)
}
n |= oct << 16
// 第三段: XXX.
oct = 0
for {
c := *(*byte)(p)
if c == '.' {
p = unsafe.Add(p, 1)
break
}
oct = oct*10 + uint32(c&0x0F)
p = unsafe.Add(p, 1)
}
n |= oct << 8
// 第四段: XXX
oct = 0
for uintptr(unsafe.Pointer(p))-uintptr(ptr) < uintptr(len(ipStr)) {
c := *(*byte)(p)
oct = oct*10 + uint32(c&0x0F)
p = unsafe.Add(p, 1)
}
return n | oct
}
@millken
Copy link
Author

millken commented Mar 20, 2025

func IpToLong(ip string) uint32 {
    var n, part uint32
    segment := 0

    for _, c := range ip {
        if c == '.' {
            n = n<<8 | part
            part = 0
            segment++
            continue
        }
        part = part*10 + uint32(c-'0') // 直接处理数字字符
    }
    n = n<<8 | part // 处理最后一段

    // 补充缺失的段(仅处理合法输入)
    for segment++ < 3 {
        n <<= 8
    }
    
    return n
}

@millken
Copy link
Author

millken commented Mar 20, 2025

//go:noinline
func IPv6ToUint128(ipStr string) (hi, lo uint64) {
    ptr := unsafe.Pointer(unsafe.StringData(ipStr))
    end := uintptr(len(ipStr))
    var (
        groups       uint16
        compressPos  = -1
        groupIdx     int
        hexAcc       uint16
        colonCount   int
        hasIPv4      bool
    )

    // 状态机扫描
    for p := uintptr(0); p < end; p++ {
        c := *(*byte)(unsafe.Add(ptr, p))

        switch {
        // 处理 IPv4 嵌入 (如 ::ffff:192.168.0.1)
        case c == '.' && hasIPv4:
            ipv4Part := unsafe.Slice((*byte)(unsafe.Add(ptr, p-3)), 7) // 反向取 3 字节
            var a, b, c, d uint8
            a = ipv4Part&0x0F*10 + ipv4Part&0x0F
            b = ipv4Part&0x0F*10 + ipv4Part&0x0F
            c = ipv4Part&0x0F*10 + ipv4Part&0x0F
            d = ipv4Part&0x0F*10 + ipv4Part&0x0F
            groups[groupIdx] = uint16(a<<8 | b)
            groups[groupIdx+1] = uint16(c<<8 | d)
            groupIdx += 2
            break

        // 处理十六进制数字
        case c >= '0' && c <= '9':
            hexAcc = hexAcc<<4 | uint16(c&0x0F)
        case c >= 'a' && c <= 'f':
            hexAcc = hexAcc<<4 | uint16(c-'a'+10)
        case c >= 'A' && c <= 'F':
            hexAcc = hexAcc<<4 | uint16(c-'A'+10)

        // 处理分组分隔
        case c == ':':
            if colonCount == 1 { // 发现压缩标记 ::
                compressPos = groupIdx
                colonCount = 0
                continue
            }
            groups[groupIdx] = hexAcc
            groupIdx++
            hexAcc = 0
            colonCount++

        // 触发 IPv4 处理标志
        case c == '.':
            hasIPv4 = true
        }
    }

    // 处理最后一个分组
    if hexAcc != 0 || groups[groupIdx] != 0 {
        groups[groupIdx] = hexAcc
        groupIdx++
    }

    // 处理压缩的零组
    if compressPos != -1 {
        gap := 8 - groupIdx
        copy(groups[compressPos+gap:], groups[compressPos:groupIdx])
        for i := compressPos; i < compressPos+gap; i++ {
            groups[i] = 0
        }
        groupIdx = 8
    }

    // 合并高低位
    hi = uint64(groups)<<48 | uint64(groups)<<32 |
         uint64(groups)<<16 | uint64(groups)
    lo = uint64(groups)<<48 | uint64(groups)<<32 |
         uint64(groups)<<16 | uint64(groups)
    return
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment