Skip to content

Commit 5ed7775

Browse files
committed
graph/{iterator,multi}: use map iterators for lines and weighted lines
1 parent c5ecad0 commit 5ed7775

9 files changed

Lines changed: 501 additions & 83 deletions

File tree

graph/iterator/lines_map.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Copyright ©2021 The Gonum Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build !safe
6+
// +build !safe
7+
8+
package iterator
9+
10+
import "gonum.org/v1/gonum/graph"
11+
12+
// Lines implements the graph.Lines interfaces.
13+
// The iteration order of Lines is randomized.
14+
type Lines struct {
15+
lines int
16+
iter *mapIter
17+
pos int
18+
curr graph.Line
19+
}
20+
21+
// NewLines returns a Lines initialized with the provided lines, a
22+
// map of line IDs to graph.Lines. No check is made that the keys
23+
// match the graph.Line IDs, and the map keys are not used.
24+
//
25+
// Behavior of the Lines is unspecified if lines is mutated after
26+
// the call to NewLines.
27+
func NewLines(lines map[int64]graph.Line) *Lines {
28+
return &Lines{lines: len(lines), iter: newMapIterLines(lines)}
29+
}
30+
31+
// Len returns the remaining number of lines to be iterated over.
32+
func (l *Lines) Len() int {
33+
return l.lines - l.pos
34+
}
35+
36+
// Next returns whether the next call of Line will return a valid line.
37+
func (l *Lines) Next() bool {
38+
if l.pos >= l.lines {
39+
return false
40+
}
41+
ok := l.iter.next()
42+
if ok {
43+
l.pos++
44+
l.curr = l.iter.line()
45+
}
46+
return ok
47+
}
48+
49+
// Line returns the current line of the iterator. Next must have been
50+
// called prior to a call to Line.
51+
func (l *Lines) Line() graph.Line {
52+
return l.curr
53+
}
54+
55+
// Reset returns the iterator to its initial state.
56+
func (l *Lines) Reset() {
57+
l.curr = nil
58+
l.pos = 0
59+
l.iter.it = nil
60+
}
61+
62+
// LineSlice returns all the remaining lines in the iterator and advances
63+
// the iterator. The order of lines within the returned slice is not
64+
// specified.
65+
func (l *Lines) LineSlice() []graph.Line {
66+
if l.Len() == 0 {
67+
return nil
68+
}
69+
lines := make([]graph.Line, 0, l.Len())
70+
for l.iter.next() {
71+
lines = append(lines, l.iter.line())
72+
}
73+
l.pos = l.lines
74+
return lines
75+
}
76+
77+
// WeightedLines implements the graph.WeightedLines interfaces.
78+
// The iteration order of WeightedLines is randomized.
79+
type WeightedLines struct {
80+
lines int
81+
iter *mapIter
82+
pos int
83+
curr graph.WeightedLine
84+
}
85+
86+
// NewWeightedLines returns a WeightedLines initialized with the provided lines, a
87+
// map of line IDs to graph.WeightedLines. No check is made that the keys
88+
// match the graph.WeightedLine IDs, and the map keys are not used.
89+
//
90+
// Behavior of the WeightedLines is unspecified if lines is mutated after
91+
// the call to NewWeightedLines.
92+
func NewWeightedLines(lines map[int64]graph.WeightedLine) *WeightedLines {
93+
return &WeightedLines{lines: len(lines), iter: newMapIterWeightedLines(lines)}
94+
}
95+
96+
// Len returns the remaining number of lines to be iterated over.
97+
func (l *WeightedLines) Len() int {
98+
return l.lines - l.pos
99+
}
100+
101+
// Next returns whether the next call of Line will return a valid line.
102+
func (l *WeightedLines) Next() bool {
103+
if l.pos >= l.lines {
104+
return false
105+
}
106+
ok := l.iter.next()
107+
if ok {
108+
l.pos++
109+
l.curr = l.iter.weightedLine()
110+
}
111+
return ok
112+
}
113+
114+
// WeightedLine returns the current line of the iterator. Next must have been
115+
// called prior to a call to WeightedLine.
116+
func (l *WeightedLines) WeightedLine() graph.WeightedLine {
117+
return l.curr
118+
}
119+
120+
// Reset returns the iterator to its initial state.
121+
func (l *WeightedLines) Reset() {
122+
l.curr = nil
123+
l.pos = 0
124+
l.iter.it = nil
125+
}
126+
127+
// WeightedLineSlice returns all the remaining lines in the iterator and advances
128+
// the iterator. The order of lines within the returned slice is not
129+
// specified.
130+
func (l *WeightedLines) WeightedLineSlice() []graph.WeightedLine {
131+
if l.Len() == 0 {
132+
return nil
133+
}
134+
lines := make([]graph.WeightedLine, 0, l.Len())
135+
for l.iter.next() {
136+
lines = append(lines, l.iter.weightedLine())
137+
}
138+
l.pos = l.lines
139+
return lines
140+
}

