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