//go:build !goexperiment.swissmap

package zgo

import "unsafe"

//go:linkname mapIterInit runtime.mapiterinit
func mapIterInit(t *MapType, m *Map, it *MapIterator)

//go:linkname mapIterNext runtime.mapiternext
func mapIterNext(it *MapIterator)

type MapIterator struct {
	Key         unsafe.Pointer // Must be in first position.  Write nil to indicate iteration end (see cmd/compile/internal/walk/range.go).
	Elem        unsafe.Pointer // Must be in second position (see cmd/compile/internal/walk/range.go).
	T           *MapType
	H           *Map
	Buckets     unsafe.Pointer    // bucket ptr at hash_iter initialization time
	Bptr        *unsafe.Pointer   // current bucket
	Overflow    *[]unsafe.Pointer // keeps overflow buckets of hmap.buckets alive
	OldOverflow *[]unsafe.Pointer // keeps overflow buckets of hmap.oldbuckets alive
	StartBucket uintptr           // bucket iteration started at
	Offset      uint8             // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1)
	Wrapped     bool              // already wrapped around from end of bucket array to beginning
	B           uint8
	I           uint8
	Bucket      uintptr
	CheckBucket uintptr
}

func (it *MapIterator) Init(t *MapType, m *Map) {
	mapIterInit(t, m, it)
}

func (it *MapIterator) Next() {
	mapIterNext(it)
}

type MapType struct {
	Type
	Key    *Type
	Elem   *Type
	Bucket *Type // internal type representing a hash bucket
	// function for hashing keys (ptr to key, seed) -> hash
	Hasher     func(unsafe.Pointer, uintptr) uintptr
	KeySize    uint8  // size of key slot
	ValueSize  uint8  // size of elem slot
	BucketSize uint16 // size of bucket
	Flags      uint32
}

type Map struct {
	Count      int // # live cells == size of map.  Must be first (used by len() builtin)
	Flags      uint8
	B          uint8          // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
	NOverflow  uint16         // approximate number of overflow buckets; see incrnoverflow for details
	Hash0      uint32         // hash seed
	Buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
	OldBuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
	NEvacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
	Extra      unsafe.Pointer // optional fields
}

func (m *Map) Len() int {
	return m.Count
}
