mirror of
https://github.com/gonum/gonum.git
synced 2025-10-05 23:26:52 +08:00

- use SetIterValue to reduce allocations - use explicit stored iterator length goos: linux goarch: amd64 pkg: gonum.org/v1/gonum/graph/traverse cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz │ old.bench │ new.bench │ │ sec/op │ sec/op vs base │ WalkAllBreadthFirstGnp_10_tenth-8 3.575µ ± 2% 2.961µ ± 2% -17.18% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_tenth-8 144.4µ ± 1% 132.4µ ± 1% -8.33% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_tenth-8 12.66m ± 2% 12.00m ± 2% -5.20% (p=0.000 n=20) WalkAllBreadthFirstGnp_10_half-8 8.415µ ± 1% 7.615µ ± 1% -9.51% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_half-8 628.0µ ± 1% 580.7µ ± 1% -7.54% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_half-8 58.74m ± 1% 55.79m ± 2% -5.03% (p=0.000 n=20) WalkAllDepthFirstGnp_10_tenth-8 3.539µ ± 2% 2.956µ ± 1% -16.49% (p=0.000 n=20) WalkAllDepthFirstGnp_100_tenth-8 144.8µ ± 2% 135.5µ ± 1% -6.40% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_tenth-8 12.40m ± 1% 12.02m ± 1% -3.10% (p=0.000 n=20) WalkAllDepthFirstGnp_10_half-8 8.210µ ± 1% 7.423µ ± 1% -9.59% (p=0.000 n=20) WalkAllDepthFirstGnp_100_half-8 625.8µ ± 1% 598.3µ ± 1% -4.40% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_half-8 58.28m ± 1% 55.65m ± 1% -4.52% (p=0.000 n=20) geomean 353.9µ 324.8µ -8.21% │ old.bench │ new.bench │ │ B/op │ B/op vs base │ WalkAllBreadthFirstGnp_10_tenth-8 1.533Ki ± 0% 1.486Ki ± 0% -3.06% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_tenth-8 29.58Ki ± 0% 29.61Ki ± 0% +0.11% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_tenth-8 1016.3Ki ± 0% 1016.4Ki ± 0% ~ (p=0.199 n=20) WalkAllBreadthFirstGnp_10_half-8 2.689Ki ± 0% 2.721Ki ± 0% +1.16% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_half-8 61.44Ki ± 0% 61.47Ki ± 0% +0.05% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_half-8 4.036Mi ± 0% 4.036Mi ± 0% ~ (p=0.080 n=20) WalkAllDepthFirstGnp_10_tenth-8 1.533Ki ± 0% 1.486Ki ± 0% -3.06% (p=0.000 n=20) WalkAllDepthFirstGnp_100_tenth-8 29.58Ki ± 0% 29.61Ki ± 0% +0.10% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_tenth-8 1.090Mi ± 1% 1.084Mi ± 1% ~ (p=0.081 n=20) WalkAllDepthFirstGnp_10_half-8 2.689Ki ± 0% 2.721Ki ± 0% +1.16% (p=0.000 n=20) WalkAllDepthFirstGnp_100_half-8 61.57Ki ± 0% 61.59Ki ± 0% +0.04% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_half-8 6.279Mi ± 0% 6.167Mi ± 0% -1.79% (p=0.000 n=20) geomean 58.77Ki 58.48Ki -0.49% │ old.bench │ new.bench │ │ allocs/op │ allocs/op vs base │ WalkAllBreadthFirstGnp_10_tenth-8 27.00 ± 0% 17.00 ± 0% -37.04% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_tenth-8 1.188k ± 0% 1.088k ± 0% -8.42% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_tenth-8 102.1k ± 0% 101.1k ± 0% -0.98% (p=0.000 n=20) WalkAllBreadthFirstGnp_10_half-8 70.00 ± 0% 60.00 ± 0% -14.29% (p=0.000 n=20) WalkAllBreadthFirstGnp_100_half-8 5.266k ± 0% 5.166k ± 0% -1.90% (p=0.000 n=20) WalkAllBreadthFirstGnp_1000_half-8 500.9k ± 0% 499.9k ± 0% -0.20% (p=0.000 n=20) WalkAllDepthFirstGnp_10_tenth-8 27.00 ± 0% 17.00 ± 0% -37.04% (p=0.000 n=20) WalkAllDepthFirstGnp_100_tenth-8 1.188k ± 0% 1.088k ± 0% -8.42% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_tenth-8 102.1k ± 0% 101.1k ± 0% -0.98% (p=0.000 n=20) WalkAllDepthFirstGnp_10_half-8 70.00 ± 0% 60.00 ± 0% -14.29% (p=0.000 n=20) WalkAllDepthFirstGnp_100_half-8 5.266k ± 0% 5.166k ± 0% -1.90% (p=0.000 n=20) WalkAllDepthFirstGnp_1000_half-8 500.9k ± 0% 499.9k ± 0% -0.20% (p=0.000 n=20) geomean 2.908k 2.572k -11.54%
157 lines
3.9 KiB
Go
157 lines
3.9 KiB
Go
// Copyright ©2021 The Gonum Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build safe
|
|
// +build safe
|
|
|
|
package iterator
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"gonum.org/v1/gonum/graph"
|
|
)
|
|
|
|
// Lines implements the graph.Lines interfaces.
|
|
// The iteration order of Lines is randomized.
|
|
type Lines struct {
|
|
iter reflect.MapIter
|
|
pos, len int
|
|
curr graph.Line
|
|
value reflect.Value
|
|
lines reflect.Value
|
|
}
|
|
|
|
// NewLines returns a Lines initialized with the provided lines, a
|
|
// map of line IDs to graph.Lines. No check is made that the keys
|
|
// match the graph.Line IDs, and the map keys are not used.
|
|
//
|
|
// Behavior of the Lines is unspecified if lines is mutated after
|
|
// the call to NewLines.
|
|
func NewLines(lines map[int64]graph.Line) *Lines {
|
|
rv := reflect.ValueOf(lines)
|
|
l := &Lines{lines: rv, len: len(lines)}
|
|
l.iter.Reset(rv)
|
|
l.value = reflect.ValueOf(&l.curr).Elem()
|
|
return l
|
|
}
|
|
|
|
// Len returns the remaining number of lines to be iterated over.
|
|
func (l *Lines) Len() int {
|
|
return l.len - l.pos
|
|
}
|
|
|
|
// Next returns whether the next call of Line will return a valid line.
|
|
func (l *Lines) Next() bool {
|
|
if l.pos >= l.len {
|
|
return false
|
|
}
|
|
ok := l.iter.Next()
|
|
if ok {
|
|
l.pos++
|
|
l.value.SetIterValue(&l.iter)
|
|
}
|
|
return ok
|
|
}
|
|
|
|
// Line returns the current line of the iterator. Next must have been
|
|
// called prior to a call to Line.
|
|
func (l *Lines) Line() graph.Line {
|
|
return l.curr
|
|
}
|
|
|
|
// Reset returns the iterator to its initial state.
|
|
func (l *Lines) Reset() {
|
|
l.curr = nil
|
|
l.pos = 0
|
|
l.iter.Reset(l.lines)
|
|
}
|
|
|
|
// LineSlice returns all the remaining lines in the iterator and advances
|
|
// the iterator. The order of lines within the returned slice is not
|
|
// specified.
|
|
func (l *Lines) LineSlice() []graph.Line {
|
|
if l.Len() == 0 {
|
|
return nil
|
|
}
|
|
lines := make([]graph.Line, 0, l.Len())
|
|
for l.iter.Next() {
|
|
l.value.SetIterValue(&l.iter)
|
|
lines = append(lines, l.curr)
|
|
}
|
|
l.pos = l.len
|
|
return lines
|
|
}
|
|
|
|
// WeightedLines implements the graph.WeightedLines interfaces.
|
|
// The iteration order of WeightedLines is randomized.
|
|
type WeightedLines struct {
|
|
iter reflect.MapIter
|
|
pos, len int
|
|
curr graph.WeightedLine
|
|
value reflect.Value
|
|
lines reflect.Value
|
|
}
|
|
|
|
// NewWeightedLines returns a WeightedLines initialized with the provided lines, a
|
|
// map of line IDs to graph.WeightedLines. No check is made that the keys
|
|
// match the graph.WeightedLine IDs, and the map keys are not used.
|
|
//
|
|
// Behavior of the WeightedLines is unspecified if lines is mutated after
|
|
// the call to NewWeightedLines.
|
|
func NewWeightedLines(lines map[int64]graph.WeightedLine) *WeightedLines {
|
|
rv := reflect.ValueOf(lines)
|
|
l := &WeightedLines{lines: rv, len: len(lines)}
|
|
l.iter.Reset(rv)
|
|
l.value = reflect.ValueOf(&l.curr).Elem()
|
|
return l
|
|
}
|
|
|
|
// Len returns the remaining number of lines to be iterated over.
|
|
func (l *WeightedLines) Len() int {
|
|
return l.len - l.pos
|
|
}
|
|
|
|
// Next returns whether the next call of WeightedLine will return a valid line.
|
|
func (l *WeightedLines) Next() bool {
|
|
if l.pos >= l.len {
|
|
return false
|
|
}
|
|
ok := l.iter.Next()
|
|
if ok {
|
|
l.pos++
|
|
l.value.SetIterValue(&l.iter)
|
|
}
|
|
return ok
|
|
}
|
|
|
|
// WeightedLine returns the current line of the iterator. Next must have been
|
|
// called prior to a call to WeightedLine.
|
|
func (l *WeightedLines) WeightedLine() graph.WeightedLine {
|
|
return l.curr
|
|
}
|
|
|
|
// Reset returns the iterator to its initial state.
|
|
func (l *WeightedLines) Reset() {
|
|
l.curr = nil
|
|
l.pos = 0
|
|
l.iter.Reset(l.lines)
|
|
}
|
|
|
|
// WeightedLineSlice returns all the remaining lines in the iterator and advances
|
|
// the iterator. The order of lines within the returned slice is not
|
|
// specified.
|
|
func (l *WeightedLines) WeightedLineSlice() []graph.WeightedLine {
|
|
if l.Len() == 0 {
|
|
return nil
|
|
}
|
|
lines := make([]graph.WeightedLine, 0, l.Len())
|
|
for l.iter.Next() {
|
|
l.value.SetIterValue(&l.iter)
|
|
lines = append(lines, l.curr)
|
|
}
|
|
l.pos = l.len
|
|
return lines
|
|
}
|