@file:Suppress("unused") package dorkbox.network.other class Node(val value: T) { var prev: Node? = null var next: Node? = null } class LinkedList : List { override val size: Int get() = sizeOfList private var sizeOfList: Int = 0 private var head: Node? = null private var tail: Node? = null fun nodeAtIndex(index: Int): Node { checkPositionIndex(index) if (index >= 0) { var node = head var i = index while (node != null) { if (i == 0) return node i -= 1 node = node.next } } throw IndexOutOfBoundsException("Index was invalid or did not have any value assigned") } override fun get(index: Int): T { return nodeAtIndex(index).value } /** * Add new item to the end of the list * * @param item - item we are adding to the end of the list */ fun add(item: T): Node { val newNode = Node(item) addToTail(newNode) return newNode } /** * Add new item to the end of the list * * @param item - item we are adding to the end of the list */ fun addToTail(item: T): Node { val newNode = Node(item) addToTail(newNode) return newNode } /** * add new node to head of the list * * @param newNode - Data we are adding to the beginning of the list */ fun addToHead(newNode: Node) { val firstNode = head if (firstNode != null) { newNode.next = firstNode firstNode.prev = newNode head = newNode } else { head = newNode tail = newNode } sizeOfList++ } /** * Add new node to end of the list * * @param newNode - node we are adding to the end of the list */ fun addToTail(newNode: Node) { val lastNode = tail if (lastNode != null) { newNode.prev = lastNode lastNode.next = newNode tail = newNode } else { head = newNode tail = newNode } sizeOfList++ } /** * Searches, and removes and item from the list * * @param item - the item we are removing from the list */ fun remove(item: T) : Int { var node = head while (node != null) { if (node.value != item) { node = node.next } else { return removeNode(node) } } // nothing was removed return sizeOfList } /** * Remove a node from the list * * @param node - Node we are removing * * @return - size of list after removal */ fun removeNode(node: Node): Int { val prev = node.prev val next = node.next if (prev != null && next != null) { // We are in the middle. Link the previous to the next and vice versa prev.next = next next.prev = prev } else if (prev == null && next != null) { // We are the head. Unlink and make the next the new head next.prev = null head = next } else if (prev != null && next == null) { // We are the tail. Unlink and make the prev the new tail prev.next = null tail = prev } else if (prev == null && next == null) { // We are the only node in the list head = null tail = null } node.prev = null node.next = null sizeOfList-- return sizeOfList } /** * Clears all of the contents of this list */ fun clear() { removeAll() } /** * Remove everything from the list */ fun removeAll() { head = null tail = null } /** * Move node to front of the list * * @param node - Node we are moving */ fun moveNodeToFront(node: Node) { val prev = node.prev val next = node.next if (prev == null && next != null) { // We are the head. Do nothing return } else if (prev == null && next == null) { // We are the head. Do nothing return } if (prev != null && next != null) { // We are in the middle. Link the previous to the next and vice versa prev.next = next next.prev = prev } else if (prev != null && next == null) { // We are the tail. Unlink and make the prev the new tail prev.next = null tail = prev } node.prev = null node.next = head head = node } /** * Add node to front of list or moves to front of list if it is in the list * * @param node - Node we are adding or moving * * @return Size of list */ fun addOrMoveNodeToFront(node: Node): Int { val prev = node.prev val next = node.next if (prev == null && next == null) { if (node == head) { //We are the head. Do Nothing return sizeOfList } // We are not linked to anything, so need to be added to the head of the list. addToHead(node) return sizeOfList } if (prev == null && next != null) { // We are the head. Do nothing return sizeOfList } if (prev != null && next == null) { // We are the tail. Unlink and make the prev the new tail prev.next = null tail = prev } else if (prev != null && next != null) { // We are in the middle. Link the previous to the next and vice versa prev.next = next next.prev = prev } head!!.prev = node node.next = head node.prev = null head = node return sizeOfList } fun forEach(function: (T) -> Unit) { var node = head while (node != null) { function(node.value) node = node.next } } private fun isPositionIndex(index: Int): Boolean { return index in 0..sizeOfList } private fun outOfBoundsMsg(index: Int): String { return "Index: $index, Size: $sizeOfList" } private fun checkPositionIndex(index: Int) { if (!isPositionIndex(index)) throw IndexOutOfBoundsException(outOfBoundsMsg(index)) } fun reverseIterator(): ListIterator { return listIterator(sizeOfList) } override operator fun iterator(): ListIterator { return listIterator(0) } override fun listIterator(): ListIterator { return listIterator(0) } override fun listIterator(index: Int): ListIterator { checkPositionIndex(index) return ListItr(index) } private inner class ListItr internal constructor(private var nextIndex: Int) : ListIterator { private var lastReturned: Node? = null private var next: Node? = null init { next = if (nextIndex == sizeOfList) null else nodeAtIndex(nextIndex) } override fun hasNext(): Boolean { return nextIndex < sizeOfList } override fun next(): T { if (!hasNext()) throw NoSuchElementException() lastReturned = next next = next!!.next nextIndex++ return lastReturned!!.value } override fun hasPrevious(): Boolean { return nextIndex > 0 } override fun previous(): T { if (!hasPrevious()) { throw NoSuchElementException() } next = if (next == null) tail else next!!.prev lastReturned = next nextIndex-- return lastReturned!!.value } override fun nextIndex(): Int { return nextIndex } override fun previousIndex(): Int { return nextIndex - 1 } } override fun toString(): String { var s = "[" var node = head while (node != null) { s += "${node.value}" node = node.next if (node != null) { s += ", " } } return "$s]" } override fun contains(element: T): Boolean { var node = head while (node != null) { if (node.value != element) { node = node.next } else { return true } } // nothing was found return false } override fun containsAll(elements: Collection): Boolean { var foundAllItems: Boolean elements.forEach { foundAllItems = contains(it) if (!foundAllItems) { return false } } return true } override fun isEmpty(): Boolean { return head == null } /** * Returns the index of the first occurrence of the specified element in the list, or -1 if the specified * element is not contained in the list. */ override fun indexOf(element: T): Int { var count = 0 var node = head while (node != null) { if (node.value != element) { node = node.next count++ } else { return count } } // nothing was found return -1 } /** * Returns the index of the last occurrence of the specified element in the list, or -1 if the specified * element is not contained in the list. */ override fun lastIndexOf(element: T): Int { var count = 0 var node = head while (node != null) { if (node.value != element) { node = node.next count++ } } // nothing was found return if (count == 0) -1 else count } /** * Returns a view of the portion of this list between the specified [fromIndex] (inclusive) and [toIndex] (exclusive). * The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. * * Structural changes in the base list make the behavior of the view undefined. */ override fun subList(fromIndex: Int, toIndex: Int): List { throw NotImplementedError("This functionality is not implemented") } }