// Copyright 2009 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_list file.

package internal

import 

// Entry is an LRU Entry
type Entry[ comparable,  any] struct {
	// Next and previous pointers in the doubly-linked list of elements.
	// To simplify the implementation, internally a list l is implemented
	// as a ring, such that &l.root is both the next element of the last
	// list element (l.Back()) and the previous element of the first list
	// element (l.Front()).
	next, prev *Entry[, ]

	// The list to which this element belongs.
	list *LruList[, ]

	// The LRU Key of this element.
	Key 

	// The Value stored with this element.
	Value 

	// The time this element would be cleaned up, optional
	ExpiresAt time.Time

	// The expiry bucket item was put in, optional
	ExpireBucket uint8
}

// PrevEntry returns the previous list element or nil.
func ( *Entry[, ]) () *Entry[, ] {
	if  := .prev; .list != nil &&  != &.list.root {
		return 
	}
	return nil
}

// LruList represents a doubly linked list.
// The zero Value for LruList is an empty list ready to use.
type LruList[ comparable,  any] struct {
	root Entry[, ] // sentinel list element, only &root, root.prev, and root.next are used
	len  int         // current list Length excluding (this) sentinel element
}

// Init initializes or clears list l.
func ( *LruList[, ]) () *LruList[, ] {
	.root.next = &.root
	.root.prev = &.root
	.len = 0
	return 
}

// NewList returns an initialized list.
func [ comparable,  any]() *LruList[, ] { return new(LruList[, ]).Init() }

// Length returns the number of elements of list l.
// The complexity is O(1).
func ( *LruList[, ]) () int { return .len }

// Back returns the last element of list l or nil if the list is empty.
func ( *LruList[, ]) () *Entry[, ] {
	if .len == 0 {
		return nil
	}
	return .root.prev
}

// lazyInit lazily initializes a zero List Value.
func ( *LruList[, ]) () {
	if .root.next == nil {
		.Init()
	}
}

// insert inserts e after at, increments l.len, and returns e.
func ( *LruList[, ]) (,  *Entry[, ]) *Entry[, ] {
	.prev = 
	.next = .next
	.prev.next = 
	.next.prev = 
	.list = 
	.len++
	return 
}

// insertValue is a convenience wrapper for insert(&Entry{Value: v, ExpiresAt: ExpiresAt}, at).
func ( *LruList[, ]) ( ,  ,  time.Time,  *Entry[, ]) *Entry[, ] {
	return .insert(&Entry[, ]{Value: , Key: , ExpiresAt: }, )
}

// Remove removes e from its list, decrements l.len
func ( *LruList[, ]) ( *Entry[, ])  {
	.prev.next = .next
	.next.prev = .prev
	.next = nil // avoid memory leaks
	.prev = nil // avoid memory leaks
	.list = nil
	.len--

	return .Value
}

// move moves e to next to at.
func ( *LruList[, ]) (,  *Entry[, ]) {
	if  ==  {
		return
	}
	.prev.next = .next
	.next.prev = .prev

	.prev = 
	.next = .next
	.prev.next = 
	.next.prev = 
}

// PushFront inserts a new element e with value v at the front of list l and returns e.
func ( *LruList[, ]) ( ,  ) *Entry[, ] {
	.lazyInit()
	return .insertValue(, , time.Time{}, &.root)
}

// PushFrontExpirable inserts a new expirable element e with Value v at the front of list l and returns e.
func ( *LruList[, ]) ( ,  ,  time.Time) *Entry[, ] {
	.lazyInit()
	return .insertValue(, , , &.root)
}

// MoveToFront moves element e to the front of list l.
// If e is not an element of l, the list is not modified.
// The element must not be nil.
func ( *LruList[, ]) ( *Entry[, ]) {
	if .list !=  || .root.next ==  {
		return
	}
	// see comment in List.Remove about initialization of l
	.move(, &.root)
}