add bytes ip sub and middle util func

This commit is contained in:
lionsoul2014 2026-04-04 18:39:31 +08:00
parent dabe7798f6
commit d9fc17727e
2 changed files with 150 additions and 0 deletions

View File

@ -82,6 +82,59 @@ func IPSubOne(ip []byte) []byte {
return r return r
} }
// IPSub Sub the spcecified two byte ip
func IPSub(sip, eip []byte) ([]byte, error) {
if len(sip) != len(eip) {
return []byte{}, fmt.Errorf("length of the two ips are not the same")
}
var carry uint16 = 0
var result = make([]byte, len(sip)+1)
for i := len(sip) - 1; i >= 0; i-- {
sum := uint16(sip[i]) + uint16(eip[i]) + carry
result[i+1] = byte(sum) // Store standard 8-bit result
carry = sum >> 8 // Extract the 1-bit carry for the next byte
}
// check and append the carry
if carry > 0 {
result[0] = byte(carry)
return result, nil
} else {
return result[1:], nil
}
}
// IPHalf get the half value of an input byte ip
func IPHalf(ip []byte) []byte {
var length = len(ip)
var result = make([]byte, length)
// Tracks the bit falling off from the previous byte
var carry byte = 0
for i := 0; i < length; i++ {
// 1. Shift current byte right by 1
// 2. Or (|) with the carry from the previous byte (shifted to the MSB position)
result[i] = (ip[i] >> 1) | (carry << 7)
// 3. Capture the Least Significant Bit (LSB) to use as carry for the next byte
carry = ip[i] & 1
}
return result
}
// IPMiddle get the middle value of two input ip address
func IPMiddle(sip, eip []byte) ([]byte, error) {
buf, err := IPSub(sip, eip)
if err != nil {
return []byte{}, fmt.Errorf("IPSub(%s, %s): %w", IP2String(sip), IP2String(eip), err)
}
return IPHalf(buf), nil
}
// Verify if the current Searcher could be used to search the specified xdb file. // Verify if the current Searcher could be used to search the specified xdb file.
// Why do we need this check ? // Why do we need this check ?
// The future features of the xdb impl may cause the current searcher not able to work properly. // The future features of the xdb impl may cause the current searcher not able to work properly.

View File

@ -9,6 +9,7 @@
package xdb package xdb
import ( import (
"encoding/binary"
"fmt" "fmt"
"testing" "testing"
"time" "time"
@ -41,6 +42,102 @@ func TestIPCompare(t *testing.T) {
} }
} }
func TestIPSub(t *testing.T) {
var strToSub = "1.2.3.4"
bytesToSub, err := ParseIP(strToSub)
if err != nil {
t.Fatalf("failed to parse ip %s", strToSub)
}
var intToSub = int(binary.BigEndian.Uint32(bytesToSub))
t.Logf("to sub ip: %d -> %s", intToSub, strToSub)
counter := 0
buf := make([]byte, 4)
for i := 0; i < 0x2FFFFFFF; i++ {
binary.BigEndian.PutUint32(buf, uint32(i))
subVal, err := IPSub(buf, bytesToSub)
if err != nil {
t.Fatalf("failed to IPSub(%s,%s): %s", IP2String(buf), strToSub, err)
}
// do it as two integers
byteSub := int(binary.BigEndian.Uint32(subVal))
intSub := i + intToSub
if byteSub != intSub {
t.Fatal("byte and int sub value are not the same")
}
counter++
}
t.Logf("test done with %d ips", counter)
}
func TestIPHalf(t *testing.T) {
var buf = make([]byte, 4)
for i := 0; i < 0xFFFFFFFF; i++ {
binary.BigEndian.PutUint32(buf, uint32(i))
half := IPHalf(buf)
// do it as two integers
byteMiddle := binary.BigEndian.Uint32(half)
intMidle := i >> 1
if byteMiddle != uint32(intMidle) {
t.Fatal("byte middle and int middle are not the same")
}
}
}
func TestSubOverflow(t *testing.T) {
var ip1Str = "255.255.255.250"
ip1Bytes, err := ParseIP(ip1Str)
if err != nil {
t.Fatalf("failed to ParseIP(%s): %s", ip1Str, err)
}
var buff = make([]byte, 4)
for i := 0; i < 10; i++ {
binary.BigEndian.PutUint32(buff, uint32(i))
ipSub, err := IPSub(ip1Bytes, buff)
if err != nil {
t.Fatalf("failed to IPSub(%s, %s): %s", ip1Str, IP2String(buff), err)
}
t.Logf("IPSub(%s, %s) = %+v", ip1Str, IP2String(buff), ipSub)
}
}
func TestIPMiddle(t *testing.T) {
var sIPStr = "0.0.0.0"
sBytes, err := ParseIP(sIPStr)
if err != nil {
t.Fatalf("failed to parse ip %s", sIPStr)
}
var sInt = int(binary.BigEndian.Uint32(sBytes))
t.Logf("start ip: %d -> %s", sInt, sIPStr)
counter := 0
buf := make([]byte, 4)
for i := 0; i < 0x0FFFFFFF; i++ {
binary.BigEndian.PutUint32(buf, uint32(i))
midVal, err := IPMiddle(sBytes, buf)
if err != nil {
t.Fatalf("failed to IPMiddle(%s,%s): %s", sIPStr, IP2String(buf), err)
}
// do it as two integers
byteMid := int(binary.BigEndian.Uint32(midVal))
intMid := (sInt + i) >> 1
if byteMid != intMid {
t.Fatal("byte and int middle value are not the same")
}
counter++
}
t.Logf("test done with %d ips", counter)
}
func TestLoadVectorIndex(t *testing.T) { func TestLoadVectorIndex(t *testing.T) {
vIndex, err := LoadVectorIndexFromFile("../../../data/ip2region_v4.xdb") vIndex, err := LoadVectorIndexFromFile("../../../data/ip2region_v4.xdb")
if err != nil { if err != nil {