All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hornetq.utils.LinkedListImpl Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 33.0.2.Final
Show newest version
/*
 * Copyright 2005-2014 Red Hat, Inc.
 * Red Hat licenses this file to you under the Apache License, version
 * 2.0 (the "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *    http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.  See the License for the specific language governing
 * permissions and limitations under the License.
 */
package org.hornetq.utils;

import java.lang.reflect.Array;
import java.util.NoSuchElementException;


/**
 * A linked list implementation which allows multiple iterators to exist at the same time on the queue, and which see any
 * elements added or removed from the queue either directly or via iterators.
 *
 * This class is not thread safe.
 *
 * @author Tim Fox
 *
 *
 */
public class LinkedListImpl implements LinkedList
{
   private static final int INITIAL_ITERATOR_ARRAY_SIZE = 10;

   private final Node head = new Node(null);

   private Node tail = null;

   private int size;

   // We store in an array rather than a Map for the best performance
   private volatile Iterator[] iters;

   private int numIters;

   private int nextIndex;

   public LinkedListImpl()
   {
      iters = createIteratorArray(INITIAL_ITERATOR_ARRAY_SIZE);
   }

   public void addHead(E e)
   {
      Node node = new Node(e);

      node.next = head.next;

      node.prev = head;

      head.next = node;

      if (size == 0)
      {
         tail = node;
      }
      else
      {
         // Need to set the previous element on the former head
         node.next.prev = node;
      }

      size++;
   }

   public void addTail(E e)
   {
      if (size == 0)
      {
         addHead(e);
      }
      else
      {
         Node node = new Node(e);

         node.prev = tail;

         tail.next = node;

         tail = node;

         size++;
      }
   }

   public E poll()
   {
      Node ret = head.next;

      if (ret != null)
      {
         removeAfter(head);

         return ret.val;
      }
      else
      {
         return null;
      }
   }

   public void clear()
   {
      tail = head.next = null;

      size = 0;
   }

   public int size()
   {
      return size;
   }

   public LinkedListIterator iterator()
   {
      return new Iterator();
   }

   public String toString()
   {
      StringBuilder str = new StringBuilder("LinkedListImpl [ ");

      Node node = head;

      while (node != null)
      {
         str.append(node.toString());

         if (node.next != null)
         {
            str.append(", ");
         }

         node = node.next;
      }

      return str.toString();
   }

   public int numIters()
   {
      return numIters;
   }

   private Iterator[] createIteratorArray(int size)
   {
      return (Iterator[])Array.newInstance(Iterator.class, size);
   }

   private void removeAfter(Node node)
   {
      Node toRemove = node.next;

      node.next = toRemove.next;

      if (toRemove.next != null)
      {
         toRemove.next.prev = node;
      }

      if (toRemove == tail)
      {
         tail = node;
      }

      size--;

      if (toRemove.iterCount != 0)
      {
         LinkedListImpl.this.nudgeIterators(toRemove);
      }

      //Help GC - otherwise GC potentially has to traverse a very long list to see if elements are reachable, this can result in OOM
      //https://jira.jboss.org/browse/HORNETQ-469
      toRemove.next = toRemove.prev = null;
   }

   private synchronized void nudgeIterators(Node node)
   {
      for (int i = 0; i < numIters; i++)
      {
         Iterator iter = iters[i];
         if (iter != null)
         {
            iter.nudged(node);
         }
      }
   }

   private synchronized void addIter(Iterator iter)
   {
      if (numIters == iters.length)
      {
         resize(2 * numIters);
      }

      iters[nextIndex++] = iter;

      numIters++;
   }

   private synchronized void resize(int newSize)
   {
      Iterator[] newIters = createIteratorArray(newSize);

      System.arraycopy(iters, 0, newIters, 0, numIters);

      iters = newIters;
   }

   private synchronized void removeIter(Iterator iter)
   {
      for (int i = 0; i < numIters; i++)
      {
         if (iter == iters[i])
         {
            iters[i] = null;

            if (i != numIters - 1)
            {
               // Fill in the hole

               System.arraycopy(iters, i + 1, iters, i, numIters - i - 1);
            }

            numIters--;

            if (numIters >= INITIAL_ITERATOR_ARRAY_SIZE && numIters == iters.length / 2)
            {
               resize(numIters);
            }

            nextIndex--;

            return;
         }
      }

      throw new IllegalStateException("Cannot find iter to remove");
   }

   private static final class Node
   {
      Node next;

      Node prev;

      final E val;

      int iterCount;

      Node(E e)
      {
         val = e;
      }

      public String toString()
      {
         return "Node, value = " + val;
      }
   }

   private class Iterator implements LinkedListIterator
   {
      Node last;

      Node current = head.next;

      boolean repeat;

      Iterator()
      {
         if (current != null)
         {
            current.iterCount++;
         }

         addIter(this);
      }

      public void repeat()
      {
         repeat = true;
      }

      public boolean hasNext()
      {
         Node e = getNode();

         if (e != null && (e != last || repeat))
         {
            return true;
         }

         return canAdvance();
      }

      public E next()
      {
         Node e = getNode();

         if (repeat)
         {
            repeat = false;

            if (e != null)
            {
               return e.val;
            }
            else
            {
               if (canAdvance())
               {
                  advance();

                  e = getNode();

                  return e.val;
               }
               else
               {
                  throw new NoSuchElementException();
               }
            }
         }

         if (e == null || e == last)
         {
            if (canAdvance())
            {
               advance();

               e = getNode();
            }
            else
            {
               throw new NoSuchElementException();
            }
         }

         last = e;

         repeat = false;

         return e.val;
      }

      public void remove()
      {
         if (last == null)
         {
            throw new NoSuchElementException();
         }

         if (current == null)
         {
            throw new NoSuchElementException();
         }

         LinkedListImpl.this.removeAfter(current.prev);

         last = null;
      }

      public void close()
      {
         removeIter(this);
      }

      public void nudged(Node node)
      {
         if (current == node)
         {
            if (canAdvance())
            {
               advance();
            }
            else
            {
               if (current.prev != head)
               {
                  current.iterCount--;

                  current = current.prev;

                  current.iterCount++;
               }
               else
               {
                  current = null;
               }
            }
         }
      }

      private Node getNode()
      {
         if (current == null)
         {
            current = head.next;

            if (current != null)
            {
               current.iterCount++;
            }
         }

         if (current != null)
         {
            return current;
         }
         else
         {
            return null;
         }
      }

      private boolean canAdvance()
      {
         if (current == null)
         {
            current = head.next;

            if (current != null)
            {
               current.iterCount++;
            }
         }

         return current != null && current.next != null;
      }

      private void advance()
      {
         if (current == null || current.next == null)
         {
            throw new NoSuchElementException();
         }

         current.iterCount--;

         current = current.next;

         current.iterCount++;
      }

   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy