// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package maps

import (
	
	
	
	
	
)

//go:linkname runtime_mapaccess1_fast64 runtime.mapaccess1_fast64
func ( *abi.MapType,  *Map,  uint64) unsafe.Pointer {
	,  := runtime_mapaccess2_fast64(, , )
	return 
}

//go:linkname runtime_mapaccess2_fast64 runtime.mapaccess2_fast64
func ( *abi.MapType,  *Map,  uint64) (unsafe.Pointer, bool) {
	if race.Enabled &&  != nil {
		 := sys.GetCallerPC()
		 := abi.FuncPCABIInternal()
		race.ReadPC(unsafe.Pointer(), , )
	}

	if  == nil || .Used() == 0 {
		return unsafe.Pointer(&zeroVal[0]), false
	}

	if .writing != 0 {
		fatal("concurrent map read and map write")
		return nil, false
	}

	if .dirLen == 0 {
		 := groupReference{
			data: .dirPtr,
		}
		 := .ctrls().matchFull()
		 := .key(, 0)
		var  uintptr
		if goexperiment.MapSplitGroup {
			 = 8 // keys are contiguous in split layout
		} else {
			 = .KeyStride // == SlotSize in interleaved layout
		}
		var  uintptr
		for  != 0 {
			if  == *(*uint64)() && .lowestSet() {
				if goexperiment.MapSplitGroup {
					return .elem(, ), true
				} else {
					return unsafe.Pointer(uintptr() + 8), true
				}
			}
			 = unsafe.Pointer(uintptr() + )
			 = .shiftOutLowest()
			++
		}
		return unsafe.Pointer(&zeroVal[0]), false
	}

	var  uintptr
	// See the related comment in runtime_mapaccess2_fast32
	if memHashAESImplemented && UseAeshash {
		 = memHash64AES(, .seed)
	} else {
		 = memHash64Fallback(, .seed)
	}

	// Select table.
	 := .directoryIndex()
	 := .directoryAt()

	// Probe table.
	 := makeProbeSeq(h1(), .groups.lengthMask)

	 := h2()
	for ; ;  = .next() {
		 := .groups.group(, .offset)

		 := .ctrls().matchH2()

		for  != 0 {
			 := .first()

			 := .key(, )
			if  == *(*uint64)() {
				if goexperiment.MapSplitGroup {
					return .elem(, ), true
				} else {
					return unsafe.Pointer(uintptr() + 8), true
				}
			}
			 = .removeFirst()
		}

		 = .ctrls().matchEmpty()
		if  != 0 {
			// Finding an empty slot means we've reached the end of
			// the probe sequence.
			return unsafe.Pointer(&zeroVal[0]), false
		}
	}
}

func ( *Map) ( *abi.MapType,  uintptr,  uint64) unsafe.Pointer {
	 := groupReference{
		data: .dirPtr,
	}

	 := .ctrls().matchH2(h2())

	// Look for an existing slot containing this key.
	for  != 0 {
		 := .first()

		 := .key(, )
		if  == *(*uint64)() {
			 := .elem(, )
			return 
		}
		 = .removeFirst()
	}

	// There can't be deleted slots, small maps can't have them
	// (see deleteSmall). Use matchEmptyOrDeleted as it is a bit
	// more efficient than matchEmpty.
	 = .ctrls().matchEmptyOrDeleted()
	if  == 0 {
		// No empty slot found. Need to grow the map.
		return nil
	}

	 := .first()

	 := .key(, )
	*(*uint64)() = 

	 := .elem(, )

	.ctrls().set(, ctrl(h2()))
	.used++

	return 
}

func ( *table) ( *abi.MapType,  uintptr,  uint64) unsafe.Pointer {
	if .growthLeft == 0 {
		panic("invariant failed: growthLeft is unexpectedly 0")
	}

	// Given key and its hash hash(key), to insert it, we construct a
	// probeSeq, and use it to find the first group with an unoccupied (empty
	// or deleted) slot. We place the key/value into the first such slot in
	// the group and mark it as full with key's H2.
	 := makeProbeSeq(h1(), .groups.lengthMask)
	for ; ;  = .next() {
		 := .groups.group(, .offset)

		 := .ctrls().matchEmptyOrDeleted()
		if  != 0 {
			 := .first()

			 := .key(, )
			*(*uint64)() = 

			 := .elem(, )

			.growthLeft--
			.used++
			.ctrls().set(, ctrl(h2()))
			return 
		}
	}
}

