From 3b2ec91d20cb479ce079594f05487bd9eac1936b Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Thu, 24 Apr 2014 18:18:53 +0400 Subject: [PATCH] Adds PriorityQueue implementation --- .../classlib/java/util/TPriorityQueue.java | 235 ++++++++++++++++++ .../classlib/java/util/LinkedHashMapTest.java | 2 +- .../classlib/java/util/PriorityQueueTest.java | 74 ++++++ 3 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/TPriorityQueue.java create mode 100644 teavm-classlib/src/test/java/org/teavm/classlib/java/util/PriorityQueueTest.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TPriorityQueue.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TPriorityQueue.java new file mode 100644 index 000000000..93aa64476 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TPriorityQueue.java @@ -0,0 +1,235 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed 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.teavm.classlib.java.util; + +import java.util.Arrays; +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.lang.TComparable; +import org.teavm.classlib.java.lang.TIllegalArgumentException; +import org.teavm.classlib.java.lang.TIllegalStateException; +import org.teavm.classlib.java.lang.TNullPointerException; + +/** + * + * @author Alexey Andreev + */ +public class TPriorityQueue extends TAbstractQueue implements TSerializable { + private Object[] data; + private TComparator comparator; + private TComparator originalComparator; + private int size; + private int version; + + public TPriorityQueue() { + this(1); + } + + public TPriorityQueue(int initialCapacity) { + this(initialCapacity, null); + } + + public TPriorityQueue(TCollection c) { + if (c instanceof TPriorityQueue) { + initFromPriorityQueue((TPriorityQueue)c); + } else if (c instanceof TSortedSet) { + initFromSortedSet((TSortedSet)c); + } else { + data = new Object[c.size()]; + fillFromCollection(c); + setComparator(null); + } + } + + public TPriorityQueue(TPriorityQueue c) { + initFromPriorityQueue(c); + } + + public TPriorityQueue(TSortedSet c) { + initFromSortedSet(c); + } + + @SuppressWarnings("unchecked") + private void initFromSortedSet(TSortedSet sortedSet) { + data = new Object[sortedSet.size()]; + setComparator((TComparator)sortedSet.comparator()); + fillFromCollection(sortedSet); + } + + @SuppressWarnings("unchecked") + private void initFromPriorityQueue(TPriorityQueue prirityQueue) { + data = Arrays.copyOf(prirityQueue.data, prirityQueue.size); + size = prirityQueue.size; + setComparator((TComparator)prirityQueue.comparator()); + } + + private void fillFromCollection(TCollection c) { + for (TIterator iter = c.iterator(); iter.hasNext();) { + offer(iter.next()); + } + version = 0; + } + + public TPriorityQueue(int initialCapacity, TComparator comparator) { + if (initialCapacity < 1) { + throw new TIllegalArgumentException(); + } + data = new Object[initialCapacity]; + setComparator(comparator); + } + + @SuppressWarnings("unchecked") + private void setComparator(TComparator comparator) { + this.originalComparator = comparator; + if (comparator == null) { + comparator = new TComparator() { + @Override public int compare(Object o1, Object o2) { + if (o1 instanceof TComparable) { + return ((TComparable)o1).compareTo(o2); + } else { + return -((TComparable)o2).compareTo(o1); + } + } + }; + } + this.comparator = (TComparator)comparator; + } + + public TComparator comparator() { + return originalComparator; + } + + @Override + public boolean offer(E e) { + if (e == null) { + throw new TNullPointerException(); + } + ensureCapacity(size + 1); + int current = size; + while (current > 0) { + int parent = (current - 1) / 2; + if (comparator.compare(e, data[parent]) < 0) { + data[current] = data[parent]; + current = parent; + } else { + break; + } + } + data[current] = e; + ++size; + ++version; + return true; + } + + @Override + public E poll() { + if (size == 0) { + return null; + } + @SuppressWarnings("unchecked") + E elem = (E)data[0]; + removeAt(0); + return elem; + } + + @SuppressWarnings("unchecked") + @Override + public E peek() { + if (size == 0) { + return null; + } + return (E)data[0]; + } + + @Override + public int size() { + return size; + } + + @Override + public TIterator iterator() { + return new TIterator() { + private int index; + private int knownVersion = version; + private int removeIndex = -1; + @Override public boolean hasNext() { + if (version != knownVersion) { + throw new TConcurrentModificationException(); + } + return index < size; + } + @SuppressWarnings("unchecked")@Override public E next() { + if (version != knownVersion) { + throw new TConcurrentModificationException(); + } + removeIndex = index; + return (E)data[index++]; + } + @Override public void remove() { + if (version != knownVersion) { + throw new TConcurrentModificationException(); + } + if (removeIndex < 0) { + throw new TIllegalStateException(); + } + removeAt(removeIndex); + removeIndex = -1; + --index; + knownVersion = version; + } + }; + } + + @Override + public void clear() { + for (int i = 0; i < size; ++i) { + data[i] = null; + } + size = 0; + ++version; + } + + private void removeAt(int index) { + ++version; + Object item = data[size - 1]; + data[--size] = null; + while (true) { + int left = index * 2 + 1; + int right = left + 1; + int next; + if (left >= size) { + break; + } else if (right >= size || comparator.compare(data[left], data[right]) < 0) { + next = left; + } else { + next = right; + } + if (comparator.compare(item, data[next]) <= 0) { + break; + } + data[index] = data[next]; + index = next; + } + data[index] = item; + } + + private void ensureCapacity(int capacity) { + if (data.length >= capacity) { + return; + } + capacity = Math.max(capacity, data.length * 3 / 2); + data = Arrays.copyOf(data, capacity); + } +} diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/util/LinkedHashMapTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/LinkedHashMapTest.java index 1a3b32b95..8c1b34469 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/java/util/LinkedHashMapTest.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/LinkedHashMapTest.java @@ -143,7 +143,7 @@ public class LinkedHashMapTest { } @Test - public void test_entrySet() {; + public void test_entrySet() { assertEquals("Returned set of incorrect size", hm.size(), hm.entrySet().size()); for (Entry m : hm.entrySet()) { assertTrue("Returned incorrect entry set", hm.containsKey(m.getKey()) && hm.containsValue(m.getValue())); diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/util/PriorityQueueTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/PriorityQueueTest.java new file mode 100644 index 000000000..2e8f54d92 --- /dev/null +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/PriorityQueueTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2014 Alexey Andreev. + * + * Licensed 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.teavm.classlib.java.util; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.PriorityQueue; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +public class PriorityQueueTest { + @Test + public void receivesElements() { + PriorityQueue queue = fillQueue(); + assertEquals(8, queue.size()); + List list = new ArrayList<>(); + while (!queue.isEmpty()) { + list.add(queue.poll()); + } + assertNull(queue.poll()); + assertArrayEquals(new Integer[] { 0, 1, 2, 3, 4, 5, 6, 7 }, list.toArray(new Integer[0])); + } + + @Test + public void removeElements() { + for (int i = 1; i < 7; ++i) { + PriorityQueue queue = fillQueue(); + List expectedList = new ArrayList<>(); + for (int j = 0; j < queue.size(); ++j) { + expectedList.add(j); + } + Iterator iter = queue.iterator(); + int indexToRemove = -1; + for (int j = 0; j < i; ++j) { + indexToRemove = iter.next(); + } + iter.remove(); + List list = new ArrayList<>(); + while (!queue.isEmpty()) { + list.add(queue.poll()); + } + expectedList.remove(indexToRemove); + assertArrayEquals(expectedList.toArray(), list.toArray()); + } + } + + private PriorityQueue fillQueue() { + PriorityQueue queue = new PriorityQueue<>(); + for (int i : new int[] { 5, 2, 4, 3, 6, 7, 0, 1 } ) { + queue.offer(i); + } + return queue; + } +}