/* * Copyright 2013 Hannes Janetzek * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package org.oscim.utils.pool; import java.util.Iterator; import javax.annotation.CheckReturnValue; /** * Utility class for making poolable objects. * Instead of using an additional list to hold pool items just extend this * class. * * Also handy for objects that exist in only *one list* at a time, if you * are *REALLY* sure about it. Better do not use it! :) */ public class Inlist<T extends Inlist<T>> { @SuppressWarnings({ "rawtypes", "unchecked" }) public static class List<T extends Inlist<?>> implements Iterable<T>, Iterator<T> { private Inlist head; private Inlist cur; /** * Insert single item at start of list. * item.next must be null. */ public void push(T it) { if (it.next != null) throw new IllegalArgumentException("item.next must be null"); ((Inlist) it).next = head; head = it; } /** * Insert item at start of list. */ public T pop() { if (head == null) return null; Inlist it = head; head = it.next; it.next = null; return (T) it; } /** * Reverse list. */ public void reverse() { Inlist tmp; Inlist itr = head; head = null; while (itr != null) { /* keep next */ tmp = itr.next; /* push itr onto new list */ itr.next = head; head = itr; itr = tmp; } } /** * Append item, O(n) - use push() and * reverse() to iterate in insertion order! */ public void append(T it) { head = Inlist.appendItem(head, it); } /** * Append Inlist. */ public void appendList(T list) { head = Inlist.appendList(head, list); } /** * Remove item from list. */ public void remove(T it) { cur = null; head = Inlist.remove(head, it); } /** * Clear list. * * @return head of list */ public T clear() { Inlist ret = head; head = null; cur = null; return (T) ret; } /** @return first node in list */ public T head() { return (T) head; } /** Iterator: Has next item */ @Override public boolean hasNext() { return cur != null; } /** Iterator: Get next item */ @Override public T next() { if (cur == null) throw new IllegalStateException(); Inlist tmp = cur; cur = cur.next; return (T) tmp; } /** Iterator: Remove current item */ @Override public void remove() { /* iterator is at first position */ if (head.next == cur) { head = head.next; return; } Inlist prev = head; while (prev.next.next != cur) prev = prev.next; prev.next = cur; } /** NB: Only one iterator at a time possible! */ @Override public Iterator<T> iterator() { cur = head; return this; } public int size() { return Inlist.size(head); } } public T next; public T next() { return next; } /** * Push 'item' onto 'list'. * * @param list the list * @param item the item * @return the new head of 'list' (item) */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue public static <T extends Inlist<?>> T push(T list, T item) { if (item.next != null) throw new IllegalArgumentException("'item' is a list"); ((Inlist) (item)).next = list; return item; } /** * Get size of 'list'. * * @param list the list * @return the number of items in 'list' */ public static <T extends Inlist<?>> int size(T list) { int count = 0; for (Inlist<?> l = list; l != null; l = l.next) count++; return count; } /** * Removes the 'item' from 'list'. * * @param list the list * @param item the item * @return the new head of 'list' */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue public static <T extends Inlist<?>> T remove(T list, T item) { if (item == list) { Inlist head = item.next; item.next = null; return (T) head; } for (Inlist prev = list, it = list.next; it != null; it = it.next) { if (it == item) { prev.next = item.next; item.next = null; return list; } prev = it; } return list; } /** * Gets the 'item' with index 'i'. * * @param list the list * @param i the index * @return the item or null */ @SuppressWarnings({ "unchecked" }) @CheckReturnValue public static <T extends Inlist<?>> T get(T list, int i) { if (i < 0) return null; while (--i > 0 && list != null) list = (T) list.next; if (i == 0) return list; return null; } /** * Append 'item' to 'list'. 'item' may not be in another list, * i.e. item.next must be null * * @param list the list * @param item the item * @return the new head of 'list' */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue public static <T extends Inlist<?>> T appendItem(T list, T item) { if (item.next != null) throw new IllegalArgumentException("'item' is list"); if (list == null) return item; Inlist<?> it = list; while (it.next != null) it = it.next; ((Inlist) it).next = item; return list; } /** * Append list 'other' to 'list'. * * @param list the list * @param other the other * @return the head of 'list' */ @SuppressWarnings({ "rawtypes", "unchecked" }) @CheckReturnValue public static <T extends Inlist> T appendList(T list, T other) { if (list == null) return other; if (other == null) return list; for (Inlist it = list;; it = it.next) { if (it.next == null) { ((Inlist) it).next = other; break; } //else if (it.next == other) { // throw new IllegalArgumentException("'other' already in 'list'"); //} } return list; } /** * Get last item in from list. * * @param list the list * @return the last item */ @SuppressWarnings("unchecked") @CheckReturnValue public static <T extends Inlist<?>> T last(T list) { while (list != null) { if (list.next == null) return list; list = (T) list.next; } return null; } /** * Prepend 'item' relative to 'other'. * * @param list the list * @param item the item * @param other the other list * @return the new head of list */ @SuppressWarnings({ "unchecked", "rawtypes" }) @CheckReturnValue public static <T extends Inlist<?>> T prependRelative(T list, T item, T other) { if (item.next != null) throw new IllegalArgumentException("'item' is list"); if (list == null) throw new IllegalArgumentException("'list' is null"); if (list == other) { ((Inlist) item).next = list; return item; } T it = list; while (it != null && it.next != other) it = (T) it.next; if (it == null) throw new IllegalArgumentException("'other' not in 'list'"); ((Inlist) item).next = it.next; ((Inlist) it).next = item; return list; } }