gonum.org/v1/gonum@v0.14.0/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  //go:build !safe
    10  // +build !safe
    11  
    12  package iterator
    13  
    14  import (
    15  	"unsafe"
    16  
    17  	"gonum.org/v1/gonum/graph"
    18  )
    19  
    20  // A mapIter is an iterator for ranging over a map.
    21  type mapIter struct {
    22  	m     *emptyInterface
    23  	hiter hiter
    24  }
    25  
    26  type emptyInterface struct {
    27  	typ, word unsafe.Pointer
    28  }
    29  
    30  // hiter's structure matches runtime.hiter's structure.
    31  // Having a clone here allows us to embed a map iterator
    32  // inside type mapIter so that mapIters can be re-used
    33  // without doing any allocations.
    34  //
    35  //lint:ignore U1000 This is a verbatim copy of the runtime type.
    36  type hiter struct {
    37  	key         unsafe.Pointer
    38  	elem        unsafe.Pointer
    39  	t           unsafe.Pointer
    40  	h           unsafe.Pointer
    41  	buckets     unsafe.Pointer
    42  	bptr        unsafe.Pointer
    43  	overflow    *[]unsafe.Pointer
    44  	oldoverflow *[]unsafe.Pointer
    45  	startBucket uintptr
    46  	offset      uint8
    47  	wrapped     bool
    48  	B           uint8
    49  	i           uint8
    50  	bucket      uintptr
    51  	checkBucket uintptr
    52  }
    53  
    54  func (h *hiter) initialized() bool {
    55  	return h.t != nil
    56  }
    57  
    58  // newMapIterNodes returns a range iterator for a map of nodes.
    59  // The returned mapIter must not have its line or weightedLine methods called.
    60  func newMapIterNodes(m map[int64]graph.Node) *mapIter {
    61  	return &mapIter{m: eface(m)}
    62  }
    63  
    64  // newMapIterEdges returns a range iterator for a map of edges.
    65  // The returned mapIter must not have its node, line or weightedLine methods called.
    66  func newMapIterEdges(m map[int64]graph.Edge) *mapIter {
    67  	return &mapIter{m: eface(m)}
    68  }
    69  
    70  // newMapIterLines returns a range iterator for a map of line.
    71  // The returned mapIter must not have its node or weightedLine method called.
    72  func newMapIterLines(m map[int64]graph.Line) *mapIter {
    73  	return &mapIter{m: eface(m)}
    74  }
    75  
    76  // newMapIterWeightedLines returns a range iterator for a map of line.
    77  // The returned mapIter must not have its node, line or weightedLine methods called.
    78  func newMapIterWeightedLines(m map[int64]graph.WeightedLine) *mapIter {
    79  	return &mapIter{m: eface(m)}
    80  }
    81  
    82  // newMapIterByWeightedEdges returns a range iterator for a map of edges.
    83  // The returned mapIter must not have its node, line or weightedLine methods called.
    84  func newMapIterByWeightedEdges(m map[int64]graph.WeightedEdge) *mapIter {
    85  	return &mapIter{m: eface(m)}
    86  }
    87  
    88  // newMapIterByLines returns a range iterator for a map of edges.
    89  // The returned mapIter must not have its node, line or weightedLine methods called.
    90  func newMapIterByLines(m map[int64]map[int64]graph.Line) *mapIter {
    91  	return &mapIter{m: eface(m)}
    92  }
    93  
    94  // newMapIterByWeightedLines returns a range iterator for a map of edges.
    95  // The returned mapIter must not have its node, line or weightedLine methods called.
    96  func newMapIterByWeightedLines(m map[int64]map[int64]graph.WeightedLine) *mapIter {
    97  	return &mapIter{m: eface(m)}
    98  }
    99  
   100  func eface(i interface{}) *emptyInterface {
   101  	return (*emptyInterface)(unsafe.Pointer(&i))
   102  }
   103  
   104  // id returns the key of the iterator's current map entry.
   105  func (it *mapIter) id() int64 {
   106  	if !it.hiter.initialized() {
   107  		panic("mapIter.id called before Next")
   108  	}
   109  	if mapiterkey(&it.hiter) == nil {
   110  		panic("mapIter.id called on exhausted iterator")
   111  	}
   112  	return *(*int64)(mapiterkey(&it.hiter))
   113  }
   114  
   115  // node returns the value of the iterator's current map entry.
   116  func (it *mapIter) node() graph.Node {
   117  	if !it.hiter.initialized() {
   118  		panic("mapIter.node called before next")
   119  	}
   120  	if mapiterkey(&it.hiter) == nil {
   121  		panic("mapIter.node called on exhausted iterator")
   122  	}
   123  	return *(*graph.Node)(mapiterelem(&it.hiter))
   124  }
   125  
   126  // line returns the value of the iterator's current map entry.
   127  func (it *mapIter) line() graph.Line {
   128  	if !it.hiter.initialized() {
   129  		panic("mapIter.line called before next")
   130  	}
   131  	if mapiterkey(&it.hiter) == nil {
   132  		panic("mapIter.line called on exhausted iterator")
   133  	}
   134  	return *(*graph.Line)(mapiterelem(&it.hiter))
   135  }
   136  
   137  // weightedLine returns the value of the iterator's current map entry.
   138  func (it *mapIter) weightedLine() graph.WeightedLine {
   139  	if !it.hiter.initialized() {
   140  		panic("mapIter.weightedLine called before next")
   141  	}
   142  	if mapiterkey(&it.hiter) == nil {
   143  		panic("mapIter.weightedLine called on exhausted iterator")
   144  	}
   145  	return *(*graph.WeightedLine)(mapiterelem(&it.hiter))
   146  }
   147  
   148  // next advances the map iterator and reports whether there is another
   149  // entry. It returns false when the iterator is exhausted; subsequent
   150  // calls to Key, Value, or next will panic.
   151  func (it *mapIter) next() bool {
   152  	if !it.hiter.initialized() {
   153  		mapiterinit(it.m.typ, it.m.word, &it.hiter)
   154  	} else {
   155  		if mapiterkey(&it.hiter) == nil {
   156  			panic("mapIter.next called on exhausted iterator")
   157  		}
   158  		mapiternext(&it.hiter)
   159  	}
   160  	return mapiterkey(&it.hiter) != nil
   161  }
   162  
   163  //go:linkname mapiterinit runtime.mapiterinit
   164  //go:noescape
   165  func mapiterinit(t, m unsafe.Pointer, it *hiter)
   166  
   167  //go:linkname mapiterkey reflect.mapiterkey
   168  //go:noescape
   169  func mapiterkey(it *hiter) (key unsafe.Pointer)
   170  
   171  //go:linkname mapiterelem reflect.mapiterelem
   172  //go:noescape
   173  func mapiterelem(it *hiter) (elem unsafe.Pointer)
   174  
   175  //go:linkname mapiternext reflect.mapiternext
   176  //go:noescape
   177  func mapiternext(it *hiter)