github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/graph/iterator/map.go (about)

     1  // Copyright ©2020 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  // Copyright 2009 The Go Authors. All rights reserved.
     6  // Use of this source code is governed by a BSD-style
     7  // license that can be found in the LICENSE file.
     8  
     9  // +build !safe
    10  
    11  package iterator
    12  
    13  import (
    14  	"unsafe"
    15  
    16  	"github.com/jingcheng-WU/gonum/graph"
    17  )
    18  
    19  // A mapIter is an iterator for ranging over a map.
    20  type mapIter struct {
    21  	m  *emptyInterface
    22  	it unsafe.Pointer
    23  }
    24  
    25  type emptyInterface struct {
    26  	typ, word unsafe.Pointer
    27  }
    28  
    29  // newMapIterNodes returns a range iterator for a map of nodes.
    30  func newMapIterNodes(m map[int64]graph.Node) *mapIter {
    31  	return &mapIter{m: eface(m)}
    32  }
    33  
    34  // newMapIterEdges returns a range iterator for a map of edges.
    35  // The returned mapIter must not have its node method called.
    36  func newMapIterEdges(m map[int64]graph.Edge) *mapIter {
    37  	return &mapIter{m: eface(m)}
    38  }
    39  
    40  // newMapIterWeightedEdges returns a range iterator for a map of edges.
    41  // The returned mapIter must not have its node method called.
    42  func newMapIterWeightedEdges(m map[int64]graph.WeightedEdge) *mapIter {
    43  	return &mapIter{m: eface(m)}
    44  }
    45  
    46  // newMapIterLines returns a range iterator for a map of edges.
    47  // The returned mapIter must not have its node method called.
    48  func newMapIterLines(m map[int64]map[int64]graph.Line) *mapIter {
    49  	return &mapIter{m: eface(m)}
    50  }
    51  
    52  // newMapIterWeightedLines returns a range iterator for a map of edges.
    53  // The returned mapIter must not have its node method called.
    54  func newMapIterWeightedLines(m map[int64]map[int64]graph.WeightedLine) *mapIter {
    55  	return &mapIter{m: eface(m)}
    56  }
    57  
    58  func eface(i interface{}) *emptyInterface {
    59  	return (*emptyInterface)(unsafe.Pointer(&i))
    60  }
    61  
    62  // id returns the key of the iterator's current map entry.
    63  func (it *mapIter) id() int64 {
    64  	if it.it == nil {
    65  		panic("mapIter.id called before Next")
    66  	}
    67  	if mapiterkey(it.it) == nil {
    68  		panic("mapIter.id called on exhausted iterator")
    69  	}
    70  	return *(*int64)(mapiterkey(it.it))
    71  }
    72  
    73  // node returns the value of the iterator's current map entry.
    74  func (it *mapIter) node() graph.Node {
    75  	if it.it == nil {
    76  		panic("mapIter.node called before next")
    77  	}
    78  	if mapiterkey(it.it) == nil {
    79  		panic("mapIter.node called on exhausted iterator")
    80  	}
    81  	return *(*graph.Node)(mapiterelem(it.it))
    82  }
    83  
    84  // next advances the map iterator and reports whether there is another
    85  // entry. It returns false when the iterator is exhausted; subsequent
    86  // calls to Key, Value, or next will panic.
    87  func (it *mapIter) next() bool {
    88  	if it.it == nil {
    89  		it.it = mapiterinit(it.m.typ, it.m.word)
    90  	} else {
    91  		if mapiterkey(it.it) == nil {
    92  			panic("mapIter.next called on exhausted iterator")
    93  		}
    94  		mapiternext(it.it)
    95  	}
    96  	return mapiterkey(it.it) != nil
    97  }
    98  
    99  // m escapes into the return value, but the caller of mapiterinit
   100  // doesn't let the return value escape.
   101  //go:linkname mapiterinit reflect.mapiterinit
   102  //go:noescape
   103  func mapiterinit(t, m unsafe.Pointer) unsafe.Pointer
   104  
   105  //go:linkname mapiterkey reflect.mapiterkey
   106  //go:noescape
   107  func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
   108  
   109  //go:linkname mapiterelem reflect.mapiterelem
   110  //go:noescape
   111  func mapiterelem(it unsafe.Pointer) (elem unsafe.Pointer)
   112  
   113  //go:linkname mapiternext reflect.mapiternext
   114  //go:noescape
   115  func mapiternext(it unsafe.Pointer)