graph/iterator/lines_map_safe.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// Copyright ©2021 The Gonum Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build safe
6+
// +build safe
7+
8+
package iterator
9+
10+
import (
11+
"reflect"
12+
13+
"gonum.org/v1/gonum/graph"
14+
)
15+
16+
// Lines implements the graph.Lines interfaces.
17+
// The iteration order of Lines is randomized.
18+
type Lines struct {
19+
lines reflect.Value
20+
iter *reflect.MapIter
21+
pos int
22+
curr graph.Line
23+
}
24+
25+
// NewLines returns a Lines initialized with the provided lines, a
26+
// map of line IDs to graph.Lines. No check is made that the keys
27+
// match the graph.Line IDs, and the map keys are not used.
28+
//
29+
// Behavior of the Lines is unspecified if lines is mutated after
30+
// the call to NewLines.
31+
func NewLines(lines map[int64]graph.Line) *Lines {
32+
rv := reflect.ValueOf(lines)
33+
return &Lines{lines: rv, iter: rv.MapRange()}
34+
}
35+
36+
// Len returns the remaining number of lines to be iterated over.
37+
func (l *Lines) Len() int {
38+
return l.lines.Len() - l.pos
39+
}
40+
41+
// Next returns whether the next call of Line will return a valid line.
42+
func (l *Lines) Next() bool {
43+
if l.pos >= l.lines.Len() {
44+
return false
45+
}
46+
ok := l.iter.Next()
47+
if ok {
48+
l.pos++
49+
l.curr = l.iter.Value().Interface().(graph.Line)
50+
}
51+
return ok
52+
}
53+
54+
// Line returns the current line of the iterator. Next must have been
55+
// called prior to a call to Line.
56+
func (l *Lines) Line() graph.Line {
57+
return l.curr
58+
}
59+
60+
// Reset returns the iterator to its initial state.
61+
func (l *Lines) Reset() {
62+
l.curr = nil
63+
l.pos = 0
64+
l.iter = l.lines.MapRange()
65+
}
66+
67+
// LineSlice returns all the remaining lines in the iterator and advances
68+
// the iterator. The order of lines within the returned slice is not
69+
// specified.
70+
func (l *Lines) LineSlice() []graph.Line {
71+
if l.Len() == 0 {
72+
return nil
73+
}
74+
lines := make([]graph.Line, 0, l.Len())
75+
for l.iter.Next() {
76+
lines = append(lines, l.iter.Value().Interface().(graph.Line))
77+
}
78+
l.pos = l.lines.Len()
79+
return lines
80+
}
81+
82+
// WeightedLines implements the graph.WeightedLines interfaces.
83+
// The iteration order of WeightedLines is randomized.
84+
type WeightedLines struct {
85+
lines reflect.Value
86+
iter *reflect.MapIter
87+
pos int
88+
curr graph.WeightedLine
89+
}
90+
91+
// NewWeightedLines returns a WeightedLines initialized with the provided lines, a
92+
// map of line IDs to graph.WeightedLines. No check is made that the keys
93+
// match the graph.WeightedLine IDs, and the map keys are not used.
94+
//
95+
// Behavior of the WeightedLines is unspecified if lines is mutated after
96+
// the call to NewWeightedLines.
97+
func NewWeightedLines(lines map[int64]graph.WeightedLine) *WeightedLines {
98+
rv := reflect.ValueOf(lines)
99+
return &WeightedLines{lines: rv, iter: rv.MapRange()}
100+
}
101+
102+
// Len returns the remaining number of lines to be iterated over.
103+
func (l *WeightedLines) Len() int {
104+
return l.lines.Len() - l.pos
105+
}
106+
107+
// Next returns whether the next call of WeightedLine will return a valid line.
108+
func (l *WeightedLines) Next() bool {
109+
if l.pos >= l.lines.Len() {
110+
return false
111+
}
112+
ok := l.iter.Next()
113+
if ok {
114+
l.pos++
115+
l.curr = l.iter.Value().Interface().(graph.WeightedLine)
116+
}
117+
return ok
118+
}
119+
120+
// WeightedLine returns the current line of the iterator. Next must have been
121+
// called prior to a call to WeightedLine.
122+
func (l *WeightedLines) WeightedLine() graph.WeightedLine {
123+
return l.curr
124+
}
125+
126+
// Reset returns the iterator to its initial state.
127+
func (l *WeightedLines) Reset() {
128+
l.curr = nil
129+
l.pos = 0
130+
l.iter = l.lines.MapRange()
131+
}
132+
133+
// WeightedLineSlice returns all the remaining lines in the iterator and advances
134+
// the iterator. The order of lines within the returned slice is not
135+
// specified.
136+
func (l *WeightedLines) WeightedLineSlice() []graph.WeightedLine {
137+
if l.Len() == 0 {
138+
return nil
139+
}
140+
lines := make([]graph.WeightedLine, 0, l.Len())
141+
for l.iter.Next() {
142+
lines = append(lines, l.iter.Value().Interface().(graph.WeightedLine))
143+
}
144+
l.pos = l.lines.Len()
145+
return lines
146+
}

0 commit comments

Comments
 (0)