// Code generated by NodeGenerator. DO NOT EDIT.

// Package node is a generated generator package.
package node

import (
	"strings"
	"unsafe"
)

const (
	InWindowQueue uint8 = iota
	InMainProbationQueue
	InMainProtectedQueue
)

const (
	aliveState uint32 = iota
	retiredState
	deadState
)

// Node is a cache entry.
type Node[K comparable, V any] interface {
	// Key returns the key.
	Key() K
	// Value returns the value.
	Value() V
	// AsPointer returns the node as a pointer.
	AsPointer() unsafe.Pointer
	// Prev returns the previous node in the eviction policy.
	Prev() Node[K, V]
	// SetPrev sets the previous node in the eviction policy.
	SetPrev(v Node[K, V])
	// Next returns the next node in the eviction policy.
	Next() Node[K, V]
	// SetNext sets the next node in the eviction policy.
	SetNext(v Node[K, V])
	// PrevExp returns the previous node in the expiration policy.
	PrevExp() Node[K, V]
	// SetPrevExp sets the previous node in the expiration policy.
	SetPrevExp(v Node[K, V])
	// NextExp returns the next node in the expiration policy.
	NextExp() Node[K, V]
	// SetNextExp sets the next node in the expiration policy.
	SetNextExp(v Node[K, V])
	// HasExpired returns true if node has expired.
	HasExpired(now int64) bool
	// ExpiresAt returns the expiration time.
	ExpiresAt() int64
	// CASExpiresAt executes the compare-and-swap operation for expiresAt.
	CASExpiresAt(old, new int64) bool
	// SetExpiresAt sets the expiration time.
	SetExpiresAt(new int64)
	// RefreshableAt returns the refresh time.
	RefreshableAt() int64
	// CASRefreshableAt executes the compare-and-swap operation for refreshableAt.
	CASRefreshableAt(old, new int64) bool
	// SetRefreshableAt returns the refresh time.
	SetRefreshableAt(new int64)
	IsFresh(now int64) bool
	// Weight returns the weight of the node.
	Weight() uint32
	// IsAlive returns true if the entry is available in the hash-table and page replacement policy.
	IsAlive() bool
	// IsRetired returns true if the entry was removed from the hash-table and is awaiting removal from the page
	// replacement policy.
	IsRetired() bool
	// Retire sets the node to the retired state.
	Retire()
	// IsDead returns true if the entry was removed from the hash-table and the page replacement policy.
	IsDead() bool
	// Die sets the node to the dead state.
	Die()
	// GetQueueType returns the queue that the entry's resides in (window, probation, or protected).
	GetQueueType() uint8
	// SetQueueType sets queue that the entry resides in (window, probation, or protected).
	SetQueueType(queueType uint8)
	// InWindow returns true if the entry is in the Window or Main space.
	InWindow() bool
	// MakeWindow sets the status to the Window queue.
	MakeWindow()
	// InMainProbation returns true if the entry is in the Main space's probation queue.
	InMainProbation() bool
	// MakeMainProbation sets the status to the Main space's probation queue.
	MakeMainProbation()
	// InMainProtected returns if the entry is in the Main space's protected queue.
	InMainProtected() bool
	// MakeMainProtected sets the status to the Main space's protected queue.
	MakeMainProtected()
}

func Equals[K comparable, V any](a, b Node[K, V]) bool {
	if a == nil {
		return b == nil || b.AsPointer() == nil
	}
	if b == nil {
		return a.AsPointer() == nil
	}
	return a.AsPointer() == b.AsPointer()
}

type Config struct {
	WithSize       bool
	WithExpiration bool
	WithWeight     bool
	WithRefresh    bool
}

type Manager[K comparable, V any] struct {
	create      func(key K, value V, expiresAt, refreshableAt int64, weight uint32) Node[K, V]
	fromPointer func(ptr unsafe.Pointer) Node[K, V]
}

func NewManager[K comparable, V any](c Config) *Manager[K, V] {
	var sb strings.Builder
	sb.WriteString("b")
	if c.WithSize {
		sb.WriteString("s")
	}
	if c.WithExpiration {
		sb.WriteString("e")
	}
	if c.WithRefresh {
		sb.WriteString("r")
	}
	if c.WithWeight {
		sb.WriteString("w")
	}
	nodeType := sb.String()
	m := &Manager[K, V]{}

	switch nodeType {
	case "b":
		m.create = NewB[K, V]
		m.fromPointer = CastPointerToB[K, V]
	case "be":
		m.create = NewBE[K, V]
		m.fromPointer = CastPointerToBE[K, V]
	case "ber":
		m.create = NewBER[K, V]
		m.fromPointer = CastPointerToBER[K, V]
	case "berw":
		m.create = NewBERW[K, V]
		m.fromPointer = CastPointerToBERW[K, V]
	case "bew":
		m.create = NewBEW[K, V]
		m.fromPointer = CastPointerToBEW[K, V]
	case "br":
		m.create = NewBR[K, V]
		m.fromPointer = CastPointerToBR[K, V]
	case "brw":
		m.create = NewBRW[K, V]
		m.fromPointer = CastPointerToBRW[K, V]
	case "bs":
		m.create = NewBS[K, V]
		m.fromPointer = CastPointerToBS[K, V]
	case "bse":
		m.create = NewBSE[K, V]
		m.fromPointer = CastPointerToBSE[K, V]
	case "bser":
		m.create = NewBSER[K, V]
		m.fromPointer = CastPointerToBSER[K, V]
	case "bsr":
		m.create = NewBSR[K, V]
		m.fromPointer = CastPointerToBSR[K, V]
	case "bw":
		m.create = NewBW[K, V]
		m.fromPointer = CastPointerToBW[K, V]
	default:
		panic("not valid nodeType")
	}
	return m
}

func (m *Manager[K, V]) Create(key K, value V, expiresAt, refreshableAt int64, weight uint32) Node[K, V] {
	return m.create(key, value, expiresAt, refreshableAt, weight)
}

func (m *Manager[K, V]) FromPointer(ptr unsafe.Pointer) Node[K, V] {
	return m.fromPointer(ptr)
}

func (m *Manager[K, V]) IsNil(n Node[K, V]) bool {
	return n == nil || n.AsPointer() == nil
}