//go:linkname runtime_mapassign_fast64 runtime.mapassign_fast64
func ( *abi.MapType,  *Map,  uint64) unsafe.Pointer {
	if  == nil {
		panic(errNilAssign)
	}
	if race.Enabled {
		 := sys.GetCallerPC()
		 := abi.FuncPCABIInternal()
		race.WritePC(unsafe.Pointer(), , )
	}
	if .writing != 0 {
		fatal("concurrent map writes")
	}

	var  uintptr
	// See the related comment in runtime_mapaccess2_fast32
	if memHashAESImplemented && UseAeshash {
		 = memHash64AES(, .seed)
	} else {
		 = memHash64Fallback(, .seed)
	}

	// Set writing after calling Hasher, since Hasher may panic, in which
	// case we have not actually done a write.
	.writing ^= 1 // toggle, see comment on writing

	if .dirPtr == nil {
		.growToSmall()
	}

	if .dirLen == 0 {
		 := .putSlotSmallFast64(, , )
		if  == nil {
			// Can't fit another entry, grow to full size map.
			 := .growToTable()

			 = .uncheckedPutSlotForAssignFast64(, , )
			.used++

			.checkInvariants(, )
		}

		if .writing == 0 {
			fatal("concurrent map writes")
		}
		.writing ^= 1

		return 
	}

	var  unsafe.Pointer
:
	for {
		// Select table.
		 := .directoryIndex()
		 := .directoryAt()

		 := makeProbeSeq(h1(), .groups.lengthMask)

		// As we look for a match, keep track of the first deleted slot
		// we find, which we'll use to insert the new entry if
		// necessary.
		var  groupReference
		var  uintptr

		 := h2()
		for ; ;  = .next() {
			 := .groups.group(, .offset)
			 := .ctrls().matchH2()

			// Look for an existing slot containing this key.
			for  != 0 {
				 := .first()

				 := .key(, )
				if  == *(*uint64)() {
					 = .elem(, )

					.checkInvariants(, )
					break 
				}
				 = .removeFirst()
			}

			// No existing slot for this key in this group. Is this the end
			// of the probe sequence?
			 = .ctrls().matchEmptyOrDeleted()
			if  == 0 {
				continue // nothing but filled slots. Keep probing.
			}
			 := .first()
			if .ctrls().get() == ctrlDeleted {
				// There are some deleted slots. Remember
				// the first one, and keep probing.
				if .data == nil {
					 = 
					 = 
				}
				continue
			}
			// We've found an empty slot, which means we've reached the end of
			// the probe sequence.

			// If we found a deleted slot along the way, we can
			// replace it without consuming growthLeft.
			if .data != nil {
				 = 
				 = 
				.growthLeft++ // will be decremented below to become a no-op.
			}

			// If we have no space left, first try to remove some tombstones.
			if .growthLeft == 0 {
				.pruneTombstones(, )
			}

			// If there is room left to grow, just insert the new entry.
			if .growthLeft > 0 {
				 := .key(, )
				*(*uint64)() = 

				 = .elem(, )

				.ctrls().set(, ctrl())
				.growthLeft--
				.used++
				.used++

				.checkInvariants(, )
				break 
			}

			.rehash(, )
			continue 
		}
	}

	if .writing == 0 {
		fatal("concurrent map writes")
	}
	.writing ^= 1

	return 
}

func ( *Map) ( *abi.MapType,  uintptr,  unsafe.Pointer) unsafe.Pointer {
	 := groupReference{
		data: .dirPtr,
	}

	 := .ctrls().matchH2(h2())

	// Look for an existing slot containing this key.
	for  != 0 {
		 := .first()

		 := .key(, )
		if  == *(*unsafe.Pointer)() {
			 := .elem(, )
			return 
		}
		 = .removeFirst()
	}

	// There can't be deleted slots, small maps can't have them
	// (see deleteSmall). Use matchEmptyOrDeleted as it is a bit
	// more efficient than matchEmpty.
	 = .ctrls().matchEmptyOrDeleted()
	if  == 0 {
		// No empty slot found. Need to grow the map.
		return nil
	}

	 := .first()

	 := .key(, )
	*(*unsafe.Pointer)() = 

	 := .elem(, )

	.ctrls().set(, ctrl(h2()))
	.used++

	return 
}

