github.com/m4gshm/gollections@v0.0.13-0.20240331203319-a34a86e58a24/map_/iter.go (about)

     1  package map_
     2  
     3  import (
     4  	"unsafe"
     5  
     6  	"github.com/m4gshm/gollections/c"
     7  	"github.com/m4gshm/gollections/kv/collection"
     8  	kvloop "github.com/m4gshm/gollections/kv/loop"
     9  	"github.com/m4gshm/gollections/loop"
    10  	"github.com/m4gshm/gollections/op"
    11  )
    12  
    13  // NewIter returns the Iter based on map elements
    14  func NewIter[K comparable, V any](elements map[K]V) Iter[K, V] {
    15  	hmap := *(*unsafe.Pointer)(unsafe.Pointer(&elements))
    16  	i := any(elements)
    17  	maptype := *(*unsafe.Pointer)(unsafe.Pointer(&i))
    18  	var iterator *hiter
    19  	if hmap != nil {
    20  		iterator = new(hiter)
    21  	}
    22  	return Iter[K, V]{maptype: maptype, hmap: hmap, size: len(elements), iterator: iterator}
    23  }
    24  
    25  // Iter is the embedded map based Iterator implementation
    26  type Iter[K comparable, V any] struct {
    27  	iterator *hiter
    28  	maptype  unsafe.Pointer
    29  	hmap     unsafe.Pointer
    30  	size     int
    31  }
    32  
    33  var _ collection.Iterator[int, any] = (*Iter[int, any])(nil)
    34  
    35  // All is used to iterate through the iterator using `for ... range`. Supported since go 1.22 with GOEXPERIMENT=rangefunc enabled.
    36  func (i *Iter[K, V]) All(consumer func(key K, value V) bool) {
    37  	kvloop.All(i.Next, consumer)
    38  }
    39  
    40  // Track takes key, value pairs retrieved by the iterator. Can be interrupt by returning Break
    41  func (i *Iter[K, V]) Track(traker func(key K, value V) error) error {
    42  	return kvloop.Track(i.Next, traker)
    43  }
    44  
    45  // TrackEach takes all key, value pairs retrieved by the iterator
    46  func (i *Iter[K, V]) TrackEach(traker func(key K, value V)) {
    47  	kvloop.TrackEach(i.Next, traker)
    48  }
    49  
    50  // Next returns the next element.
    51  // The ok result indicates whether the element was returned by the iterator.
    52  // If ok == false, then the iteration must be completed.
    53  func (i *Iter[K, V]) Next() (key K, value V, ok bool) {
    54  	if i == nil {
    55  		return key, value, false
    56  	}
    57  	iterator := i.iterator
    58  	if iterator == nil {
    59  		return key, value, false
    60  	}
    61  	if !iterator.initialized() {
    62  		mapiterinit(i.maptype, i.hmap, iterator)
    63  	} else {
    64  		mapiternext(iterator)
    65  	}
    66  	iterkey := mapiterkey(iterator)
    67  	if iterkey == nil {
    68  		return key, value, false
    69  	}
    70  	iterelem := mapiterelem(iterator)
    71  	key = *(*K)(iterkey)
    72  	value = *(*V)(iterelem)
    73  	return key, value, true
    74  }
    75  
    76  // Size returns the size of the map
    77  func (i *Iter[K, V]) Size() int {
    78  	if i == nil {
    79  		return 0
    80  	}
    81  	return i.size
    82  }
    83  
    84  //go:linkname mapiterinit reflect.mapiterinit
    85  func mapiterinit(maptype, hmap unsafe.Pointer, it *hiter)
    86  
    87  func mapiterkey(it *hiter) unsafe.Pointer {
    88  	return it.key
    89  }
    90  
    91  func mapiterelem(it *hiter) unsafe.Pointer {
    92  	return it.elem
    93  }
    94  
    95  //go:linkname mapiternext reflect.mapiternext
    96  func mapiternext(it *hiter)
    97  
    98  // hiter's structure matches runtime.hiter's structure
    99  type hiter struct {
   100  	key         unsafe.Pointer
   101  	elem        unsafe.Pointer
   102  	t           unsafe.Pointer
   103  	h           unsafe.Pointer
   104  	buckets     unsafe.Pointer
   105  	bptr        unsafe.Pointer
   106  	overflow    *[]unsafe.Pointer
   107  	oldoverflow *[]unsafe.Pointer
   108  	startBucket uintptr
   109  	offset      uint8
   110  	wrapped     bool
   111  	B           uint8
   112  	i           uint8
   113  	bucket      uintptr
   114  	checkBucket uintptr
   115  }
   116  
   117  func (h *hiter) initialized() bool {
   118  	return h.t != nil
   119  }
   120  
   121  // NewKeyIter instantiates a map keys iterator
   122  func NewKeyIter[K comparable, V any](uniques map[K]V) KeyIter[K, V] {
   123  	return KeyIter[K, V]{Iter: NewIter(uniques)}
   124  }
   125  
   126  // KeyIter is the Iterator implementation that provides iterating over keys of a key/value pairs iterator
   127  type KeyIter[K comparable, V any] struct {
   128  	Iter[K, V]
   129  }
   130  
   131  var (
   132  	_ c.Iterator[string] = (*KeyIter[string, any])(nil)
   133  	_ c.Iterator[string] = KeyIter[string, any]{}
   134  )
   135  
   136  // All is used to iterate through the iterator using `for ... range`. Supported since go 1.22 with GOEXPERIMENT=rangefunc enabled.
   137  func (i KeyIter[K, V]) All(consumer func(element K) bool) {
   138  	loop.All(i.Next, consumer)
   139  }
   140  
   141  // For takes elements retrieved by the iterator. Can be interrupt by returning Break
   142  func (i KeyIter[K, V]) For(consumer func(element K) error) error {
   143  	return loop.For(i.Next, consumer)
   144  }
   145  
   146  // ForEach FlatIter all elements retrieved by the iterator
   147  func (i KeyIter[K, V]) ForEach(consumer func(element K)) {
   148  	loop.ForEach(i.Next, consumer)
   149  }
   150  
   151  // Next returns the next element.
   152  // The ok result indicates whether the element was returned by the iterator.
   153  // If ok == false, then the iteration must be completed.
   154  func (i KeyIter[K, V]) Next() (K, bool) {
   155  	key, _, ok := i.Iter.Next()
   156  	return key, ok
   157  }
   158  
   159  // Size returns the iterator capacity
   160  func (i KeyIter[K, V]) Size() int {
   161  	return i.Iter.Size()
   162  }
   163  
   164  // NewValIter is the main values iterator constructor
   165  func NewValIter[K comparable, V any](uniques map[K]V) ValIter[K, V] {
   166  	return ValIter[K, V]{Iter: NewIter(op.IfElse(uniques != nil, uniques, map[K]V{}))}
   167  }
   168  
   169  // ValIter is a map values iterator
   170  type ValIter[K comparable, V any] struct {
   171  	Iter[K, V]
   172  }
   173  
   174  var (
   175  	_ c.Iterator[any] = (*ValIter[int, any])(nil)
   176  	_ c.Iterator[any] = ValIter[int, any]{}
   177  )
   178  
   179  // All is used to iterate through the iterator using `for ... range`. Supported since go 1.22 with GOEXPERIMENT=rangefunc enabled.
   180  func (i ValIter[K, V]) All(consumer func(element V) bool) {
   181  	loop.All(i.Next, consumer)
   182  }
   183  
   184  // For takes elements retrieved by the iterator. Can be interrupt by returning Break
   185  func (i ValIter[K, V]) For(consumer func(element V) error) error {
   186  	return loop.For(i.Next, consumer)
   187  }
   188  
   189  // ForEach FlatIter all elements retrieved by the iterator
   190  func (i ValIter[K, V]) ForEach(consumer func(element V)) {
   191  	loop.ForEach(i.Next, consumer)
   192  }
   193  
   194  // Next returns the next element.
   195  // The ok result indicates whether the element was returned by the iterator.
   196  // If ok == false, then the iteration must be completed.
   197  func (i ValIter[K, V]) Next() (V, bool) {
   198  	_, val, ok := i.Iter.Next()
   199  	return val, ok
   200  }
   201  
   202  // Size returns the size of the map
   203  func (i ValIter[K, V]) Size() int {
   204  	return i.Iter.Size()
   205  }