| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF 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.apache.activemq.artemis.tests.unit.util; |
| |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.NoSuchElementException; |
| |
| import io.netty.util.collection.LongObjectHashMap; |
| import org.apache.activemq.artemis.tests.util.ActiveMQTestBase; |
| import org.apache.activemq.artemis.tests.util.RandomUtil; |
| import org.apache.activemq.artemis.utils.collections.NodeStore; |
| import org.apache.activemq.artemis.utils.collections.LinkedListImpl; |
| import org.apache.activemq.artemis.utils.collections.LinkedListIterator; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| public class LinkedListTest extends ActiveMQTestBase { |
| |
| private LinkedListImpl<Integer> list; |
| |
| @Override |
| @Before |
| public void setUp() throws Exception { |
| super.setUp(); |
| list = new LinkedListImpl<>(integerComparator); |
| } |
| |
| Comparator<Integer> integerComparator = new Comparator<Integer>() { |
| @Override |
| public int compare(Integer o1, Integer o2) { |
| if (o1.intValue() == o2.intValue()) { |
| return 0; |
| } |
| if (o2.intValue() > o1.intValue()) { |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| }; |
| |
| @Test |
| public void addSorted() { |
| |
| list.addSorted(1); |
| list.addSorted(3); |
| list.addSorted(2); |
| list.addSorted(0); |
| validateOrder(null); |
| Assert.assertEquals(4, list.size()); |
| |
| } |
| |
| |
| @Test |
| public void randomSorted() { |
| |
| HashSet<Integer> values = new HashSet<>(); |
| for (int i = 0; i < 1000; i++) { |
| |
| int value = RandomUtil.randomInt(); |
| if (!values.contains(value)) { |
| values.add(value); |
| list.addSorted(value); |
| } |
| } |
| |
| Assert.assertEquals(values.size(), list.size()); |
| |
| validateOrder(values); |
| |
| Assert.assertEquals(0, values.size()); |
| |
| } |
| |
| private void validateOrder(HashSet<Integer> values) { |
| Integer previous = null; |
| LinkedListIterator<Integer> integerIterator = list.iterator(); |
| while (integerIterator.hasNext()) { |
| |
| Integer value = integerIterator.next(); |
| if (previous != null) { |
| Assert.assertTrue(value + " should be > " + previous, integerComparator.compare(previous, value) > 0); |
| Assert.assertTrue(value + " should be > " + previous, value.intValue() > previous.intValue()); |
| } |
| |
| if (values != null) { |
| values.remove(value); |
| } |
| previous = value; |
| } |
| integerIterator.close(); |
| } |
| |
| private static final class ObservableNode extends LinkedListImpl.Node<ObservableNode> { |
| |
| public String serverID; |
| public int id; |
| ObservableNode(String serverID, int id) { |
| this.id = id; |
| this.serverID = serverID; |
| } |
| |
| public LinkedListImpl.Node<ObservableNode> publicNext() { |
| return next(); |
| } |
| |
| public LinkedListImpl.Node<ObservableNode> publicPrev() { |
| return prev(); |
| } |
| |
| } |
| |
| static class ListNodeStore implements NodeStore<ObservableNode> { |
| // this is for serverID = null; |
| LongObjectHashMap<LinkedListImpl.Node<ObservableNode>> nodeLongObjectHashMap = new LongObjectHashMap<>(); |
| |
| HashMap<Object, LongObjectHashMap<LinkedListImpl.Node<ObservableNode>>> mapList = new HashMap<>(); |
| |
| @Override |
| public void storeNode(ObservableNode element, LinkedListImpl.Node<ObservableNode> node) { |
| LongObjectHashMap<LinkedListImpl.Node<ObservableNode>> map = getNodesMap(element.serverID); |
| map.put(element.id, node); |
| } |
| |
| @Override |
| public LinkedListImpl.Node<ObservableNode> getNode(String listID, long id) { |
| LongObjectHashMap<LinkedListImpl.Node<ObservableNode>> map = getNodesMap(listID); |
| if (map == null) { |
| return null; |
| } |
| return map.get(id); |
| } |
| |
| @Override |
| public void removeNode(ObservableNode element, LinkedListImpl.Node<ObservableNode> node) { |
| LongObjectHashMap<LinkedListImpl.Node<ObservableNode>> map = getNodesMap(element.serverID); |
| if (map != null) { |
| map.remove(element.id); |
| } |
| } |
| |
| private LongObjectHashMap<LinkedListImpl.Node<ObservableNode>> getNodesMap(String listID) { |
| if (listID == null) { |
| return nodeLongObjectHashMap; |
| } else { |
| LongObjectHashMap<LinkedListImpl.Node<ObservableNode>> theMap = mapList.get(listID); |
| |
| if (theMap == null) { |
| theMap = new LongObjectHashMap<>(); |
| mapList.put(listID, theMap); |
| } |
| return theMap; |
| } |
| } |
| |
| @Override |
| public void clear() { |
| nodeLongObjectHashMap.clear(); |
| mapList.clear(); |
| } |
| |
| @Override |
| public int size() { |
| int size = 0; |
| for (LongObjectHashMap list : mapList.values()) { |
| size = +list.size(); |
| } |
| return nodeLongObjectHashMap.size() + size; |
| } |
| } |
| |
| |
| @Test |
| public void testAddAndRemove() { |
| LinkedListImpl<ObservableNode> objs = new LinkedListImpl<>(); |
| |
| // Initial add |
| for (int i = 0; i < 100; i++) { |
| final ObservableNode o = new ObservableNode(null, i); |
| objs.addTail(o); |
| } |
| |
| try (LinkedListIterator<ObservableNode> iter = objs.iterator()) { |
| |
| for (int i = 0; i < 500; i++) { |
| |
| for (int add = 0; add < 1000; add++) { |
| final ObservableNode o = new ObservableNode(null, add); |
| objs.addTail(o); |
| assertNotNull("prev", o.publicPrev()); |
| assertNull("next", o.publicNext()); |
| } |
| |
| for (int remove = 0; remove < 1000; remove++) { |
| final ObservableNode next = iter.next(); |
| assertNotNull(next); |
| assertNotNull("prev", next.publicPrev()); |
| //it's ok to check this, because we've *at least* 100 elements left! |
| assertNotNull("next", next.publicNext()); |
| iter.remove(); |
| assertNull("prev", next.publicPrev()); |
| assertNull("next", next.publicNext()); |
| } |
| assertEquals(100, objs.size()); |
| } |
| |
| while (iter.hasNext()) { |
| final ObservableNode next = iter.next(); |
| assertNotNull(next); |
| iter.remove(); |
| assertNull("prev", next.publicPrev()); |
| assertNull("next", next.publicNext()); |
| } |
| } |
| assertEquals(0, objs.size()); |
| |
| } |
| |
| |
| @Test |
| public void testAddAndRemoveWithIDs() { |
| internalAddWithID(true); |
| } |
| |
| @Test |
| public void testAddAndRemoveWithIDsDeferredSupplier() { |
| internalAddWithID(false); |
| } |
| |
| private void internalAddWithID(boolean deferSupplier) { |
| |
| for (int sid = 1; sid <= 2; sid++) { |
| LinkedListImpl<ObservableNode> objs = new LinkedListImpl<>(); |
| objs.clearID(); |
| |
| String serverID = sid == 1 ? null : "" + sid; |
| |
| ListNodeStore nodeStore = new ListNodeStore(); |
| |
| if (!deferSupplier) { |
| objs.setNodeStore(nodeStore); |
| } |
| |
| // Initial add |
| for (int i = 1; i <= 1000; i++) { |
| final ObservableNode o = new ObservableNode(serverID, i); |
| objs.addTail(o); |
| } |
| |
| Assert.assertEquals(1000, objs.size()); |
| |
| if (deferSupplier) { |
| Assert.assertEquals(0, nodeStore.size()); |
| objs.setNodeStore(nodeStore); |
| } else { |
| // clear the ID supplier |
| objs.clearID(); |
| // and redo it |
| Assert.assertEquals(0, nodeStore.size()); |
| nodeStore = new ListNodeStore(); |
| objs.setNodeStore(nodeStore); |
| Assert.assertEquals(1000, objs.size()); |
| } |
| |
| Assert.assertEquals(1000, nodeStore.size()); |
| |
| /** remove all even items */ |
| for (int i = 1; i <= 1000; i += 2) { |
| objs.removeWithID(serverID, i); |
| } |
| |
| Assert.assertEquals(500, objs.size()); |
| Assert.assertEquals(500, nodeStore.size()); |
| |
| Iterator<ObservableNode> iterator = objs.iterator(); |
| |
| { |
| int i = 2; |
| while (iterator.hasNext()) { |
| ObservableNode value = iterator.next(); |
| Assert.assertEquals(i, value.id); |
| i += 2; |
| } |
| } |
| |
| for (int i = 2; i <= 1000; i += 2) { |
| Assert.assertNotNull(objs.removeWithID(serverID, i)); |
| } |
| |
| Assert.assertEquals(0, nodeStore.size()); |
| Assert.assertEquals(0, objs.size()); |
| |
| } |
| } |
| |
| @Test |
| public void testAddHeadAndRemove() { |
| LinkedListImpl<ObservableNode> objs = new LinkedListImpl<>(); |
| |
| // Initial add |
| for (int i = 0; i < 1001; i++) { |
| final ObservableNode o = new ObservableNode(null, i); |
| objs.addHead(o); |
| } |
| assertEquals(1001, objs.size()); |
| |
| int countLoop = 0; |
| |
| try (LinkedListIterator<ObservableNode> iter = objs.iterator()) { |
| int removed = 0; |
| for (countLoop = 0; countLoop <= 1000; countLoop++) { |
| final ObservableNode obj = iter.next(); |
| Assert.assertNotNull(obj); |
| if (countLoop == 500 || countLoop == 1000) { |
| assertNotNull("prev", obj.publicPrev()); |
| iter.remove(); |
| assertNull("prev", obj.publicPrev()); |
| assertNull("next", obj.publicNext()); |
| removed++; |
| } |
| } |
| assertEquals(1001 - removed, objs.size()); |
| } |
| |
| final int expectedSize = objs.size(); |
| try (LinkedListIterator<ObservableNode> iter = objs.iterator()) { |
| countLoop = 0; |
| while (iter.hasNext()) { |
| final ObservableNode obj = iter.next(); |
| assertNotNull(obj); |
| countLoop++; |
| } |
| Assert.assertEquals(expectedSize, countLoop); |
| } |
| // it's needed to add this line here because IBM JDK calls finalize on all objects in list |
| // before previous assert is called and fails the test, this will prevent it |
| objs.clear(); |
| } |
| |
| @Test |
| public void testAddTail() { |
| int num = 10; |
| |
| assertEquals(0, list.size()); |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| |
| assertEquals(i + 1, list.size()); |
| } |
| |
| for (int i = 0; i < num; i++) { |
| assertEquals(i, list.poll().intValue()); |
| |
| assertEquals(num - i - 1, list.size()); |
| } |
| } |
| |
| @Test |
| public void testAddHead() { |
| int num = 10; |
| |
| assertEquals(0, list.size()); |
| |
| for (int i = 0; i < num; i++) { |
| list.addHead(i); |
| |
| assertEquals(i + 1, list.size()); |
| } |
| |
| for (int i = num - 1; i >= 0; i--) { |
| assertEquals(i, list.poll().intValue()); |
| |
| assertEquals(i, list.size()); |
| } |
| } |
| |
| @Test |
| public void testAddHeadAndTail() { |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addHead(i); |
| } |
| |
| for (int i = num; i < num * 2; i++) { |
| list.addTail(i); |
| } |
| |
| for (int i = num * 2; i < num * 3; i++) { |
| list.addHead(i); |
| } |
| |
| for (int i = num * 3; i < num * 4; i++) { |
| list.addTail(i); |
| } |
| |
| for (int i = num * 3 - 1; i >= num * 2; i--) { |
| assertEquals(i, list.poll().intValue()); |
| } |
| |
| for (int i = num - 1; i >= 0; i--) { |
| assertEquals(i, list.poll().intValue()); |
| } |
| |
| for (int i = num; i < num * 2; i++) { |
| assertEquals(i, list.poll().intValue()); |
| } |
| |
| for (int i = num * 3; i < num * 4; i++) { |
| assertEquals(i, list.poll().intValue()); |
| } |
| |
| } |
| |
| @Test |
| public void testPoll() { |
| int num = 10; |
| |
| assertNull(list.poll()); |
| assertNull(list.poll()); |
| assertNull(list.poll()); |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| for (int i = 0; i < num; i++) { |
| assertEquals(i, list.poll().intValue()); |
| } |
| |
| assertNull(list.poll()); |
| assertNull(list.poll()); |
| assertNull(list.poll()); |
| |
| for (int i = num; i < num * 2; i++) { |
| list.addHead(i); |
| } |
| |
| for (int i = num * 2 - 1; i >= num; i--) { |
| assertEquals(i, list.poll().intValue()); |
| } |
| |
| assertNull(list.poll()); |
| assertNull(list.poll()); |
| assertNull(list.poll()); |
| |
| } |
| |
| @Test |
| public void testIterateNoElements() { |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| assertNotNull(iter); |
| |
| assertNoSuchElementIsThrown(iter); |
| |
| try { |
| iter.remove(); |
| |
| fail("Should throw NoSuchElementException"); |
| } catch (NoSuchElementException e) { |
| // OK |
| } |
| } |
| |
| @Test |
| public void testCreateIteratorBeforeAddElements() { |
| int num = 10; |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| assertNotNull(iter); |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| testIterate1(num, iter); |
| } |
| |
| @Test |
| public void testCreateIteratorAfterAddElements() { |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| assertNotNull(iter); |
| |
| testIterate1(num, iter); |
| } |
| |
| @Test |
| public void testIterateThenAddMoreAndIterateAgain() { |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| assertNotNull(iter); |
| |
| for (int i = 0; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| assertFalse(iter.hasNext()); |
| |
| assertNoSuchElementIsThrown(iter); |
| |
| // Add more |
| |
| for (int i = num; i < num * 2; i++) { |
| list.addTail(i); |
| } |
| |
| for (int i = num; i < num * 2; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| assertFalse(iter.hasNext()); |
| |
| assertNoSuchElementIsThrown(iter); |
| |
| // Add some more at head |
| |
| for (int i = num * 2; i < num * 3; i++) { |
| list.addHead(i); |
| } |
| |
| iter = list.iterator(); |
| |
| for (int i = num * 3 - 1; i >= num * 2; i--) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| for (int i = 0; i < num * 2; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| assertFalse(iter.hasNext()); |
| } |
| |
| private void testIterate1(int num, LinkedListIterator<Integer> iter) { |
| for (int i = 0; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| assertFalse(iter.hasNext()); |
| |
| assertNoSuchElementIsThrown(iter); |
| } |
| |
| /** |
| * @param iter |
| */ |
| private void assertNoSuchElementIsThrown(LinkedListIterator<Integer> iter) { |
| try { |
| iter.next(); |
| |
| fail("Should throw NoSuchElementException"); |
| } catch (NoSuchElementException e) { |
| // OK |
| } |
| } |
| |
| @Test |
| public void testRemoveAll() { |
| int num = 10; |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| try { |
| iter.remove(); |
| |
| fail("Should throw NoSuchElementException"); |
| } catch (NoSuchElementException e) { |
| // OK |
| } |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| assertEquals(num, list.size()); |
| |
| try { |
| iter.remove(); |
| |
| fail("Should throw NoSuchElementException"); |
| } catch (NoSuchElementException e) { |
| // OK |
| } |
| |
| for (int i = 0; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| iter.remove(); |
| assertEquals(num - i - 1, list.size()); |
| } |
| |
| assertFalse(iter.hasNext()); |
| } |
| |
| @Test |
| public void testRemoveOdd() { |
| int num = 10; |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| try { |
| iter.remove(); |
| |
| fail("Should throw NoSuchElementException"); |
| } catch (NoSuchElementException e) { |
| // OK |
| } |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| try { |
| iter.remove(); |
| |
| fail("Should throw NoSuchElementException"); |
| } catch (NoSuchElementException e) { |
| // OK |
| } |
| |
| int size = num; |
| for (int i = 0; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| if (i % 2 == 0) { |
| iter.remove(); |
| size--; |
| } |
| assertEquals(list.size(), size); |
| } |
| |
| iter = list.iterator(); |
| for (int i = 0; i < num; i++) { |
| if (i % 2 == 1) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| } |
| |
| assertFalse(iter.hasNext()); |
| } |
| |
| @Test |
| public void testRemoveHead1() { |
| int num = 10; |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| iter.next(); |
| iter.remove(); |
| |
| for (int i = 1; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| |
| assertFalse(iter.hasNext()); |
| } |
| |
| @Test |
| public void testRemoveHead2() { |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| iter.next(); |
| iter.remove(); |
| |
| iter = list.iterator(); |
| |
| for (int i = 1; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| |
| assertFalse(iter.hasNext()); |
| } |
| |
| @Test |
| public void testRemoveHead3() { |
| int num = 10; |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| for (int i = 0; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| iter.remove(); |
| } |
| |
| for (int i = num; i < num * 2; i++) { |
| list.addTail(i); |
| } |
| |
| for (int i = num; i < num * 2; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| iter.remove(); |
| } |
| |
| } |
| |
| @Test |
| public void testRemoveTail1() { |
| int num = 10; |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| for (int i = 0; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| |
| assertFalse(iter.hasNext()); |
| |
| // Remove the last one, that's element 9 |
| iter.remove(); |
| |
| iter = list.iterator(); |
| |
| for (int i = 0; i < num - 1; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| |
| assertFalse(iter.hasNext()); |
| } |
| |
| @Test |
| public void testRemoveMiddle() { |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| for (int i = 0; i < num / 2; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| |
| // Remove the 4th element |
| iter.remove(); |
| |
| iter = list.iterator(); |
| |
| for (int i = 0; i < num; i++) { |
| if (i != num / 2 - 1) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| } |
| |
| assertFalse(iter.hasNext()); |
| } |
| |
| @Test |
| public void testRemoveTail2() { |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| for (int i = 0; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| |
| assertFalse(iter.hasNext()); |
| |
| // Remove the last one, that's element 9 |
| iter.remove(); |
| |
| try { |
| iter.remove(); |
| fail("Should throw exception"); |
| } catch (NoSuchElementException e) { |
| } |
| |
| iter = list.iterator(); |
| |
| for (int i = 0; i < num - 1; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| |
| assertFalse(iter.hasNext()); |
| } |
| |
| @Test |
| public void testRemoveTail3() { |
| int num = 10; |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| for (int i = 0; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| |
| assertFalse(iter.hasNext()); |
| |
| // This should remove the 9th element and move the iterator back to position 8 |
| iter.remove(); |
| |
| for (int i = num; i < num * 2; i++) { |
| list.addTail(i); |
| } |
| |
| assertTrue(iter.hasNext()); |
| assertEquals(8, iter.next().intValue()); |
| |
| for (int i = num; i < num * 2; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| } |
| |
| @Test |
| public void testRemoveHeadAndTail1() { |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| iter.remove(); |
| } |
| |
| } |
| |
| @Test |
| public void testRemoveHeadAndTail2() { |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addHead(i); |
| assertEquals(1, list.size()); |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| iter.remove(); |
| } |
| |
| } |
| |
| @Test |
| public void testRemoveHeadAndTail3() { |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| if (i % 2 == 0) { |
| list.addHead(i); |
| } else { |
| list.addTail(i); |
| } |
| assertEquals(1, list.size()); |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| iter.remove(); |
| } |
| |
| } |
| |
| @Test |
| public void testRemoveInTurn() { |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| for (int i = 0; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| iter.remove(); |
| } |
| |
| assertFalse(iter.hasNext()); |
| assertEquals(0, list.size()); |
| |
| } |
| |
| @Test |
| public void testGCNepotismPoll() { |
| final int count = 100; |
| final LinkedListImpl<ObservableNode> list = new LinkedListImpl<>(); |
| for (int i = 0; i < count; i++) { |
| final ObservableNode node = new ObservableNode(null, i); |
| assertNull(node.publicPrev()); |
| assertNull(node.publicNext()); |
| list.addTail(node); |
| assertNotNull(node.publicPrev()); |
| } |
| ObservableNode node; |
| int removed = 0; |
| while ((node = list.poll()) != null) { |
| assertNull(node.publicPrev()); |
| assertNull(node.publicNext()); |
| removed++; |
| } |
| assertEquals(count, removed); |
| assertEquals(0, list.size()); |
| } |
| |
| @Test |
| public void testGCNepotismClear() { |
| final int count = 100; |
| final ObservableNode[] nodes = new ObservableNode[count]; |
| final LinkedListImpl<ObservableNode> list = new LinkedListImpl<>(); |
| for (int i = 0; i < count; i++) { |
| final ObservableNode node = new ObservableNode(null, i); |
| assertNull(node.publicPrev()); |
| assertNull(node.publicNext()); |
| nodes[i] = node; |
| list.addTail(node); |
| assertNotNull(node.publicPrev()); |
| } |
| list.clear(); |
| for (ObservableNode node : nodes) { |
| assertNull(node.publicPrev()); |
| assertNull(node.publicNext()); |
| } |
| assertEquals(0, list.size()); |
| } |
| |
| @Test |
| public void testClear() { |
| |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| assertEquals(num, list.size()); |
| |
| list.clear(); |
| |
| assertEquals(0, list.size()); |
| |
| assertNull(list.poll()); |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| assertFalse(iter.hasNext()); |
| |
| try { |
| iter.next(); |
| } catch (NoSuchElementException e) { |
| } |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| assertEquals(num, list.size()); |
| |
| iter = list.iterator(); |
| |
| for (int i = 0; i < num; i++) { |
| assertTrue(iter.hasNext()); |
| assertEquals(i, iter.next().intValue()); |
| } |
| assertFalse(iter.hasNext()); |
| |
| for (int i = 0; i < num; i++) { |
| assertEquals(i, list.poll().intValue()); |
| } |
| assertNull(list.poll()); |
| assertEquals(0, list.size()); |
| |
| } |
| |
| @Test |
| public void testMultipleIterators1() { |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| LinkedListIterator<Integer> iter1 = list.iterator(); |
| LinkedListIterator<Integer> iter2 = list.iterator(); |
| LinkedListIterator<Integer> iter3 = list.iterator(); |
| |
| for (int i = 0; i < num; ) { |
| assertTrue(iter1.hasNext()); |
| assertEquals(i++, iter1.next().intValue()); |
| iter1.remove(); |
| |
| if (i == 10) { |
| break; |
| } |
| |
| assertTrue(iter2.hasNext()); |
| assertEquals(i++, iter2.next().intValue()); |
| iter2.remove(); |
| |
| assertTrue(iter3.hasNext()); |
| assertEquals(i++, iter3.next().intValue()); |
| iter3.remove(); |
| } |
| } |
| |
| @Test |
| public void testRepeat() { |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| assertTrue(iter.hasNext()); |
| assertEquals(0, iter.next().intValue()); |
| |
| iter.repeat(); |
| assertTrue(iter.hasNext()); |
| assertEquals(0, iter.next().intValue()); |
| |
| iter.next(); |
| iter.next(); |
| iter.next(); |
| iter.hasNext(); |
| assertEquals(4, iter.next().intValue()); |
| |
| iter.repeat(); |
| assertTrue(iter.hasNext()); |
| assertEquals(4, iter.next().intValue()); |
| |
| iter.next(); |
| iter.next(); |
| iter.next(); |
| iter.next(); |
| assertEquals(9, iter.next().intValue()); |
| assertFalse(iter.hasNext()); |
| |
| iter.repeat(); |
| assertTrue(iter.hasNext()); |
| assertEquals(9, iter.next().intValue()); |
| assertFalse(iter.hasNext()); |
| } |
| |
| @Test |
| public void testRepeatAndRemove() { |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| LinkedListIterator<Integer> iter1 = list.iterator(); |
| |
| LinkedListIterator<Integer> iter2 = list.iterator(); |
| |
| assertTrue(iter1.hasNext()); |
| assertEquals(0, iter1.next().intValue()); |
| |
| assertTrue(iter2.hasNext()); |
| assertEquals(0, iter2.next().intValue()); |
| |
| iter2.remove(); |
| |
| iter1.repeat(); |
| |
| // Should move to the next one |
| assertTrue(iter1.hasNext()); |
| assertEquals(1, iter1.next().intValue()); |
| |
| iter1.next(); |
| iter1.next(); |
| iter1.next(); |
| iter1.next(); |
| iter1.next(); |
| iter1.next(); |
| iter1.next(); |
| iter1.next(); |
| assertEquals(9, iter1.next().intValue()); |
| |
| iter2.next(); |
| iter2.next(); |
| iter2.next(); |
| iter2.next(); |
| iter2.next(); |
| iter2.next(); |
| iter2.next(); |
| iter2.next(); |
| assertEquals(9, iter2.next().intValue()); |
| |
| iter1.remove(); |
| |
| iter2.repeat(); |
| |
| // Go back one since can't go forward |
| assertEquals(8, iter2.next().intValue()); |
| |
| } |
| |
| @Test |
| public void testMultipleIterators2() { |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| LinkedListIterator<Integer> iter1 = list.iterator(); |
| LinkedListIterator<Integer> iter2 = list.iterator(); |
| LinkedListIterator<Integer> iter3 = list.iterator(); |
| LinkedListIterator<Integer> iter4 = list.iterator(); |
| LinkedListIterator<Integer> iter5 = list.iterator(); |
| |
| assertTrue(iter1.hasNext()); |
| assertTrue(iter2.hasNext()); |
| assertTrue(iter3.hasNext()); |
| assertTrue(iter4.hasNext()); |
| assertTrue(iter5.hasNext()); |
| |
| assertEquals(0, iter2.next().intValue()); |
| assertTrue(iter2.hasNext()); |
| assertEquals(1, iter2.next().intValue()); |
| |
| assertEquals(0, iter1.next().intValue()); |
| iter1.remove(); |
| |
| assertTrue(iter1.hasNext()); |
| assertEquals(1, iter1.next().intValue()); |
| |
| // The others should get nudged onto the next value up |
| assertEquals(1, iter3.next().intValue()); |
| assertEquals(1, iter4.next().intValue()); |
| assertEquals(1, iter5.next().intValue()); |
| |
| assertTrue(iter4.hasNext()); |
| assertEquals(2, iter4.next().intValue()); |
| assertEquals(3, iter4.next().intValue()); |
| assertEquals(4, iter4.next().intValue()); |
| assertEquals(5, iter4.next().intValue()); |
| assertEquals(6, iter4.next().intValue()); |
| assertEquals(7, iter4.next().intValue()); |
| assertEquals(8, iter4.next().intValue()); |
| assertEquals(9, iter4.next().intValue()); |
| assertFalse(iter4.hasNext()); |
| |
| assertTrue(iter5.hasNext()); |
| assertEquals(2, iter5.next().intValue()); |
| assertEquals(3, iter5.next().intValue()); |
| assertEquals(4, iter5.next().intValue()); |
| assertEquals(5, iter5.next().intValue()); |
| assertEquals(6, iter5.next().intValue()); |
| |
| assertTrue(iter3.hasNext()); |
| assertEquals(2, iter3.next().intValue()); |
| assertEquals(3, iter3.next().intValue()); |
| assertEquals(4, iter3.next().intValue()); |
| |
| assertTrue(iter2.hasNext()); |
| assertEquals(2, iter2.next().intValue()); |
| assertEquals(3, iter2.next().intValue()); |
| assertEquals(4, iter2.next().intValue()); |
| |
| assertTrue(iter1.hasNext()); |
| assertEquals(2, iter1.next().intValue()); |
| assertEquals(3, iter1.next().intValue()); |
| assertEquals(4, iter1.next().intValue()); |
| |
| // 1, 2, 3 are on element 4 |
| |
| iter2.remove(); |
| assertEquals(5, iter2.next().intValue()); |
| iter2.remove(); |
| |
| // Should be nudged to element 6 |
| |
| assertTrue(iter1.hasNext()); |
| assertEquals(6, iter1.next().intValue()); |
| assertTrue(iter2.hasNext()); |
| assertEquals(6, iter2.next().intValue()); |
| assertTrue(iter3.hasNext()); |
| assertEquals(6, iter3.next().intValue()); |
| |
| iter5.remove(); |
| assertTrue(iter5.hasNext()); |
| assertEquals(7, iter5.next().intValue()); |
| |
| // Should be nudged to 7 |
| |
| assertTrue(iter1.hasNext()); |
| assertEquals(7, iter1.next().intValue()); |
| assertTrue(iter2.hasNext()); |
| assertEquals(7, iter2.next().intValue()); |
| assertTrue(iter3.hasNext()); |
| assertEquals(7, iter3.next().intValue()); |
| |
| // Delete last element |
| |
| assertTrue(iter5.hasNext()); |
| assertEquals(8, iter5.next().intValue()); |
| assertTrue(iter5.hasNext()); |
| assertEquals(9, iter5.next().intValue()); |
| assertFalse(iter5.hasNext()); |
| |
| iter5.remove(); |
| |
| // iter4 should be nudged back to 8, now remove element 8 |
| iter4.remove(); |
| |
| // add a new element on tail |
| |
| list.addTail(10); |
| |
| // should be nudged back to 7 |
| |
| assertTrue(iter5.hasNext()); |
| assertEquals(7, iter5.next().intValue()); |
| assertTrue(iter5.hasNext()); |
| assertEquals(10, iter5.next().intValue()); |
| |
| assertTrue(iter4.hasNext()); |
| assertEquals(7, iter4.next().intValue()); |
| assertTrue(iter4.hasNext()); |
| assertEquals(10, iter4.next().intValue()); |
| |
| assertTrue(iter3.hasNext()); |
| assertEquals(10, iter3.next().intValue()); |
| |
| assertTrue(iter2.hasNext()); |
| assertEquals(10, iter2.next().intValue()); |
| |
| assertTrue(iter1.hasNext()); |
| assertEquals(10, iter1.next().intValue()); |
| |
| } |
| |
| @Test |
| public void testResizing() { |
| int numIters = 1000; |
| |
| List<LinkedListIterator<Integer>> iters = new java.util.LinkedList<>(); |
| |
| int num = 10; |
| |
| for (int i = 0; i < num; i++) { |
| list.addTail(i); |
| } |
| |
| for (int i = 0; i < numIters; i++) { |
| LinkedListIterator<Integer> iter = list.iterator(); |
| |
| iters.add(iter); |
| |
| for (int j = 0; j < num / 2; j++) { |
| assertTrue(iter.hasNext()); |
| |
| assertEquals(j, iter.next().intValue()); |
| } |
| } |
| |
| assertEquals(numIters, list.numIters()); |
| |
| // Close the odd ones |
| |
| boolean b = false; |
| for (LinkedListIterator<Integer> iter : iters) { |
| if (b) { |
| iter.close(); |
| } |
| b = !b; |
| } |
| |
| assertEquals(numIters / 2, list.numIters()); |
| |
| // close the even ones |
| |
| b = true; |
| for (LinkedListIterator<Integer> iter : iters) { |
| if (b) { |
| iter.close(); |
| } |
| b = !b; |
| } |
| |
| assertEquals(0, list.numIters()); |
| |
| } |
| } |