From 3aaefdf23a52c8d02d3fd2ceddfe77ec8a0583d9 Mon Sep 17 00:00:00 2001 From: Ivan Hetman Date: Mon, 6 Jul 2020 11:29:56 +0300 Subject: [PATCH] Hashmaps foreach (#513) --- .../teavm/classlib/java/util/THashMap.java | 69 ++++++++++++++++++- .../classlib/java/util/TLinkedHashMap.java | 63 +++++++++++++++++ 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/THashMap.java b/classlib/src/main/java/org/teavm/classlib/java/util/THashMap.java index 82dc1f7f6..1fcf6e248 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/THashMap.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/THashMap.java @@ -33,7 +33,8 @@ package org.teavm.classlib.java.util; import java.util.Arrays; -import java.util.ConcurrentModificationException; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.lang.*; import org.teavm.interop.Rename; @@ -101,7 +102,7 @@ public class THashMap extends TAbstractMap implements TCloneable, TS return false; } - final void checkConcurrentMod() throws ConcurrentModificationException { + final void checkConcurrentMod() throws TConcurrentModificationException { if (expectedModCount != associatedMap.modCount) { throw new TConcurrentModificationException(); } @@ -237,6 +238,23 @@ public class THashMap extends TAbstractMap implements TCloneable, TS public TIterator> iterator() { return new EntryIterator<>(associatedMap); } + + @Override + public void forEach(Consumer> action) { + if (associatedMap.elementCount > 0) { + int prevModCount = associatedMap.modCount; + for (int i = 0; i < associatedMap.elementData.length; i++) { + HashEntry entry = associatedMap.elementData[i]; + while (entry != null) { + action.accept(entry); + entry = entry.next; + if (prevModCount != associatedMap.modCount) { + throw new TConcurrentModificationException(); + } + } + } + } + } } @SuppressWarnings("unchecked") @@ -425,6 +443,21 @@ public class THashMap extends TAbstractMap implements TCloneable, TS @Override public TIterator iterator() { return new KeyIterator<>(THashMap.this); } + @Override public void forEach(Consumer action) { + if (elementCount > 0) { + int prevModCount = modCount; + for (int i = 0; i < elementData.length; i++) { + HashEntry entry = elementData[i]; + while (entry != null) { + action.accept(entry.key); + entry = entry.next; + if (prevModCount != modCount) { + throw new TConcurrentModificationException(); + } + } + } + } + } }; } return cachedKeySet; @@ -598,11 +631,43 @@ public class THashMap extends TAbstractMap implements TCloneable, TS @Override public TIterator iterator() { return new ValueIterator<>(THashMap.this); } + @Override public void forEach(Consumer action) { + if (elementCount > 0) { + int prevModCount = modCount; + for (int i = 0; i < elementData.length; i++) { + HashEntry entry = elementData[i]; + while (entry != null) { + action.accept(entry.value); + entry = entry.next; + if (prevModCount != modCount) { + throw new TConcurrentModificationException(); + } + } + } + } + } }; } return cachedValues; } + @Override + public void forEach(BiConsumer action) { + if (elementCount > 0) { + int prevModCount = modCount; + for (int i = 0; i < elementData.length; i++) { + HashEntry entry = elementData[i]; + while (entry != null) { + action.accept(entry.key, entry.value); + entry = entry.next; + if (prevModCount != modCount) { + throw new TConcurrentModificationException(); + } + } + } + } + } + static int computeHashCode(Object key) { return key.hashCode(); } diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashMap.java b/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashMap.java index a02839aea..65934b337 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashMap.java +++ b/classlib/src/main/java/org/teavm/classlib/java/util/TLinkedHashMap.java @@ -31,6 +31,8 @@ */ package org.teavm.classlib.java.util; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import org.teavm.classlib.java.lang.TIllegalStateException; public class TLinkedHashMap extends THashMap implements TMap { @@ -177,6 +179,22 @@ public class TLinkedHashMap extends THashMap implements TMap { public TIterator> iterator() { return new EntryIterator<>((TLinkedHashMap) hashMap()); } + + @Override + public void forEach(Consumer> action) { + TLinkedHashMap map = (TLinkedHashMap) hashMap(); + if (map.elementCount > 0) { + int prevModCount = map.modCount; + LinkedHashMapEntry entry = map.head; + do { + action.accept(entry); + entry = entry.chainForward; + if (map.modCount != prevModCount) { + throw new TConcurrentModificationException(); + } + } while (entry != null); + } + } } static final class LinkedHashMapEntry extends HashEntry { @@ -427,6 +445,21 @@ public class TLinkedHashMap extends THashMap implements TMap { public TIterator iterator() { return new KeyIterator<>(TLinkedHashMap.this); } + + @Override + public void forEach(Consumer action) { + if (elementCount > 0) { + int prevModCount = modCount; + LinkedHashMapEntry entry = head; + do { + action.accept(entry.key); + entry = entry.chainForward; + if (modCount != prevModCount) { + throw new TConcurrentModificationException(); + } + } while (entry != null); + } + } }; } return cachedKeySet; @@ -455,6 +488,21 @@ public class TLinkedHashMap extends THashMap implements TMap { public TIterator iterator() { return new ValueIterator<>(TLinkedHashMap.this); } + + @Override + public void forEach(Consumer action) { + if (elementCount > 0) { + int prevModCount = modCount; + LinkedHashMapEntry entry = head; + do { + action.accept(entry.value); + entry = entry.chainForward; + if (modCount != prevModCount) { + throw new TConcurrentModificationException(); + } + } while (entry != null); + } + } }; } return cachedValues; @@ -481,6 +529,21 @@ public class TLinkedHashMap extends THashMap implements TMap { return m.value; } + @Override + public void forEach(BiConsumer action) { + if (elementCount > 0) { + int prevModCount = modCount; + LinkedHashMapEntry entry = head; + do { + action.accept(entry.key, entry.value); + entry = entry.chainForward; + if (modCount != prevModCount) { + throw new TConcurrentModificationException(); + } + } while (entry != null); + } + } + protected boolean removeEldestEntry(@SuppressWarnings("unused") Entry eldest) { return false; }