func ( *table) ( *abi.MapType,  uintptr,  unsafe.Pointer) unsafe.Pointer {
	if .growthLeft == 0 {
		panic("invariant failed: growthLeft is unexpectedly 0")
	}

	// Given key and its hash hash(key), to insert it, we construct a
	// probeSeq, and use it to find the first group with an unoccupied (empty
	// or deleted) slot. We place the key/value into the first such slot in
	// the group and mark it as full with key's H2.
	 := makeProbeSeq(h1(), .groups.lengthMask)
	for ; ;  = .next() {
		 := .groups.group(, .offset)

		 := .ctrls().matchEmptyOrDeleted()
		if  != 0 {
			 := .first()

			 := .key(, )
			*(*unsafe.Pointer)() = 

			 := .elem(, )

			.growthLeft--
			.used++
			.ctrls().set(, ctrl(h2()))
			return 
		}
	}
}

// Key is a 64-bit pointer (only called on 64-bit GOARCH).
//
//go:linkname runtime_mapassign_fast64ptr runtime.mapassign_fast64ptr
func ( *abi.MapType,  *Map,  unsafe.Pointer) unsafe.Pointer {
	if  == nil {
		panic(errNilAssign)
	}
	if race.Enabled {
		 := sys.GetCallerPC()
		 := abi.FuncPCABIInternal()
		race.WritePC(unsafe.Pointer(), , )
	}
	if .writing != 0 {
		fatal("concurrent map writes")
	}

	var  uintptr
	// See the related comment in runtime_mapaccess2_fast32
	if memHashAESImplemented && UseAeshash {
		 = memHash64AES(uint64((uintptr)()), .seed)
	} else {
		 = memHash64Fallback(uint64((uintptr)()), .seed)
	}

	// Set writing after calling Hasher, since Hasher may panic, in which
	// case we have not actually done a write.
	.writing ^= 1 // toggle, see comment on writing

	if .dirPtr == nil {
		.growToSmall()
	}

	if .dirLen == 0 {
		 := .putSlotSmallFastPtr(, , )
		if  == nil {
			// Can't fit another entry, grow to full size map.
			 := .growToTable()

			 = .uncheckedPutSlotForAssignFastPtr(, , )
			.used++

			.checkInvariants(, )
		}

		if .writing == 0 {
			fatal("concurrent map writes")
		}
		.writing ^= 1

		return 
	}

	var  unsafe.Pointer
:
	for {
		// Select table.
		 := .directoryIndex()
		 := .directoryAt()

		 := makeProbeSeq(h1(), .groups.lengthMask)

		// As we look for a match, keep track of the first deleted slot
		// we find, which we'll use to insert the new entry if
		// necessary.
		var  groupReference
		var  uintptr

		 := h2()
		for ; ;  = .next() {
			 := .groups.group(, .offset)
			 := .ctrls().matchH2()

			// Look for an existing slot containing this key.
			for  != 0 {
				 := .first()

				 := .key(, )
				if  == *(*unsafe.Pointer)() {
					 = .elem(, )

					.checkInvariants(, )
					break 
				}
				 = .removeFirst()
			}

			// No existing slot for this key in this group. Is this the end
			// of the probe sequence?
			 = .ctrls().matchEmptyOrDeleted()
			if  == 0 {
				continue // nothing but filled slots. Keep probing.
			}
			 := .first()
			if .ctrls().get() == ctrlDeleted {
				// There are some deleted slots. Remember
				// the first one, and keep probing.
				if .data == nil {
					 = 
					 = 
				}
				continue
			}
			// We've found an empty slot, which means we've reached the end of
			// the probe sequence.

			// If we found a deleted slot along the way, we can
			// replace it without consuming growthLeft.
			if .data != nil {
				 = 
				 = 
				.growthLeft++ // will be decremented below to become a no-op.
			}

			if .growthLeft == 0 {
				.pruneTombstones(, )
			}

			// If there is room left to grow, just insert the new entry.
			if .growthLeft > 0 {
				 := .key(, )
				*(*unsafe.Pointer)() = 

				 = .elem(, )

				.ctrls().set(, ctrl())
				.growthLeft--
				.used++
				.used++

				.checkInvariants(, )
				break 
			}

			.rehash(, )
			continue 
		}
	}

	if .writing == 0 {
		fatal("concurrent map writes")
	}
	.writing ^= 1

	return 
}

//go:linkname runtime_mapdelete_fast64 runtime.mapdelete_fast64
func ( *abi.MapType,  *Map,  uint64) {
	if race.Enabled {
		 := sys.GetCallerPC()
		 := abi.FuncPCABIInternal()
		race.WritePC(unsafe.Pointer(), , )
	}

	if  == nil || .Used() == 0 {
		return
	}

	.Delete(, abi.NoEscape(unsafe.Pointer(&)))
}