10 "github.com/edsrzf/mmap-go"
13 // The packed format is an 8 byte integer of the number of ranges. Then 20
14 // bytes per range, consisting of 4 byte packed IP being the lower bound IP of
15 // the range, then 4 bytes of the upper, inclusive bound, 8 bytes for the
16 // offset of the description from the end of the packed ranges, and 4 bytes
17 // for the length of the description. After these packed ranges, are the
18 // concatenated descriptions.
21 packedRangesOffset = 8
25 func (ipl *IPList) WritePacked(w io.Writer) (err error) {
26 descOffsets := make(map[string]int64, len(ipl.ranges))
27 descs := make([]string, 0, len(ipl.ranges))
29 // This is a little monadic, no?
30 write := func(b []byte, expectedLen int) {
44 binary.LittleEndian.PutUint64(b[:], uint64(len(ipl.ranges)))
46 for _, r := range ipl.ranges {
47 write(r.First.To16(), 16)
48 write(r.Last.To16(), 16)
49 descOff, ok := descOffsets[r.Description]
52 descOffsets[r.Description] = descOff
53 descs = append(descs, r.Description)
54 nextOffset += int64(len(r.Description))
56 binary.LittleEndian.PutUint64(b[:], uint64(descOff))
58 binary.LittleEndian.PutUint32(b[:], uint32(len(r.Description)))
61 for _, d := range descs {
62 write([]byte(d), len(d))
67 func NewFromPacked(b []byte) PackedIPList {
68 ret := PackedIPList(b)
69 minLen := packedRangesOffset + ret.len()*packedRangeLen
71 panic(fmt.Sprintf("packed len %d < %d", len(b), minLen))
76 type PackedIPList []byte
78 var _ Ranger = PackedIPList{}
80 func (pil PackedIPList) len() int {
81 return int(binary.LittleEndian.Uint64(pil[:8]))
84 func (pil PackedIPList) NumRanges() int {
88 func (pil PackedIPList) getFirst(i int) net.IP {
89 off := packedRangesOffset + packedRangeLen*i
90 return net.IP(pil[off : off+16])
93 func (pil PackedIPList) getRange(i int) (ret Range) {
94 rOff := packedRangesOffset + packedRangeLen*i
95 last := pil[rOff+16 : rOff+32]
96 descOff := int(binary.LittleEndian.Uint64(pil[rOff+32:]))
97 descLen := int(binary.LittleEndian.Uint32(pil[rOff+40:]))
98 descOff += packedRangesOffset + packedRangeLen*pil.len()
102 string(pil[descOff : descOff+descLen]),
107 func (pil PackedIPList) Lookup(ip net.IP) (r Range, ok bool) {
112 return lookup(pil.getFirst, pil.getRange, pil.len(), ip16)
115 type closerFunc func() error
117 func (me closerFunc) Close() error {
121 func MMapPackedFile(filename string) (
128 f, err := os.Open(filename)
133 mm, err := mmap.Map(f, mmap.RDONLY, 0)
140 }{NewFromPacked(mm), closerFunc(mm.Unmap)}