/* -*- java -*- */ /** * Copyright © 2014 Mattias Andrée (m@maandree.se) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ £< EDGE=EDGE ; (( with_sentinel )) && EDGE=edge null=null ; (( array )) && null=EDGE Node=Node ; (( array )) && Node=int mirror=0 with_next=1 with_previous=${with_prev} circular=0 if (( with_sentinel )) || (( (1 - with_head) * (1 - with_tail) )); then circular=1 fi function xor { echo "this.next_previous[${1}]" } function next_previous { xor "$@" } function next { (( array )) && echo "this.next[${1}]" || echo "${1}.next" } function set-head-next { (( with_xor )) && echo "$(xor "${1}") = (${2} ^ ${null})" || echo "$(next "${1}") = ${2}" } function get-head-next { (( with_xor )) && echo "($(xor "${1}") ^ ${null})" || echo "$(next "${1}")" } function set-next { (( with_xor )) && echo "$(xor "${1}") ^= (${2} ^ ${3})" || echo "$(next "${1}") = ${2}" } function previous { (( array )) && echo "this.previous[${1}]" || echo "${1}.previous" } function get-tail-previous { (( with_xor )) && echo "($(xor "${1}") ^ ${null})" || echo "$(previous "${1}")" } function set-previous { (( with_xor )) && echo "$(xor "${1}") ^= (${2} ^ ${3})" || echo "$(previous "${1}") = ${2}" } function free { (( array )) && echo "unuse(${1})" || echo "${1}" } function singularity { (( with_xor )) && echo "${mirror}" || echo "${1}" } refs="" (( with_xor )) && refs="${refs} next_previous" (( with_xor )) || { refs="${refs} next" ; (( with_prev )) && refs="${refs} previous" ; } if (( 1 - array )); then function new £> { £{Node} £{1} = new Node(£{2}); £< } else function new £> { £{Node} £{1} = getNext(); this.values[£{1}] = £{2}; £< } £>fi public class £{name} { £>if (( 1 - array )); then /** * Node for the list */ public class Node { /** * Constructor * * @param value The value to store in the list */ public Node(T value) { this.value = value; } /** * The value stored in the list by this node */ public T value; /** * The next node in the list */ public Node next = null; £>if (( with_prev )); then /** * The previous node in the list */ public Node previous = null; £>fi } /** * Constructor */ public £{name}(Class tClass) { this.tClass = tClass; £>if (( with_sentinel )); then £>new node null this.edge = node; £>for var in $refs; do £($var this.edge) = £(singularity this.edge); £>done £>fi } £>else /** * The default initial capacity */ private static final int DEFAULT_INITIAL_CAPACITY = 128; £>if (( 1 - with_sentinel )); then /** * Sentinel value indicating that an edge has been reached */ public static final int EDGE = 0xFFFFFFFF; £>fi /** * Sentinel value indicating that the position is unused */ public static final int UNUSED = 0x80000000; /* The values of EDGE and UNUSED are choosen so that * the XOR of two indices (including EDGE) should never * reproduce UNUSED. It can only happen if EDGE is XOR:ed * with 0x7FFFFFFF — the most positive integer — which * not only is an impractically large number of elements * but also if the elements are counted it would add up * to −1. */ /** * Constructor */ @SuppressWarnings("unchecked") public £{name}(Class tClass) { this(tClass, DEFAULT_INITIAL_CAPACITY); } /** * Constructor * * @param initialCapacity The initial size of the arrays */ @SuppressWarnings("unchecked") public £{name}(Class tClass, int initialCapacity) { this.tClass = tClass; initialCapacity = algorithms.bits.Powers.toPowerOf2(initialCapacity); this.capacity = initialCapacity; £>for var in $refs reusable; do this.£{var} = new int[initialCapacity]; £>done this.values = (T[])(Array.newInstance(this.tClass, initialCapacity)); £>if (( with_sentinel )); then £>new node null this.edge = node; £>for var in $refs; do £($var this.edge) = £(singularity this.edge); £>done £>fi } /** * The size of the arrays */ private int capacity; /** * The index after the last used index in * {@link #values} and {@link #next} */ public int end = 0; /** * Head of the stack of reusable positions */ private int reuseHead = 0; /** * Stack of indices than are no longer in use */ private int[] reusable; /** * The value stored in each node */ public T[] values; £>if (( with_xor )); then /** * The XOR of the next and previous node for * each node. If it resolves to {@link #£{EDGE}} * there is no next node in that direction. If * the value stored in this array is {@link #UNUSED} * that position is not being used */ public int[] next_previous; £>else /** * The next node for each node, {@link #£{EDGE}} * if the current node is the last node, and * {@link #UNUSED} if there is no node on this * position */ public int[] next; £>if (( with_prev )); then /** * The previou node for each node, {@link #£{EDGE}} * if the current node is the first node, and * {@link #UNUSED} if there is no node on this * position */ public int[] previous; £>fi £>fi £>fi /** * Java's generics erasure is kind of silly * when it comes to arrays. We can either * create {@code Object[]} and cast it to * {@code T[]} and let the user of the class * cast it back to {@code Object[]}, get an * element and cast it back to {@code T}; or * we can let the user not only specify * {@code } when calling the constructor, * but also add an {@code T.class} argument * and then store that argument so we can * at any time use the class {@link Array} * to create an array. */ private Class tClass; £>if (( with_sentinel )); then /** * The sentinel node in the list */ public £{Node} edge; £>fi £>if (( with_head )); then /** * The first node in the list */ public £{Node} head = £{null}; £>fi £>if (( with_tail )); then /** * The last node in the list */ public £{Node} tail = £{null}; £>fi £>if (( array )); then /** * Pack the list so that there are no reusable * positions, and reduce the capacity to the * smallest capacity that can be used. Not that * values (nodes) returned by the list's methods * will become invalid. Additionally (to reduce * the complexity) the list will be defragment * so that the nodes' indices are continuous. * This method has linear time complexity and * linear memory complexity. */ public void pack() { int size = this.end - reuseHead; int cap = algorithms.bits.Powers.toPowerOf2(size); £>forward=next ; (( with_xor )) && forward=xor £>backward=previous ; (( with_xor )) && backward=xor £>x= ; (( with_xor )) && x=^ £>(( with_xor )) && int prev = EDGE; @SuppressWarnings("unchecked") T[] vals = (T[])(Array.newInstance(this.tClass, cap)); £>if (( 1 - with_head )); then int head = 0; while ((head < this.end) && (£($forward head) == UNUSED)) head++; if (head < this.end) { £>if (( with_xor )); then int tail = prev = head; while (++tail < this.end) if (£($forward tail) != UNUSED) prev = tail; £>fi for (int ptr = 0, node = head; (node != head) || (ptr == 0);) £>elif (( with_sentinel )); then for (int ptr = 0, node = this.edge; (node != this.edge) || (ptr == 0);) £>else for (int ptr = 0, node = this.head; node != £{null};) £>fi { vals[ptr++] = this.values[node]; node = £($forward node)£{x:+ ^ prev}; } £>(( 1 - with_head )) && } if (cap != this.capacity) { £>for var in $refs reusable; do this.£{var} = new int[cap]; £>done } £>LAST=EDGE FIRST=EDGE ; (( circular )) && LAST=0 FIRST="size - 1" for (int i = 0; i < size;) £($forward i) = ++i; £($forward "size - 1") = £{LAST}; £>if (( with_prev )); then for (int i = 1; i < size; i++) £($backward i) £{x}= i - 1; £($backward 0) £{x}= £{FIRST}; £>fi this.values = vals; this.end = size; this.reuseHead = 0; £>(( with_head )) && this.head = 0; £>(( with_tail )) && this.tail = this.end - 1; } /** * Gets the next free position, and grow the * arrays if necessary. This methods has constant * amortised time complexity. * * @return The next free position */ @SuppressWarnings("unchecked") private int getNext() { if (this.reuseHead > 0) return this.reusable[--this.reuseHead]; if (this.end == this.capacity) { this.capacity <<= 1; System.arraycopy(this.values, 0, this.values = (T[])(Array.newInstance(this.tClass, this.capacity)), 0, this.end); £>for var in $refs reusable; do System.arraycopy(this.£{var}, 0, this.£{var} = new int[this.capacity], 0, this.end); £>done } return this.end++; } /** * Mark a position as unused * * @param node The position * @return The position */ private int unuse(int node) { if (node >= 0) { this.reusable[reuseHead++] = node; £>for var in $refs; do this.£{var}[node] = UNUSED; £>done } return node; } £>fi £>if (( 1 - with_sentinel )) && (( 1 - with_head )) && (( 1 - with_tail )); then /** * Creates the initial node in a circularly linked list * * @param value The value of the initial node * @return The node that has been created and inserted */ public £{Node} create(T value) { £>new node value £>for var in $refs; do £($var node) = £(singularity node); £>done return node; } £>fi £>if (( with_head )) || (( with_sentinel )); then /** * Insert a value in the beginning of the list * * @param value The value to insert * @return The node that has been created and inserted */ public £{Node} insertBeginning(T value) { £>if (( with_sentinel )); then return insertAfter(value, this.edge); £>else £>new node value £(set-head-next node this.head); £>if (( with_xor )); then £(set-previous this.head "${null}" node); £>elif (( with_prev )); then if (£(next node) != £{null}) £(previous "$(next node)") = node; £>fi £>if (( with_tail )); then if (this.head == £{null}) this.tail = node; £>fi this.head = node; return node; £>fi } /** * Remove the node at the beginning of the list * * @return The node that has been removed */ public £{Node} removeBeginning() { £>if (( with_sentinel )); then return removeAfter(this.edge); £>else £{Node} node = this.head; if (node != £{null}) { this.head = £(get-head-next node); £>if (( with_prev )); then if (this.head != £{null}) £(set-previous this.head "${null}" node); £>fi £>if (( with_tail )); then if (this.tail == node) this.tail = £{null}; £>fi } return £(free node); £>fi } £>fi £>if (( 1 - with_xor )); then £>function insertDirection £>{ £>new node value £(${2} node) = £(next ${1}); £(${2} ${1}) = node; £>if (( with_${3} )); then £(${3} node) = £{1}; £>(( with_sentinel )) || if (£(${2} node) != £{null}) £(${3} "$(${2} node)") = node; £>fi £>if (( with_${4} )); then if (this.£{4} == £{1}) this.£{4} = node; £>fi return node; £>} £>function removeDirection £>{ £{Node} node = £(${2} ${1}); £>(( with_sentinel )) || if (node != £{null}) { £(${2} ${1}) = £(${2} node); £>if (( with_${3} )); then £>(( with_sentinel )) || if (£(${2} node) != £{null}) £(${3} "$(${2} node)") = £{1}; £>fi £>if (( with_${4} )); then if (this.£{4} == node) this.£{4} = £{1}; £>fi } return £(free node); £>} /** * Insert a value after a specified, reference, node * * @param value The value to insert * @param predecessor The reference node * @return The node that has been created and inserted */ public £{Node} insertAfter(T value, £{Node} predecessor) { £>insertDirection predecessor next previous tail } /** * Remove the node after a specified, reference, node * * @param predecessor The reference node * @return The node that has been removed */ public £{Node} removeAfter(£{Node} predecessor) { £>removeDirection predecessor next previous tail } £>if (( with_prev )); then /** * Insert a value before a specified, reference, node * * @param value The value to insert * @param successor The reference node * @return The node that has been created and inserted */ public £{Node} insertBefore(T value, £{Node} successor) { £>insertDirection successor previous next head } /** * Remove the node before a specified, reference, node * * @param successor The reference node * @return The node that has been removed */ public £{Node} removeBefore(£{Node} successor) { £>removeDirection successor previous next head } /** * Remove the node from the list * * @param node The node to remove */ public void remove(£{Node} node) { £>for x in "previous next head" "next previous tail"; do x=( $x ) £>(( with_sentinel )) || if (£(${x[0]} node) != £{null}) £(${x[1]} "$(${x[0]} node)") = £(${x[1]} node); £>if (( with_${x[2]} )); then else this.£{x[2]} = £(${x[1]} node); £>fi £>done £>(( array )) && unuse(node); } £>fi £>fi £>if (( with_tail )) || (( with_sentinel * with_prev )); then £>if (( 1 - with_xor )); then /** * Insert a value in the end of the list * * @param value The value to insert * @return The node that has been created and inserted */ public £{Node} insertEnd(T value) { £>if (( with_sentinel )); then return insertBefore(value, this.edge); £>else if (this.tail == £{null}) { £>if (( with_head )); then return insertBeginning(value); £>else £>new node value return this.tail = node; £>fi } return insertAfter(value, this.tail); £>fi } £>fi £>if (( with_prev )); then /** * Remove the node at the end of the list * * @return The node that has been removed */ public £{Node} removeEnd() { £>if (( with_sentinel )); then return removeBefore(this.edge); £>else £{Node} node = this.tail; if (node != £{null}) { this.tail = £(get-tail-previous node); £(set-next this.tail "${null}" node); } return £(free node); £>fi } £>fi £>fi }