forked from mikioh/ipaddr
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcursor.go
More file actions
137 lines (124 loc) · 2.98 KB
/
cursor.go
File metadata and controls
137 lines (124 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright 2015 Mikio Hara. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.
package ipaddr
import (
"errors"
"net"
)
// A Cursor represents a movable indicator on single or multiple
// prefixes.
type Cursor struct {
curr, start, end ipv6Int
pi int
ps []Prefix
}
func (c *Cursor) set(pi int, ip net.IP) {
c.pi = pi
c.curr = ipToIPv6Int(ip.To16())
c.start = ipToIPv6Int(c.ps[c.pi].IP.To16())
if ip.To4() != nil {
c.end = c.ps[c.pi].lastIPv4MappedIPv6Int()
}
if ip.To16() != nil && ip.To4() == nil {
c.end = c.ps[c.pi].lastIPv6Int()
}
}
// First returns the start position on c.
func (c *Cursor) First() *Position {
return &Position{IP: c.ps[0].IP, Prefix: c.ps[0]}
}
// Last returns the end position on c.
func (c *Cursor) Last() *Position {
return &Position{IP: c.ps[len(c.ps)-1].Last(), Prefix: c.ps[len(c.ps)-1]}
}
// List returns the list of prefixes on c.
func (c *Cursor) List() []Prefix {
return c.ps
}
// Next turns to the next position on c.
// It returns nil at the end on c.
func (c *Cursor) Next() *Position {
n := c.curr.cmp(&c.end)
if n == 0 {
if c.pi == len(c.ps)-1 {
return nil
}
c.pi++
c.curr = ipToIPv6Int(c.ps[c.pi].IP.To16())
c.start = c.curr
if c.ps[c.pi].IP.To4() != nil {
c.end = c.ps[c.pi].lastIPv4MappedIPv6Int()
}
if c.ps[c.pi].IP.To16() != nil && c.ps[c.pi].IP.To4() == nil {
c.end = c.ps[c.pi].lastIPv6Int()
}
} else {
c.curr.incr()
}
return c.Pos()
}
// Pos returns the current position on c.
func (c *Cursor) Pos() *Position {
return &Position{IP: c.curr.ip(), Prefix: c.ps[c.pi]}
}
// Prev turns to the previous position on c.
// It returns nil at the start on c.
func (c *Cursor) Prev() *Position {
n := c.curr.cmp(&c.start)
if n == 0 {
if c.pi == 0 {
return nil
}
c.pi--
if c.ps[c.pi].IP.To4() != nil {
c.curr = c.ps[c.pi].lastIPv4MappedIPv6Int()
c.end = c.curr
}
if c.ps[c.pi].IP.To16() != nil && c.ps[c.pi].IP.To4() == nil {
c.curr = c.ps[c.pi].lastIPv6Int()
c.end = c.curr
}
c.start = ipToIPv6Int(c.ps[c.pi].IP.To16())
} else {
c.curr.decr()
}
return c.Pos()
}
// Reset resets all state and switches to ps.
// It uses the existing prefixes when ps is nil.
func (c *Cursor) Reset(ps []Prefix) {
ps = newSortedPrefixes(ps, sortAscending, false)
if len(ps) > 0 {
c.ps = ps
}
c.set(0, c.ps[0].IP.To16())
}
// Set sets the current position on c to pos.
func (c *Cursor) Set(pos *Position) error {
if pos == nil {
return errors.New("invalid position")
}
pi := -1
for i, p := range c.ps {
if p.Equal(&pos.Prefix) {
pi = i
break
}
}
if pi == -1 || !c.ps[pi].IPNet.Contains(pos.IP) {
return errors.New("position out of range")
}
c.set(pi, pos.IP.To16())
return nil
}
// NewCursor returns a new cursor.
func NewCursor(ps []Prefix) *Cursor {
ps = newSortedPrefixes(ps, sortAscending, false)
if len(ps) == 0 {
return nil
}
c := &Cursor{ps: ps}
c.set(0, c.ps[0].IP.To16())
return c
}