diff --git a/ReadMe.md b/ReadMe.md
index 2542f41..f8f390f 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -46,7 +46,7 @@ API 介绍,使用文档和测试程序请参考对应 `searcher` 查询客户
| [Csharp](binding/csharp) | csharp xdb 查询客户端 | :white_check_mark: | :white_check_mark: | [Alen Lee](https://github.com/malus2077) & [ArgoZhang](https://github.com/ArgoZhang) |
| [Erlang](binding/erlang) | erlang xdb 查询客户端 | :white_check_mark: | :x: | [malou](https://github.com/malou996) |
| [Nginx](binding/nginx) | nginx 扩展 xdb 查询客户端 | :white_check_mark: | :x: | [Wu Jian Ping](https://github.com/wujjpp) |
-| [C++](binding/cpp) | C++ xdb 查询客户端 | :white_check_mark: | :x: | [Yunbin Liu](https://github.com/liuyunbin) |
+| [C++](binding/cpp) | C++ xdb 查询客户端 | :white_check_mark: | :white_check_mark: | [Yunbin Liu](https://github.com/liuyunbin) |
以下工具链实现由社区开发者通过第三方仓库贡献:
@@ -69,13 +69,13 @@ API 介绍,使用文档和测试程序请参考如下 `maker` 生成程序下
| [Python](maker/python) | python xdb 生成程序 | :white_check_mark: | :x: | [leolin49](https://github.com/leolin49) |
| [Csharp](maker/csharp) | csharp xdb 生成程序 | :white_check_mark: | :x: | [Alan Lee](https://github.com/malus2077) |
| [Rust](maker/rust) | rust xdb 生成程序 | :white_check_mark: | :white_check_mark: | [KevinWang](https://github.com/KevinWL) & [gongzhengyang](https://github.com/gongzhengyang) |
-| [C++](maker/cpp) | C++ xdb 生成程序 | :white_check_mark: | :x: | [Yunbin Liu](https://github.com/liuyunbin) |
-
-
+| [C++](maker/cpp) | C++ xdb 生成程序 | :white_check_mark: | :white_check_mark: | [Yunbin Liu](https://github.com/liuyunbin) |
+
+
# `xdb` 数据更新
-
+
ip2region 项目的核心在于 研究 IP 数据的存储和快速查询的设计和实现, 项目自带的 `./data/ipv4_source.txt` 和 `./data/ipv6_source.txt` 原始数据不会再提供更新,对于数据精度和更新频率要求很高的使用场景建议到 [Ip2Region社区](https://ip2region.net/products/offline) 或者第三方购买商用离线数据,你可以使用如下几种方式来尝试自己更新数据:
-
+
### 手动编辑更新
你可以基于 ip2region 自带的 `./data/ipv4_source.txt` 和 `./data/ipv6_source.txt` 原始 IP 数据用 ip2region 提供的编辑工具来自己修改,目前数据源有如下几种方式:
1. ip2region 社区提供的数据(请参考地底部的公众号关注社区通知)
@@ -87,7 +87,7 @@ ip2region 项目的核心在于 研究 IP 数据的存储和快速查询的
|:------------------------------------|:-------------------------|:-------------------|:-------------------|:-------------------------------------------|
| [Golang](maker/golang#xdb-数据编辑) | golang IP 原始数据编辑器 | :white_check_mark: | :white_check_mark: | [Lion](https://github.com/lionsoul2014) |
| [Java](maker/java#xdb-数据编辑) | java IP 原始数据编辑器 | :white_check_mark: | :soon: | [Lion](https://github.com/lionsoul2014) |
-| [C++](maker/cpp#xdb-数据编辑) | C++ IP 原始数据编辑器 | :white_check_mark: | :x: | [Yunbin Liu](https://github.com/liuyunbin) |
+| [C++](maker/cpp) | C++ IP 原始数据编辑器 | :white_check_mark: | :white_check_mark: | [Yunbin Liu](https://github.com/liuyunbin) |
### 检测自动更新
diff --git a/binding/cpp/Makefile b/binding/cpp/Makefile
index 2f810d6..5f7599e 100644
--- a/binding/cpp/Makefile
+++ b/binding/cpp/Makefile
@@ -1,11 +1,27 @@
-all: xdb_search xdb_bench
+all: bin header search bench make edit
-xdb_search: xdb_search.cc xdb_search_test.cc
- g++ -std=c++11 -O2 $^ -o $@
+FILES=$(wildcard src/*.cc)
-xdb_bench: xdb_search.cc xdb_bench.cc xdb_bench_test.cc
- g++ -std=c++11 -O2 $^ -o $@
+bin:
+ mkdir -p bin
+
+header: $(FILES) test/header.cc
+ g++ -std=c++11 -O2 $^ -o bin/$@
+
+search: $(FILES) test/search.cc
+ g++ -std=c++11 -O2 $^ -o bin/$@
+
+bench: $(FILES) test/bench.cc
+ g++ -std=c++11 -O2 $^ -o bin/$@
+
+make: $(FILES) test/make.cc
+ g++ -std=c++11 -O2 $^ -o bin/$@
+
+edit: $(FILES)
+ g++ -std=c++11 -O2 $^ test/edit_v4.cc -o bin/edit_v4
+ g++ -std=c++11 -O2 $^ test/edit_v6.cc -o bin/edit_v6
clean:
- rm -f xdb_search xdb_bench
+ rm -rf bin
+
diff --git a/binding/cpp/readme.md b/binding/cpp/readme.md
index bac5bda..e2baf9f 100644
--- a/binding/cpp/readme.md
+++ b/binding/cpp/readme.md
@@ -1,108 +1,563 @@
-# ip2region xdb C++ 查询客户端实现
+# ip2region xdb C++ 实现
-## 使用方式
-### 完全基于文件的查询
+## 0. 文件说明
```
-#include
+Makefile --------- 构建
-#include "xdb_search.h"
+src ------------------ 源文件目录
+src/base.* ----------- 常量及工具函数
+src/ip.* ------------- 实现 IP 处理
+src/header.* --------- 实现 xdb 头部解析
+src/search.* --------- 实现 xdb 查找
+src/bench.* ---------- 实现 查找 测速
+src/make.* ----------- 实现 生成 xdb 文件
+src/edit.* ----------- 实现 原始数据编辑
-int main(int argc, char* argv[]) {
- char file_name[] = "../../data/ip2region.xdb";
- char ip[] = "1.2.3.4";
+test ---------------- 测试目录
+test/header.cc ------ 测试 头部
+test/search.cc ------ 测试 查找
+test/bench.cc ------- 测速
+test/make.cc -------- 生成 xdb 文件
+test/edit_v4.cc ----- 测试 原始数据编辑(ipv4)
+test/edit_v6.cc ----- 测试 原始数据编辑(ipv6)
- xdb_search_t xdb(file_name);
- xdb.init_file();
- std::cout << xdb.search(ip) << std::endl;
- return 0;
-}
+bin --------------- 可执行文件目录(通过 make 生成)
+bin/header -------- 测试 头部
+bin/search -------- 测试 查找
+bin/bench --------- 测速
+bin/make ---------- 生成 xdb 文件
+bin/edit_v4 ------- 测试 原始数据编辑(ipv4)
+bin/edit_v6 ------- 测试 原始数据编辑(ipv6)
+
+readme.md --------- readme
```
-### 缓存 `vector_index` 索引
-```
-#include
-
-#include "xdb_search.h"
-
-int main(int argc, char* argv[]) {
- char file_name[] = "../../data/ip2region.xdb";
- char ip[] = "1.2.3.4";
-
- xdb_search_t xdb(file_name);
- xdb.init_vector_index();
-
- std::cout << xdb.search(ip) << std::endl;
- return 0;
-}
-```
-
-### 缓存整个 `xdb` 数据
-```
-#include
-
-#include "xdb_search.h"
-
-int main(int argc, char* argv[]) {
- char file_name[] = "../../data/ip2region.xdb";
- char ip[] = "1.2.3.4";
-
- xdb_search_t xdb(file_name);
- xdb.init_content();
-
- std::cout << xdb.search(ip) << std::endl;
- return 0;
-}
-```
-
-## 测试程序编译
-1. 切换到当前目录
-2. 编译
-
+## 1. 编译
```
$ make
-g++ -std=c++11 -O2 xdb_search.cc xdb_search_test.cc -o xdb_search
-g++ -std=c++11 -O2 xdb_search.cc xdb_bench.cc xdb_bench_test.cc -o xdb_bench
```
-## 测试查询
-### 说明
+## 2. 查找
+### 2.1 示例
```
-$ ./xdb_search --help
-./xdb_search [command options]
-options:
- --db string ip2region binary xdb file path
- --cache-policy string cache policy: file/vector_index/content
- --help print help
+#include "src/search.h"
+
+// IP 版本: xdb::ipv4 xdb::ipv6
+// 策略: xdb::policy_file xdb::policy_vector xdb::policy_content
+// 不缓存 部分缓存 全部缓存
+int main() {
+ std::string xdb_name = "../../data/ip2region_v6.xdb";
+ int version = xdb::ipv6;
+ int policy = xdb::policy_content;
+ std::string ip = "2001:200:124::";
+
+ xdb::search_t s(xdb_name, version, policy);
+ std::cout << s.search(ip) << std::endl;
+ return 0;
+}
+
+// $ g++ src/*.cc 1.cc --- 编译
+// $ ./a.out ------------- 测试
+// 日本|东京都|千代田区|专线用户
```
-### 测试
+### 2.2 测试 xdb 头部
```
-$ ./xdb_search --db ../../data/ip2region.xdb --cache-policy vector_index
-cache policy : vector_index
-ip2region>> 1.2.3.4
-美国|0|华盛顿|0|谷歌
+$ ./bin/header
+测试 IPv4
+版本号: 3
+缓存策略: 1
+文件生成时间: 2025-09-06 02:24:16
+索引起始地址: 955933
+索引结束地址: 11042415
+IP版本: 4
+指针字节数: 4
+
+测试 IPv6
+版本号: 3
+缓存策略: 1
+文件生成时间: 2025-10-17 04:41:04
+索引起始地址: 3094259
+索引结束地址: 36258303
+IP版本: 6
+指针字节数: 4
```
-## bench 测试
-### 说明
+### 2.3 测试查找
```
-$ ./xdb_bench --help
-./xdb_bench [command options]
-options:
- --db string ip2region binary xdb file path
- --src string source ip text file path
- --cache-policy string cache policy: file/vector_index/content
- --help print help
+$ ./bin/search
+测试 IPv4 不缓存: 成功
+测试 IPv4 部分缓存: 成功
+测试 IPv4 全部缓存: 成功
+测试 IPv6 不缓存: 成功
+测试 IPv6 部分缓存: 成功
+测试 IPv6 全部缓存: 成功
```
-### 测试
+## 3. 测速以及检验正确性
```
-$ ./xdb_bench --db ../../data/ip2region.xdb --src ../../data/ip.merge.txt --cache-policy content
-total: 3419220, took: 3.44 s, cost: 0.27 μs/op, io count: 0
-$ ./xdb_bench --db ../../data/ip2region.xdb --src ../../data/ip.merge.txt --cache-policy vector_index
-total: 3419220, took: 45.99 s, cost: 12.24 μs/op, io count: 21739300
-$ ./xdb_bench --db ../../data/ip2region.xdb --src ../../data/ip.merge.txt --cache-policy file
-total: 3419220, took: 60.39 s, cost: 16.32 μs/op, io count: 25158520
+./bin/bench
+测试 IPv4, 不缓存, total: 3910284, took: 27.60s, cost: 6.59μs/op, io count: 28227147
+测试 IPv4, 部分缓存, total: 3910284, took: 21.85s, cost: 5.15μs/op, io count: 24316863
+测试 IPv4, 全部缓存, total: 3910284, took: 2.26s, cost: 0.25μs/op, io count: 0
+测试 IPv6, 不缓存, total: 4792520, took: 100.40s, cost: 20.22μs/op, io count: 80758866
+测试 IPv6, 部分缓存, total: 4792520, took: 93.06s, cost: 18.71μs/op, io count: 75966346
+测试 IPv6, 全部缓存, total: 4792520, took: 6.24s, cost: 0.81μs/op, io count: 0
+```
+
+## 4. 生成 xdb 文件
+### 4.1 生成 xdb 文件
+```
+$ ./bin/make
+生成 ipv4 的 xdb 文件, took: 0.57s
+生成 ipv6 的 xdb 文件, took: 1.24s
+```
+
+### 4.2 测试正确性
+```
+# ipv4 --- 只有时间不同
+$ diff <(xxd ./ip2region_v4.xdb) <(xxd ../../data/ip2region_v4.xdb)
+1c1
+< 00000000: 0300 0100 9f2f 2969 1d96 0e00 6f7e a800 ...../)i....o~..
+---
+> 00000000: 0300 0100 509b bb68 1d96 0e00 6f7e a800 ....P..h....o~..
+
+# ipv6 --- 只有时间不同
+$ diff <(xxd ./ip2region_v6.xdb) <(xxd ../../data/ip2region_v6.xdb)
+1c1
+< 00000000: 0300 0100 a02f 2969 f336 2f00 ff41 2902 ...../)i.6/..A).
+---
+> 00000000: 0300 0100 e0c8 f168 f336 2f00 ff41 2902 .......h.6/..A).
+```
+
+## 5. 原始数据编辑
+### 5.1. 使用说明
+* 新的IP归属地文件可以包含空行
+* 新的IP归属地文件顺序可以乱序, 程序会自动排序
+* 新的IP归属地文件顺序可以重叠, 只要无二义性, 程序会自动合并
+* 最终的结果会将相邻的且归属地相同的行自动合并
+* 以下测试, 原文件使用仓库自带的数据文件, 新文件使用当前目录下的 1.txt
+
+### 5.2. 数据正确性测试 -- ipv4
+#### 测试一: 测试数据文件包含空行以及重复的情况
+```
+$ cat -n 1.txt
+ 1
+ 2 1.0.128.0|1.0.128.255|测试归属地
+ 3
+ 4 1.0.128.0|1.0.128.255|测试归属地
+ 5
+$ ./bin/edit_v4
+took: 0.80s
+$ git diff ../../data/
+diff --git a/data/ipv4_source.txt b/data/ipv4_source.txt
+index 00dacc3..5d1fdfa 100644
+--- a/data/ipv4_source.txt
++++ b/data/ipv4_source.txt
+@@ -7,7 +7,7 @@
+ 1.0.32.0|1.0.63.255|中国|广东省|广州市|电信
+ 1.0.64.0|1.0.79.255|日本|广岛县|0|0
+ 1.0.80.0|1.0.127.255|日本|冈山县|0|0
+-1.0.128.0|1.0.128.255|泰国|清莱府|0|TOT
++1.0.128.0|1.0.128.255|测试归属地
+ 1.0.129.0|1.0.132.191|泰国|曼谷|曼谷|TOT
+ 1.0.132.192|1.0.132.255|泰国|Nakhon-Ratchasima|0|TOT
+ 1.0.133.0|1.0.133.255|泰国|素攀武里府|0|TOT
+```
+
+#### 测试二: 测试数据文件乱序以及数据有交叉, 归属地相同的情况
+```
+$ cat 1.txt
+1.0.128.5|1.0.128.255|测试归属地
+1.0.128.0|1.0.128.9|测试归属地
+$ ./bin/edit_v4
+took: 0.88s
+$ git diff ../../data/
+diff --git a/data/ipv4_source.txt b/data/ipv4_source.txt
+index 00dacc3..5d1fdfa 100644
+--- a/data/ipv4_source.txt
++++ b/data/ipv4_source.txt
+@@ -7,7 +7,7 @@
+ 1.0.32.0|1.0.63.255|中国|广东省|广州市|电信
+ 1.0.64.0|1.0.79.255|日本|广岛县|0|0
+ 1.0.80.0|1.0.127.255|日本|冈山县|0|0
+-1.0.128.0|1.0.128.255|泰国|清莱府|0|TOT
++1.0.128.0|1.0.128.255|测试归属地
+ 1.0.129.0|1.0.132.191|泰国|曼谷|曼谷|TOT
+ 1.0.132.192|1.0.132.255|泰国|Nakhon-Ratchasima|0|TOT
+ 1.0.133.0|1.0.133.255|泰国|素攀武里府|0|TOT
+```
+
+#### 测试三: 测试数据文件重叠, 归属地相同的情况
+```
+$ cat 1.txt
+1.0.128.0|1.0.128.8|测试归属地
+1.0.128.7|1.0.128.255|测试归属地
+$ ./bin/edit_v4
+took: 0.91s
+$ git diff ../../data/
+diff --git a/data/ipv4_source.txt b/data/ipv4_source.txt
+index 00dacc3..5d1fdfa 100644
+--- a/data/ipv4_source.txt
++++ b/data/ipv4_source.txt
+@@ -7,7 +7,7 @@
+ 1.0.32.0|1.0.63.255|中国|广东省|广州市|电信
+ 1.0.64.0|1.0.79.255|日本|广岛县|0|0
+ 1.0.80.0|1.0.127.255|日本|冈山县|0|0
+-1.0.128.0|1.0.128.255|泰国|清莱府|0|TOT
++1.0.128.0|1.0.128.255|测试归属地
+ 1.0.129.0|1.0.132.191|泰国|曼谷|曼谷|TOT
+ 1.0.132.192|1.0.132.255|泰国|Nakhon-Ratchasima|0|TOT
+ 1.0.133.0|1.0.133.255|泰国|素攀武里府|0|TOT
+```
+
+#### 测试四: 测试数据文件重叠, 归属地相同的情况
+```
+$ cat 1.txt
+1.0.128.0|1.0.128.8|测试归属地
+1.0.128.8|1.0.128.255|测试归属地
+$ ./bin/edit_v4
+took: 0.81s
+git diff ../../data
+diff --git a/data/ipv4_source.txt b/data/ipv4_source.txt
+index 00dacc3..5d1fdfa 100644
+--- a/data/ipv4_source.txt
++++ b/data/ipv4_source.txt
+@@ -7,7 +7,7 @@
+ 1.0.32.0|1.0.63.255|中国|广东省|广州市|电信
+ 1.0.64.0|1.0.79.255|日本|广岛县|0|0
+ 1.0.80.0|1.0.127.255|日本|冈山县|0|0
+-1.0.128.0|1.0.128.255|泰国|清莱府|0|TOT
++1.0.128.0|1.0.128.255|测试归属地
+ 1.0.129.0|1.0.132.191|泰国|曼谷|曼谷|TOT
+ 1.0.132.192|1.0.132.255|泰国|Nakhon-Ratchasima|0|TOT
+ 1.0.133.0|1.0.133.255|泰国|素攀武里府|0|TOT
+```
+
+#### 测试五: 测试数据文件连接, 归属地相同的情况
+```
+$ cat 1.txt
+1.0.128.0|1.0.128.8|测试归属地
+1.0.128.9|1.0.128.255|测试归属地
+$ ./bin/edit_v4
+took: 0.71s
+git diff ../../data
+diff --git a/data/ipv4_source.txt b/data/ipv4_source.txt
+index 00dacc3..5d1fdfa 100644
+--- a/data/ipv4_source.txt
++++ b/data/ipv4_source.txt
+@@ -7,7 +7,7 @@
+ 1.0.32.0|1.0.63.255|中国|广东省|广州市|电信
+ 1.0.64.0|1.0.79.255|日本|广岛县|0|0
+ 1.0.80.0|1.0.127.255|日本|冈山县|0|0
+-1.0.128.0|1.0.128.255|泰国|清莱府|0|TOT
++1.0.128.0|1.0.128.255|测试归属地
+ 1.0.129.0|1.0.132.191|泰国|曼谷|曼谷|TOT
+ 1.0.132.192|1.0.132.255|泰国|Nakhon-Ratchasima|0|TOT
+ 1.0.133.0|1.0.133.255|泰国|素攀武里府|0|TOT
+```
+
+#### 测试六: 测试数据文件重叠, 归属地不同情况
+```
+$ cat 1.txt
+1.0.128.0|1.0.128.8|测试归属地123
+1.0.128.8|1.0.128.255|测试归属地
+$ ./bin/edit_v4
+数据有二义性: 1.0.128.0|1.0.128.8|测试归属地123, 1.0.128.8|1.0.128.255|测试归属地
+```
+
+#### 测试七: 测试数据文件连接, 归属地不同情况
+```
+$ cat 1.txt
+1.0.128.0|1.0.128.8|测试归属地123
+1.0.128.9|1.0.128.255|测试归属地
+$ ./bin/edit_v4
+took: 0.75s
+git diff ../../data
+diff --git a/data/ipv4_source.txt b/data/ipv4_source.txt
+index 00dacc3..976e6bf 100644
+--- a/data/ipv4_source.txt
++++ b/data/ipv4_source.txt
+@@ -7,7 +7,8 @@
+ 1.0.32.0|1.0.63.255|中国|广东省|广州市|电信
+ 1.0.64.0|1.0.79.255|日本|广岛县|0|0
+ 1.0.80.0|1.0.127.255|日本|冈山县|0|0
+-1.0.128.0|1.0.128.255|泰国|清莱府|0|TOT
++1.0.128.0|1.0.128.8|测试归属地123
++1.0.128.9|1.0.128.255|测试归属地
+ 1.0.129.0|1.0.132.191|泰国|曼谷|曼谷|TOT
+ 1.0.132.192|1.0.132.255|泰国|Nakhon-Ratchasima|0|TOT
+ 1.0.133.0|1.0.133.255|泰国|素攀武里府|0|TOT
+```
+
+#### 测试八: 测试将一个IP数据拆成多个IP
+```
+$ cat 1.txt
+36.136.1.0|36.136.7.255|中国|0|广西|来宾市|移动
+36.136.8.0|36.136.15.255|中国|0|广西|玉林市|移动
+36.136.16.0|36.136.23.255|中国|0|广西|河池市|移动
+$ ./bin/edit_v4
+took: 0.80s
+git diff ../../data
+diff --git a/data/ipv4_source.txt b/data/ipv4_source.txt
+index 00dacc3..f895c2f 100644
+--- a/data/ipv4_source.txt
++++ b/data/ipv4_source.txt
+@@ -54778,7 +54778,11 @@
+ 36.134.84.0|36.134.85.255|中国|安徽省|合肥市|移动
+ 36.134.86.0|36.134.87.255|中国|广西|南宁市|移动
+ 36.134.88.0|36.134.89.255|中国|内蒙古|呼和浩特市|移动
+-36.134.90.0|36.141.255.255|中国|0|0|移动
++36.134.90.0|36.136.0.255|中国|0|0|移动
++36.136.1.0|36.136.7.255|中国|0|广西|来宾市|移动
++36.136.8.0|36.136.15.255|中国|0|广西|玉林市|移动
++36.136.16.0|36.136.23.255|中国|0|广西|河池市|移动
++36.136.24.0|36.141.255.255|中国|0|0|移动
+ 36.142.0.0|36.142.1.255|中国|四川省|成都市|移动
+ 36.142.2.0|36.142.31.255|中国|甘肃省|兰州市|移动
+ 36.142.32.0|36.142.127.255|中国|甘肃省|0|移动
+```
+
+#### 测试九: 测试将多个IP数据并成一个IP数据
+```
+$ cat 1.txt
+1.0.16.0|1.0.127.255|测试归属地
+$ ./bin/edit_v4
+took: 0.76s
+git diff ../../data
+diff --git a/data/ipv4_source.txt b/data/ipv4_source.txt
+index 00dacc3..756354c 100644
+--- a/data/ipv4_source.txt
++++ b/data/ipv4_source.txt
+@@ -3,10 +3,7 @@
+ 1.0.1.0|1.0.3.255|中国|福建省|福州市|电信
+ 1.0.4.0|1.0.7.255|澳大利亚|维多利亚|墨尔本|0
+ 1.0.8.0|1.0.15.255|中国|广东省|广州市|电信
+-1.0.16.0|1.0.31.255|日本|0|0|0
+-1.0.32.0|1.0.63.255|中国|广东省|广州市|电信
+-1.0.64.0|1.0.79.255|日本|广岛县|0|0
+-1.0.80.0|1.0.127.255|日本|冈山县|0|0
++1.0.16.0|1.0.127.255|测试归属地
+ 1.0.128.0|1.0.128.255|泰国|清莱府|0|TOT
+ 1.0.129.0|1.0.132.191|泰国|曼谷|曼谷|TOT
+ 1.0.132.192|1.0.132.255|泰国|Nakhon-Ratchasima|0|TOT
+```
+
+### 5.3 数据正确性测试 -- ipv6
+#### 测试一: 测试数据文件包含空行以及重复的情况
+```
+$ cat -n 1.txt
+ 1
+ 2 2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|测试归属地
+ 3
+ 4 2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|测试归属地
+ 5
+$ ./bin/edit_v6
+took: 1.74s
+git diff ../../data
+diff --git a/data/ipv6_source.txt b/data/ipv6_source.txt
+index 4dee31b..29617c4 100644
+--- a/data/ipv6_source.txt
++++ b/data/ipv6_source.txt
+@@ -2,7 +2,7 @@
+ 2001:200::|2001:200:101:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:102::|2001:200:104:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:105::|2001:200:11f:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
++2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|测试归属地
+ 2001:200:123::|2001:200:123:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:124::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:12a::|2001:200:12a:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+```
+
+#### 测试二: 测试数据文件乱序以及数据有交叉, 归属地相同的情况
+```
+$ cat 1.txt
+2001:200:121::|2001:200:125:ffff:ffff:ffff:ffff:ffff|测试归属地
+2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|测试归属地
+$ ./bin/edit_v6
+took: 1.68s
+git diff ../../data
+diff --git a/data/ipv6_source.txt b/data/ipv6_source.txt
+index 4dee31b..9e83b03 100644
+--- a/data/ipv6_source.txt
++++ b/data/ipv6_source.txt
+@@ -2,9 +2,8 @@
+ 2001:200::|2001:200:101:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:102::|2001:200:104:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:105::|2001:200:11f:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+-2001:200:123::|2001:200:123:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:124::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
++2001:200:120::|2001:200:125:ffff:ffff:ffff:ffff:ffff|测试归属地
++2001:200:126::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:12a::|2001:200:12a:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:12b::|2001:200:130:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:131::|2001:200:132:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+```
+
+#### 测试三: 测试数据文件重叠, 归属地相同的情况
+```
+$ cat 1.txt
+2001:200:120::|2001:200:125:ffff:ffff:ffff:ffff:ffff|测试归属地
+2001:200:125::|2001:200:126:ffff:ffff:ffff:ffff:ffff|测试归属地
+$ ./bin/edit_v6
+took: 1.75s
+git diff ../../data
+diff --git a/data/ipv6_source.txt b/data/ipv6_source.txt
+index 4dee31b..7a23ba2 100644
+--- a/data/ipv6_source.txt
++++ b/data/ipv6_source.txt
+@@ -2,9 +2,8 @@
+ 2001:200::|2001:200:101:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:102::|2001:200:104:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:105::|2001:200:11f:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+-2001:200:123::|2001:200:123:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:124::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
++2001:200:120::|2001:200:126:ffff:ffff:ffff:ffff:ffff|测试归属地
++2001:200:127::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:12a::|2001:200:12a:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:12b::|2001:200:130:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:131::|2001:200:132:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+```
+
+#### 测试四: 测试数据文件重叠, 归属地相同的情况
+```
+$ cat 1.txt
+2001:200:120::|2001:200:125::|测试归属地
+2001:200:125::|2001:200:126:ffff:ffff:ffff:ffff:ffff|测试归属地
+$ ./bin/edit_v6
+took: 1.46s
+git diff ../../data
+diff --git a/data/ipv6_source.txt b/data/ipv6_source.txt
+index 4dee31b..7a23ba2 100644
+--- a/data/ipv6_source.txt
++++ b/data/ipv6_source.txt
+@@ -2,9 +2,8 @@
+ 2001:200::|2001:200:101:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:102::|2001:200:104:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:105::|2001:200:11f:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+-2001:200:123::|2001:200:123:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:124::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
++2001:200:120::|2001:200:126:ffff:ffff:ffff:ffff:ffff|测试归属地
++2001:200:127::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:12a::|2001:200:12a:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:12b::|2001:200:130:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:131::|2001:200:132:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+```
+
+#### 测试五: 测试数据文件连接, 归属地相同的情况
+```
+$ cat 1.txt
+2001:200:120::|2001:200:125:ffff:ffff:ffff:ffff:ffff|测试归属地
+2001:200:126::|2001:200:126:ffff:ffff:ffff:ffff:ffff|测试归属地
+$ ./bin/edit_v6
+took: 1.79s
+git diff ../../data
+diff --git a/data/ipv6_source.txt b/data/ipv6_source.txt
+index 4dee31b..7a23ba2 100644
+--- a/data/ipv6_source.txt
++++ b/data/ipv6_source.txt
+@@ -2,9 +2,8 @@
+ 2001:200::|2001:200:101:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:102::|2001:200:104:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:105::|2001:200:11f:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+-2001:200:123::|2001:200:123:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:124::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
++2001:200:120::|2001:200:126:ffff:ffff:ffff:ffff:ffff|测试归属地
++2001:200:127::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:12a::|2001:200:12a:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:12b::|2001:200:130:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:131::|2001:200:132:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+```
+
+#### 测试六: 测试数据文件重叠, 归属地不同情况
+```
+$ cat 1.txt
+2001:200:120::|2001:200:126::|测试归属地123
+2001:200:126::|2001:200:126:ffff:ffff:ffff:ffff:ffff|测试归属地
+$ ./bin/edit_v6
+数据有二义性: 2001:200:120::|2001:200:126::|测试归属地123, 2001:200:126::|2001:200:126:ffff:ffff:ffff:ffff:ffff|测试归属地
+```
+
+#### 测试七: 测试数据文件连接, 归属地不同情况
+```
+$ cat 1.txt
+2001:200:120::|2001:200:125:ffff:ffff:ffff:ffff:ffff|测试归属地123
+2001:200:126::|2001:200:126:ffff:ffff:ffff:ffff:ffff|测试归属地
+$ ./bin/edit_v6
+took: 1.78s
+git diff ../../data
+diff --git a/data/ipv6_source.txt b/data/ipv6_source.txt
+index 4dee31b..142f7cc 100644
+--- a/data/ipv6_source.txt
++++ b/data/ipv6_source.txt
+@@ -2,9 +2,9 @@
+ 2001:200::|2001:200:101:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:102::|2001:200:104:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:105::|2001:200:11f:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+-2001:200:123::|2001:200:123:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:124::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
++2001:200:120::|2001:200:125:ffff:ffff:ffff:ffff:ffff|测试归属地123
++2001:200:126::|2001:200:126:ffff:ffff:ffff:ffff:ffff|测试归属地
++2001:200:127::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:12a::|2001:200:12a:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:12b::|2001:200:130:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:131::|2001:200:132:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+```
+
+#### 测试八: 测试将一个IP数据拆成多个IP
+```
+$ cat 1.txt
+2001:200:105::|2001:200:11f:ffff:ffff:ffff:ffff:ff11|测试归属地1
+2001:200:11f:ffff:ffff:ffff:ffff:ff12|2001:200:11f:ffff:ffff:ffff:ffff:ff33|测试归属地2
+2001:200:11f:ffff:ffff:ffff:ffff:ff34|2001:200:11f:ffff:ffff:ffff:ffff:ffff|测试归属地3
+$ ./bin/edit_v6
+took: 1.52s
+git diff ../../data
+diff --git a/data/ipv6_source.txt b/data/ipv6_source.txt
+index 4dee31b..e450e27 100644
+--- a/data/ipv6_source.txt
++++ b/data/ipv6_source.txt
+@@ -1,7 +1,9 @@
+ 1:1::|2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff|0|0|内网IP|内网IP
+ 2001:200::|2001:200:101:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:102::|2001:200:104:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+-2001:200:105::|2001:200:11f:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
++2001:200:105::|2001:200:11f:ffff:ffff:ffff:ffff:ff11|测试归属地1
++2001:200:11f:ffff:ffff:ffff:ffff:ff12|2001:200:11f:ffff:ffff:ffff:ffff:ff33|测试归属地2
++2001:200:11f:ffff:ffff:ffff:ffff:ff34|2001:200:11f:ffff:ffff:ffff:ffff:ffff|测试归属地3
+ 2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:123::|2001:200:123:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:124::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+```
+
+#### 测试九: 测试将多个IP数据并成一个IP数据
+```
+$ cat 1.txt
+2001:200:123::|2001:200:12a:ffff:ffff:ffff:ffff:ffff|测试归属地
+$ ./bin/edit_v6
+took: 1.99s
+git diff ../../data
+diff --git a/data/ipv6_source.txt b/data/ipv6_source.txt
+index 4dee31b..ecd29c3 100644
+--- a/data/ipv6_source.txt
++++ b/data/ipv6_source.txt
+@@ -3,9 +3,7 @@
+ 2001:200:102::|2001:200:104:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:105::|2001:200:11f:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:120::|2001:200:122:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+-2001:200:123::|2001:200:123:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+-2001:200:124::|2001:200:129:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+-2001:200:12a::|2001:200:12a:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
++2001:200:123::|2001:200:12a:ffff:ffff:ffff:ffff:ffff|测试归属地
+ 2001:200:12b::|2001:200:130:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
+ 2001:200:131::|2001:200:132:ffff:ffff:ffff:ffff:ffff|日本|神奈川县|藤泽市|专线用户
+ 2001:200:133::|2001:200:135:ffff:ffff:ffff:ffff:ffff|日本|东京都|千代田区|专线用户
```
diff --git a/binding/cpp/src/base.cc b/binding/cpp/src/base.cc
new file mode 100644
index 0000000..7493483
--- /dev/null
+++ b/binding/cpp/src/base.cc
@@ -0,0 +1,74 @@
+
+#include "base.h"
+
+namespace xdb {
+
+int ip_version; // ip 版本
+int ip_size; // ip 占的字节数
+int content_size;
+
+void init_xdb(int version) {
+ ip_version = version;
+ ip_size = version == ipv4 ? 4 : 16;
+ content_size = ip_size * 2 + 2 + 4;
+}
+
+void log_exit(const string &msg) {
+ std::cout << msg << std::endl;
+ exit(-1);
+}
+
+void read_bin(int index, char *buf, size_t len, FILE *db) {
+ fseek(db, index, SEEK_SET);
+ if (fread(buf, 1, len, db) != len)
+ log_exit(__func__);
+}
+
+unsigned to_uint(const char *buf) {
+ return ((buf[0]) & 0x000000FF) | ((buf[1] << 8) & 0x0000FF00) |
+ ((buf[2] << 16) & 0x00FF0000) | ((buf[3] << 24) & 0xFF000000);
+}
+
+unsigned to_ushort(const char *buf) {
+ return ((buf[0]) & 0x000000FF) | ((buf[1] << 8) & 0x0000FF00);
+}
+
+unsigned to_int(const char *buf, int n) {
+ return n == 2 ? to_ushort(buf) : to_uint(buf);
+}
+
+void write_uint(unsigned data, char buf[]) {
+ buf[0] = (data >> 0) & 0xFF;
+ buf[1] = (data >> 8) & 0xFF;
+ buf[2] = (data >> 16) & 0xFF;
+ buf[3] = (data >> 24) & 0xFF;
+}
+
+void write_uint(unsigned data, FILE *dst) {
+ char buf[4];
+ write_uint(data, buf);
+ fwrite(buf, 1, sizeof(buf), dst);
+}
+
+void write_ushort(unsigned data, char buf[]) {
+ buf[0] = (data >> 0) & 0xFF;
+ buf[1] = (data >> 8) & 0xFF;
+}
+
+void write_ushort(unsigned data, FILE *dst) {
+ char buf[2];
+ write_ushort(data, buf);
+ fwrite(buf, 1, sizeof(buf), dst);
+}
+
+void write_string(const char *buf, unsigned len, FILE *dst) {
+ fwrite(buf, 1, len, dst);
+}
+
+unsigned long long get_time() {
+ struct timeval tv1;
+ gettimeofday(&tv1, NULL);
+ return (unsigned long long)tv1.tv_sec * 1000 * 1000 + tv1.tv_usec;
+}
+
+} // namespace xdb
diff --git a/binding/cpp/src/base.h b/binding/cpp/src/base.h
new file mode 100644
index 0000000..287b038
--- /dev/null
+++ b/binding/cpp/src/base.h
@@ -0,0 +1,58 @@
+#ifndef BASE_H
+#define BASE_H
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include