/*
 * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
 * SPDX-License-Identifier: Apache-2.0
 */

package skl

import (
	
	

	
)

const (
	offsetSize = int(unsafe.Sizeof(uint32(0)))

	// Always align nodes on 64-bit boundaries, even on 32-bit architectures,
	// so that the node.value field is 64-bit aligned. This is necessary because
	// node.getValueOffset uses atomic.LoadUint64, which expects its input
	// pointer to be 64-bit aligned.
	nodeAlign = int(unsafe.Sizeof(uint64(0))) - 1
)

// Arena should be lock-free.
type Arena struct {
	n   atomic.Uint32
	buf []byte
}

// newArena returns a new arena.
func newArena( int64) *Arena {
	// Don't store data at position 0 in order to reserve offset=0 as a kind
	// of nil pointer.
	 := &Arena{buf: make([]byte, )}
	.n.Store(1)
	return 
}

func ( *Arena) () int64 {
	return int64(.n.Load())
}

// putNode allocates a node in the arena. The node is aligned on a pointer-sized
// boundary. The arena offset of the node is returned.
func ( *Arena) ( int) uint32 {
	// Compute the amount of the tower that will never be used, since the height
	// is less than maxHeight.
	 := (maxHeight - ) * offsetSize

	// Pad the allocation with enough bytes to ensure pointer alignment.
	 := uint32(MaxNodeSize -  + nodeAlign)
	 := .n.Add()
	y.AssertTruef(int() <= len(.buf),
		"Arena too small, toWrite:%d newTotal:%d limit:%d",
		, , len(.buf))

	// Return the aligned offset.
	 := ( -  + uint32(nodeAlign)) & ^uint32(nodeAlign)
	return 
}

// Put will *copy* val into arena. To make better use of this, reuse your input
// val buffer. Returns an offset into buf. User is responsible for remembering
// size of val. We could also store this size inside arena but the encoding and
// decoding will incur some overhead.
func ( *Arena) ( y.ValueStruct) uint32 {
	 := .EncodedSize()
	 := .n.Add()
	y.AssertTruef(int() <= len(.buf),
		"Arena too small, toWrite:%d newTotal:%d limit:%d",
		, , len(.buf))
	 :=  - 
	.Encode(.buf[:])
	return 
}

func ( *Arena) ( []byte) uint32 {
	 := uint32(len())
	 := .n.Add()
	y.AssertTruef(int() <= len(.buf),
		"Arena too small, toWrite:%d newTotal:%d limit:%d",
		, , len(.buf))
	// m is the offset where you should write.
	// n = new len - key len give you the offset at which you should write.
	 :=  - 
	// Copy to buffer from m:n
	y.AssertTrue(len() == copy(.buf[:], ))
	return 
}

// getNode returns a pointer to the node located at offset. If the offset is
// zero, then the nil node pointer is returned.
func ( *Arena) ( uint32) *node {
	if  == 0 {
		return nil
	}

	return (*node)(unsafe.Pointer(&.buf[]))
}

// getKey returns byte slice at offset.
func ( *Arena) ( uint32,  uint16) []byte {
	return .buf[ : +uint32()]
}

// getVal returns byte slice at offset. The given size should be just the value
// size and should NOT include the meta bytes.
func ( *Arena) ( uint32,  uint32) ( y.ValueStruct) {
	.Decode(.buf[ : +])
	return
}

// getNodeOffset returns the offset of node in the arena. If the node pointer is
// nil, then the zero offset is returned.
func ( *Arena) ( *node) uint32 {
	if  == nil {
		return 0
	}

	return uint32(uintptr(unsafe.Pointer()) - uintptr(unsafe.Pointer(&.buf[0])))
}