mirror of
https://github.com/corda/corda.git
synced 2025-01-06 05:04:20 +00:00
implement ConcurrentHashMap and AtomicReferenceArray
This is the simplest possible ConcurrentHashMap I could come up with that works and is actually concurrent in the way one would expect. It's pretty unconventional, being based on a persistent red-black tree, and not particularly memory-efficient or cache-friendly. I think this is a good place to start, though, and it should perform reasonably well for most workloads. Patches for a more efficient implementation are welcome! I also implemented AtomicReferenceArray, since I was using it in my first, naive attempt to implement ConcurrentHashMap. I had to do a bit of refactoring, including moving some non-standard stuff from java.util.Collections to avian.Data so I could make it available to code outside the java.util package, which is why I had to modify several unrelated files.
This commit is contained in:
parent
b6c3bc6f4d
commit
c0d178d5f1
310
classpath/avian/Data.java
Normal file
310
classpath/avian/Data.java
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
/* Copyright (c) 2008-2014, Avian Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
package avian;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.AbstractSet;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class Data {
|
||||||
|
public static int nextPowerOfTwo(int n) {
|
||||||
|
int r = 1;
|
||||||
|
while (r < n) r <<= 1;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <V> boolean equal(V a, V b) {
|
||||||
|
return a == null ? b == null : a.equals(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T[] toArray(Collection collection, T[] array) {
|
||||||
|
Class c = array.getClass().getComponentType();
|
||||||
|
|
||||||
|
if (array.length < collection.size()) {
|
||||||
|
array = (T[]) java.lang.reflect.Array.newInstance(c, collection.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (Object o: collection) {
|
||||||
|
if (c.isInstance(o)) {
|
||||||
|
array[i++] = (T) o;
|
||||||
|
} else {
|
||||||
|
throw new ArrayStoreException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toString(Collection c) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("[");
|
||||||
|
for (Iterator it = c.iterator(); it.hasNext();) {
|
||||||
|
sb.append(it.next());
|
||||||
|
if (it.hasNext()) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toString(Map m) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("{");
|
||||||
|
for (Iterator<Entry> it = m.entrySet().iterator(); it.hasNext();) {
|
||||||
|
Entry e = it.next();
|
||||||
|
sb.append(e.getKey())
|
||||||
|
.append("=")
|
||||||
|
.append(e.getValue());
|
||||||
|
if (it.hasNext()) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append("}");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface EntryMap<K,V> {
|
||||||
|
public int size();
|
||||||
|
|
||||||
|
public Entry<K,V> find(Object key);
|
||||||
|
|
||||||
|
public Entry<K,V> remove(Object key);
|
||||||
|
|
||||||
|
public void clear();
|
||||||
|
|
||||||
|
public Iterator<Entry<K,V>> iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EntrySet<K, V> extends AbstractSet<Entry<K, V>> {
|
||||||
|
private final EntryMap<K, V> map;
|
||||||
|
|
||||||
|
public EntrySet(EntryMap<K, V> map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return map.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(Object o) {
|
||||||
|
return (o instanceof Entry<?,?>)
|
||||||
|
&& map.find(((Entry<?,?>)o).getKey()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean add(Entry<K, V> e) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(Object o) {
|
||||||
|
return (o instanceof Entry<?,?>)
|
||||||
|
&& map.remove(((Entry<?,?>) o).getKey()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(Entry<K, V> e) {
|
||||||
|
return map.remove(e.getKey()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] toArray() {
|
||||||
|
return toArray(new Object[size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T[] toArray(T[] array) {
|
||||||
|
return toArray(this, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Entry<K, V>> iterator() {
|
||||||
|
return map.iterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class KeySet<K> extends AbstractSet<K> {
|
||||||
|
private final EntryMap<K, ?> map;
|
||||||
|
|
||||||
|
public KeySet(EntryMap<K, ?> map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return map.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(Object key) {
|
||||||
|
return map.find(key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean add(K key) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(Object key) {
|
||||||
|
return map.remove(key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] toArray() {
|
||||||
|
return toArray(new Object[size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T[] toArray(T[] array) {
|
||||||
|
return toArray(this, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<K> iterator() {
|
||||||
|
return new KeyIterator(map.iterator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Values<K, V> implements Collection<V> {
|
||||||
|
private final EntryMap<K, V> map;
|
||||||
|
|
||||||
|
public Values(EntryMap<K, V> map) {
|
||||||
|
this.map = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return map.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(Object value) {
|
||||||
|
for (Iterator<Entry<K, V>> it = map.iterator(); it.hasNext();) {
|
||||||
|
if (equal(it.next().getValue(), value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsAll(Collection<?> c) {
|
||||||
|
if (c == null) {
|
||||||
|
throw new NullPointerException("collection is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iterator<?> it = c.iterator(); it.hasNext();) {
|
||||||
|
if (! contains(it.next())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean add(V value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addAll(Collection<? extends V> collection) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(Object value) {
|
||||||
|
for (Iterator<Entry<K, V>> it = map.iterator();
|
||||||
|
it.hasNext();)
|
||||||
|
{
|
||||||
|
if (equal(it.next().getValue(), value)) {
|
||||||
|
it.remove();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeAll(Collection<?> c) {
|
||||||
|
boolean changed = false;
|
||||||
|
for (Iterator<Entry<K, V>> it = map.iterator(); it.hasNext();) {
|
||||||
|
if (c.contains(it.next().getValue())) {
|
||||||
|
it.remove();
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] toArray() {
|
||||||
|
return toArray(new Object[size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T[] toArray(T[] array) {
|
||||||
|
return toArray(this, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<V> iterator() {
|
||||||
|
return new ValueIterator(map.iterator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class KeyIterator<K, V> implements Iterator<K> {
|
||||||
|
private final Iterator<Entry<K, V>> it;
|
||||||
|
|
||||||
|
public KeyIterator(Iterator<Entry<K, V>> it) {
|
||||||
|
this.it = it;
|
||||||
|
}
|
||||||
|
|
||||||
|
public K next() {
|
||||||
|
return it.next().getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ValueIterator<K, V> implements Iterator<V> {
|
||||||
|
private final Iterator<Entry<K, V>> it;
|
||||||
|
|
||||||
|
public ValueIterator(Iterator<Entry<K, V>> it) {
|
||||||
|
this.it = it;
|
||||||
|
}
|
||||||
|
|
||||||
|
public V next() {
|
||||||
|
return it.next().getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -97,12 +97,12 @@ public abstract class AbstractCollection<T> implements Collection<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <S> S[] toArray(S[] array) {
|
public <S> S[] toArray(S[] array) {
|
||||||
return Collections.toArray(this, array);
|
return avian.Data.toArray(this, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Iterator<T> iterator();
|
public abstract Iterator<T> iterator();
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Collections.toString(this);
|
return avian.Data.toString(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ public class ArrayList<T> extends AbstractList<T> implements java.io.Serializabl
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Collections.toString(this);
|
return avian.Data.toString(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeObject(ObjectOutputStream out) throws IOException {
|
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||||
|
@ -10,12 +10,14 @@
|
|||||||
|
|
||||||
package java.util;
|
package java.util;
|
||||||
|
|
||||||
|
import avian.Data;
|
||||||
|
|
||||||
public class Collections {
|
public class Collections {
|
||||||
|
|
||||||
private Collections() { }
|
private Collections() { }
|
||||||
|
|
||||||
public static void shuffle(List list, Random random) {
|
public static void shuffle(List list, Random random) {
|
||||||
Object[] array = toArray(list, new Object[list.size()]);
|
Object[] array = Data.toArray(list, new Object[list.size()]);
|
||||||
for (int i = 0; i < array.length; ++i) {
|
for (int i = 0; i < array.length; ++i) {
|
||||||
int j = random.nextInt(array.length);
|
int j = random.nextInt(array.length);
|
||||||
Object tmp = array[i];
|
Object tmp = array[i];
|
||||||
@ -173,25 +175,6 @@ public class Collections {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static <T> T[] toArray(Collection collection, T[] array) {
|
|
||||||
Class c = array.getClass().getComponentType();
|
|
||||||
|
|
||||||
if (array.length < collection.size()) {
|
|
||||||
array = (T[]) java.lang.reflect.Array.newInstance(c, collection.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (Object o: collection) {
|
|
||||||
if (c.isInstance(o)) {
|
|
||||||
array[i++] = (T) o;
|
|
||||||
} else {
|
|
||||||
throw new ArrayStoreException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final List EMPTY_LIST
|
public static final List EMPTY_LIST
|
||||||
= new UnmodifiableList<Object>(new ArrayList<Object>(0));
|
= new UnmodifiableList<Object>(new ArrayList<Object>(0));
|
||||||
|
|
||||||
@ -208,35 +191,6 @@ public class Collections {
|
|||||||
return (Set<T>) new UnmodifiableSet<Object>(
|
return (Set<T>) new UnmodifiableSet<Object>(
|
||||||
new HashSet<Object>(0));
|
new HashSet<Object>(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static String toString(Collection c) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("[");
|
|
||||||
for (Iterator it = c.iterator(); it.hasNext();) {
|
|
||||||
sb.append(it.next());
|
|
||||||
if (it.hasNext()) {
|
|
||||||
sb.append(",");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.append("]");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static String toString(Map m) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("{");
|
|
||||||
for (Iterator<Map.Entry> it = m.entrySet().iterator(); it.hasNext();) {
|
|
||||||
Map.Entry e = it.next();
|
|
||||||
sb.append(e.getKey())
|
|
||||||
.append("=")
|
|
||||||
.append(e.getValue());
|
|
||||||
if (it.hasNext()) {
|
|
||||||
sb.append(",");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.append("}");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Enumeration<T> enumeration(Collection<T> c) {
|
public static <T> Enumeration<T> enumeration(Collection<T> c) {
|
||||||
return new IteratorEnumeration<T> (c.iterator());
|
return new IteratorEnumeration<T> (c.iterator());
|
||||||
@ -746,46 +700,6 @@ public class Collections {
|
|||||||
public static <T> Set<T> unmodifiableSet(Set<T> hs) {
|
public static <T> Set<T> unmodifiableSet(Set<T> hs) {
|
||||||
return new UnmodifiableSet<T>(hs);
|
return new UnmodifiableSet<T>(hs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class KeyIterator<K, V> implements Iterator<K> {
|
|
||||||
private final Iterator<Map.Entry<K, V>> it;
|
|
||||||
|
|
||||||
public KeyIterator(Iterator<Map.Entry<K, V>> it) {
|
|
||||||
this.it = it;
|
|
||||||
}
|
|
||||||
|
|
||||||
public K next() {
|
|
||||||
return it.next().getKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
return it.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ValueIterator<K, V> implements Iterator<V> {
|
|
||||||
private final Iterator<Map.Entry<K, V>> it;
|
|
||||||
|
|
||||||
public ValueIterator(Iterator<Map.Entry<K, V>> it) {
|
|
||||||
this.it = it;
|
|
||||||
}
|
|
||||||
|
|
||||||
public V next() {
|
|
||||||
return it.next().getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
return it.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
it.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ReverseComparator<T> implements Comparator<T> {
|
private static final class ReverseComparator<T> implements Comparator<T> {
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
package java.util;
|
package java.util;
|
||||||
|
|
||||||
|
import avian.Data;
|
||||||
|
|
||||||
public class HashMap<K, V> implements Map<K, V> {
|
public class HashMap<K, V> implements Map<K, V> {
|
||||||
private static final int MinimumCapacity = 16;
|
private static final int MinimumCapacity = 16;
|
||||||
|
|
||||||
@ -19,7 +21,7 @@ public class HashMap<K, V> implements Map<K, V> {
|
|||||||
|
|
||||||
public HashMap(int capacity, Helper<K, V> helper) {
|
public HashMap(int capacity, Helper<K, V> helper) {
|
||||||
if (capacity > 0) {
|
if (capacity > 0) {
|
||||||
array = new Cell[nextPowerOfTwo(capacity)];
|
array = new Cell[Data.nextPowerOfTwo(capacity)];
|
||||||
}
|
}
|
||||||
this.helper = helper;
|
this.helper = helper;
|
||||||
}
|
}
|
||||||
@ -40,13 +42,7 @@ public class HashMap<K, V> implements Map<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Collections.toString(this);
|
return avian.Data.toString(this);
|
||||||
}
|
|
||||||
|
|
||||||
private static int nextPowerOfTwo(int n) {
|
|
||||||
int r = 1;
|
|
||||||
while (r < n) r <<= 1;
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
@ -72,7 +68,7 @@ public class HashMap<K, V> implements Map<K, V> {
|
|||||||
private void resize(int capacity) {
|
private void resize(int capacity) {
|
||||||
Cell<K, V>[] newArray = null;
|
Cell<K, V>[] newArray = null;
|
||||||
if (capacity != 0) {
|
if (capacity != 0) {
|
||||||
capacity = nextPowerOfTwo(capacity);
|
capacity = Data.nextPowerOfTwo(capacity);
|
||||||
if (array != null && array.length == capacity) {
|
if (array != null && array.length == capacity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -220,21 +216,43 @@ public class HashMap<K, V> implements Map<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Set<Entry<K, V>> entrySet() {
|
public Set<Entry<K, V>> entrySet() {
|
||||||
return new EntrySet();
|
return new Data.EntrySet(new MyEntryMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<K> keySet() {
|
public Set<K> keySet() {
|
||||||
return new KeySet();
|
return new Data.KeySet(new MyEntryMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<V> values() {
|
public Collection<V> values() {
|
||||||
return new Values();
|
return new Data.Values(new MyEntryMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
Iterator<Entry<K, V>> iterator() {
|
Iterator<Entry<K, V>> iterator() {
|
||||||
return new MyIterator();
|
return new MyIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class MyEntryMap implements Data.EntryMap<K, V> {
|
||||||
|
public int size() {
|
||||||
|
return HashMap.this.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entry<K,V> find(Object key) {
|
||||||
|
return HashMap.this.find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Entry<K,V> remove(Object key) {
|
||||||
|
return removeCell(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
HashMap.this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Entry<K,V>> iterator() {
|
||||||
|
return HashMap.this.iterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface Cell<K, V> extends Entry<K, V> {
|
interface Cell<K, V> extends Entry<K, V> {
|
||||||
public HashMap.Cell<K, V> next();
|
public HashMap.Cell<K, V> next();
|
||||||
|
|
||||||
@ -303,148 +321,6 @@ public class HashMap<K, V> implements Map<K, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class EntrySet extends AbstractSet<Entry<K, V>> {
|
|
||||||
public int size() {
|
|
||||||
return HashMap.this.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return HashMap.this.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Object o) {
|
|
||||||
return (o instanceof Entry<?,?>)
|
|
||||||
&& containsKey(((Entry<?,?>)o).getKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(Entry<K, V> e) {
|
|
||||||
return putCell(e.getKey(), e.getValue()) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(Object o) {
|
|
||||||
return (o instanceof Entry<?,?>) && remove((Entry<?,?>)o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(Entry<K, V> e) {
|
|
||||||
return removeCell(e.getKey()) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] toArray() {
|
|
||||||
return toArray(new Object[size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T[] toArray(T[] array) {
|
|
||||||
return Collections.toArray(this, array);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
HashMap.this.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterator<Entry<K, V>> iterator() {
|
|
||||||
return new MyIterator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class KeySet extends AbstractSet<K> {
|
|
||||||
public int size() {
|
|
||||||
return HashMap.this.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return HashMap.this.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Object key) {
|
|
||||||
return containsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(K key) {
|
|
||||||
return putCell(key, null) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(Object key) {
|
|
||||||
return removeCell(key) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] toArray() {
|
|
||||||
return toArray(new Object[size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T[] toArray(T[] array) {
|
|
||||||
return Collections.toArray(this, array);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
HashMap.this.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterator<K> iterator() {
|
|
||||||
return new Collections.KeyIterator(new MyIterator());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Values implements Collection<V> {
|
|
||||||
public int size() {
|
|
||||||
return HashMap.this.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return HashMap.this.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(Object value) {
|
|
||||||
return containsValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean containsAll(Collection<?> c) {
|
|
||||||
if (c == null) {
|
|
||||||
throw new NullPointerException("collection is null");
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<?> it = c.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
if (! contains(it.next())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(V value) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addAll(Collection<? extends V> collection) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(Object value) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean removeAll(Collection<?> c) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] toArray() {
|
|
||||||
return toArray(new Object[size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T[] toArray(T[] array) {
|
|
||||||
return Collections.toArray(this, array);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
HashMap.this.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterator<V> iterator() {
|
|
||||||
return new Collections.ValueIterator(new MyIterator());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MyIterator implements Iterator<Entry<K, V>> {
|
private class MyIterator implements Iterator<Entry<K, V>> {
|
||||||
private int currentIndex = -1;
|
private int currentIndex = -1;
|
||||||
private int nextIndex = -1;
|
private int nextIndex = -1;
|
||||||
|
@ -63,7 +63,7 @@ public class HashSet<T> extends AbstractSet<T> implements Set<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Collections.toString(this);
|
return avian.Data.toString(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MyIterator<T> implements Iterator<T> {
|
private static class MyIterator<T> implements Iterator<T> {
|
||||||
|
@ -131,7 +131,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T> T[] toArray(T[] array) {
|
public <T> T[] toArray(T[] array) {
|
||||||
return Collections.toArray(this, array);
|
return avian.Data.toArray(this, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
@ -169,7 +169,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T> T[] toArray(T[] array) {
|
public <T> T[] toArray(T[] array) {
|
||||||
return Collections.toArray(this, array);
|
return avian.Data.toArray(this, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
@ -177,7 +177,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<K> iterator() {
|
public Iterator<K> iterator() {
|
||||||
return new Collections.KeyIterator(new MyIterator());
|
return new avian.Data.KeyIterator(new MyIterator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T> T[] toArray(T[] array) {
|
public <T> T[] toArray(T[] array) {
|
||||||
return Collections.toArray(this, array);
|
return avian.Data.toArray(this, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
@ -238,7 +238,7 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<V> iterator() {
|
public Iterator<V> iterator() {
|
||||||
return new Collections.ValueIterator(new MyIterator());
|
return new avian.Data.ValueIterator(new MyIterator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ public class LinkedHashSet<T> extends AbstractSet<T> implements Set<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Collections.toString(this);
|
return avian.Data.toString(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MyIterator<T> implements Iterator<T> {
|
private static class MyIterator<T> implements Iterator<T> {
|
||||||
|
@ -360,7 +360,7 @@ public class LinkedList<T> extends AbstractSequentialList<T> implements Deque<T>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Collections.toString(this);
|
return avian.Data.toString(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -42,7 +42,7 @@ public class TreeMap<K,V> implements Map<K,V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Collections.toString(this);
|
return avian.Data.toString(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public V get(Object key) {
|
public V get(Object key) {
|
||||||
@ -164,7 +164,7 @@ public class TreeMap<K,V> implements Map<K,V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T> T[] toArray(T[] array) {
|
public <T> T[] toArray(T[] array) {
|
||||||
return Collections.toArray(this, array);
|
return avian.Data.toArray(this, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
@ -172,7 +172,7 @@ public class TreeMap<K,V> implements Map<K,V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<K> iterator() {
|
public Iterator<K> iterator() {
|
||||||
return new Collections.KeyIterator(set.iterator());
|
return new avian.Data.KeyIterator(set.iterator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ public class TreeMap<K,V> implements Map<K,V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T> T[] toArray(T[] array) {
|
public <T> T[] toArray(T[] array) {
|
||||||
return Collections.toArray(this, array);
|
return avian.Data.toArray(this, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
@ -233,7 +233,7 @@ public class TreeMap<K,V> implements Map<K,V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<V> iterator() {
|
public Iterator<V> iterator() {
|
||||||
return new Collections.ValueIterator(set.iterator());
|
return new avian.Data.ValueIterator(set.iterator());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ public class TreeSet<T> extends AbstractSet<T> implements Collection<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Collections.toString(this);
|
return avian.Data.toString(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean add(T value) {
|
public boolean add(T value) {
|
||||||
|
430
classpath/java/util/concurrent/ConcurrentHashMap.java
Normal file
430
classpath/java/util/concurrent/ConcurrentHashMap.java
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
/* Copyright (c) 2008-2014, Avian Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
package java.util.concurrent;
|
||||||
|
|
||||||
|
import avian.Data;
|
||||||
|
import avian.PersistentSet;
|
||||||
|
import avian.PersistentSet.Path;
|
||||||
|
|
||||||
|
import sun.misc.Unsafe;
|
||||||
|
import java.util.AbstractMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
public class ConcurrentHashMap<K,V>
|
||||||
|
extends AbstractMap<K,V>
|
||||||
|
implements ConcurrentMap<K,V>
|
||||||
|
{
|
||||||
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||||
|
private static final long Content;
|
||||||
|
private static final Content Empty = new Content(new PersistentSet(), 0);
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
Content = unsafe.objectFieldOffset
|
||||||
|
(ConcurrentHashMap.class.getDeclaredField("content"));
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private volatile Content<K,V> content;
|
||||||
|
|
||||||
|
public ConcurrentHashMap() {
|
||||||
|
content = Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConcurrentHashMap(int initialCapacity) {
|
||||||
|
this();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return content.size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return content.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsKey(Object key) {
|
||||||
|
return find(key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsValue(Object value) {
|
||||||
|
for (V v: values()) {
|
||||||
|
if (value.equals(v)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public V get(Object key) {
|
||||||
|
Cell<K,V> cell = find(key);
|
||||||
|
return cell == null ? null : cell.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cell<K,V> find(Object key) {
|
||||||
|
Content<K,V> c = content;
|
||||||
|
|
||||||
|
Path<Node<Cell<K,V>>> path = c.set.find(new Node(key.hashCode()));
|
||||||
|
for (Cell<K,V> cell = path.value().value;
|
||||||
|
cell != null;
|
||||||
|
cell = cell.next)
|
||||||
|
{
|
||||||
|
if (key.equals(cell.key)) {
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public V putIfAbsent(K key, V value) {
|
||||||
|
Cell<K,V> cell = put(key, value, PutCondition.IfAbsent, null);
|
||||||
|
return cell == null ? null : cell.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(K key, V value) {
|
||||||
|
Cell<K,V> cell = remove(key, RemoveCondition.IfEqual, value);
|
||||||
|
return cell != null && cell.value.equals(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public V replace(K key, V value) {
|
||||||
|
Cell<K,V> cell = put(key, value, PutCondition.IfPresent, null);
|
||||||
|
return cell == null ? null : cell.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean replace(K key, V oldValue, V newValue) {
|
||||||
|
Cell<K,V> cell = put(key, newValue, PutCondition.IfEqual, oldValue);
|
||||||
|
return cell != null && cell.value.equals(oldValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public V put(K key, V value) {
|
||||||
|
Cell<K,V> cell = put(key, value, PutCondition.Always, null);
|
||||||
|
return cell == null ? null : cell.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public V remove(Object key) {
|
||||||
|
Cell<K,V> cell = remove(key, RemoveCondition.Always, null);
|
||||||
|
return cell == null ? null : cell.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum PutCondition {
|
||||||
|
Always() {
|
||||||
|
public boolean addIfAbsent() { return true; }
|
||||||
|
public <V> boolean addIfPresent(V a, V b) { return true; }
|
||||||
|
}, IfAbsent() {
|
||||||
|
public boolean addIfAbsent() { return true; }
|
||||||
|
public <V> boolean addIfPresent(V a, V b) { return false; }
|
||||||
|
}, IfPresent() {
|
||||||
|
public boolean addIfAbsent() { return false; }
|
||||||
|
public <V> boolean addIfPresent(V a, V b) { return true; }
|
||||||
|
}, IfEqual() {
|
||||||
|
public boolean addIfAbsent() { return false; }
|
||||||
|
public <V> boolean addIfPresent(V a, V b) { return a.equals(b); }
|
||||||
|
};
|
||||||
|
|
||||||
|
public boolean addIfAbsent() { throw new AssertionError(); }
|
||||||
|
public <V> boolean addIfPresent(V a, V b) { throw new AssertionError(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum RemoveCondition {
|
||||||
|
Always() {
|
||||||
|
public <V> boolean remove(V a, V b) { return true; }
|
||||||
|
}, IfEqual() {
|
||||||
|
public <V> boolean remove(V a, V b) { return a.equals(b); }
|
||||||
|
};
|
||||||
|
|
||||||
|
public <V> boolean remove(V a, V b) { throw new AssertionError(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cell<K,V> put(K key, V value, PutCondition condition, V oldValue) {
|
||||||
|
Node<Cell<K,V>> node = new Node(key.hashCode());
|
||||||
|
|
||||||
|
loop: while (true) {
|
||||||
|
node.value = null;
|
||||||
|
Content content = this.content;
|
||||||
|
Path<Node<Cell<K,V>>> path = content.set.find(node);
|
||||||
|
for (Cell<K,V> cell = path.value().value;
|
||||||
|
cell != null;
|
||||||
|
cell = cell.next)
|
||||||
|
{
|
||||||
|
if (key.equals(cell.key)) {
|
||||||
|
if (! condition.addIfPresent(cell.value, oldValue)) {
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell<K,V> start = null;
|
||||||
|
Cell<K,V> last = null;
|
||||||
|
for (Cell<K,V> cell2 = path.value().value;
|
||||||
|
true;
|
||||||
|
cell2 = cell2.next)
|
||||||
|
{
|
||||||
|
Cell<K,V> c;
|
||||||
|
c = cell2.clone();
|
||||||
|
|
||||||
|
if (last == null) {
|
||||||
|
last = start = c;
|
||||||
|
} else {
|
||||||
|
last.next = c;
|
||||||
|
last = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell2 == cell) {
|
||||||
|
c.value = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node.value = start;
|
||||||
|
if (unsafe.compareAndSwapObject
|
||||||
|
(this, Content, content, new Content
|
||||||
|
(path.replaceWith(node), content.size)))
|
||||||
|
{
|
||||||
|
return cell;
|
||||||
|
} else {
|
||||||
|
continue loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no mapping found -- add a new one if appropriate
|
||||||
|
if (! condition.addIfAbsent()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.value = new Cell(key, value, null);
|
||||||
|
if (unsafe.compareAndSwapObject
|
||||||
|
(this, Content, content, new Content
|
||||||
|
(path.fresh() ? path.add() : path.replaceWith(node),
|
||||||
|
content.size + 1)))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putAll(Map<? extends K, ? extends V> map) {
|
||||||
|
for (Map.Entry<? extends K, ? extends V> e: map.entrySet()) {
|
||||||
|
put(e.getKey(), e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cell<K,V> remove(Object key, RemoveCondition condition,
|
||||||
|
V oldValue)
|
||||||
|
{
|
||||||
|
Node<Cell<K,V>> node = new Node(key.hashCode());
|
||||||
|
|
||||||
|
loop: while (true) {
|
||||||
|
node.value = null;
|
||||||
|
Content content = this.content;
|
||||||
|
Path<Node<Cell<K,V>>> path = content.set.find(node);
|
||||||
|
for (Cell<K,V> cell = path.value().value;
|
||||||
|
cell != null;
|
||||||
|
cell = cell.next)
|
||||||
|
{
|
||||||
|
if (key.equals(cell.key)) {
|
||||||
|
if (! condition.remove(cell.value, oldValue)) {
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cell<K,V> start = null;
|
||||||
|
Cell<K,V> last = null;
|
||||||
|
for (Cell<K,V> cell2 = path.value().value;
|
||||||
|
cell2 != cell;
|
||||||
|
cell2 = cell2.next)
|
||||||
|
{
|
||||||
|
Cell<K,V> c = cell2.clone();
|
||||||
|
if (last == null) {
|
||||||
|
last = start = c;
|
||||||
|
} else {
|
||||||
|
last.next = c;
|
||||||
|
last = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last == null) {
|
||||||
|
start = last = cell.next;
|
||||||
|
} else {
|
||||||
|
last.next = cell.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.value = start;
|
||||||
|
if (unsafe.compareAndSwapObject
|
||||||
|
(this, Content, content, new Content
|
||||||
|
(start == null ? path.remove() : path.replaceWith(node),
|
||||||
|
content.size - 1)))
|
||||||
|
{
|
||||||
|
return cell;
|
||||||
|
} else {
|
||||||
|
continue loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
content = Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Map.Entry<K, V>> entrySet() {
|
||||||
|
return new Data.EntrySet(new MyEntryMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<K> keySet() {
|
||||||
|
return new Data.KeySet(new MyEntryMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<V> values() {
|
||||||
|
return new Data.Values(new MyEntryMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyEntryMap implements Data.EntryMap<K, V> {
|
||||||
|
public int size() {
|
||||||
|
return ConcurrentHashMap.this.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map.Entry<K,V> find(Object key) {
|
||||||
|
return new MyEntry(ConcurrentHashMap.this.find(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map.Entry<K,V> remove(Object key) {
|
||||||
|
return new MyEntry
|
||||||
|
(ConcurrentHashMap.this.remove(key, RemoveCondition.Always, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
ConcurrentHashMap.this.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Map.Entry<K,V>> iterator() {
|
||||||
|
return new MyIterator(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Content<K,V> {
|
||||||
|
private final PersistentSet<Node<Cell<K,V>>> set;
|
||||||
|
private final int size;
|
||||||
|
|
||||||
|
public Content(PersistentSet<Node<Cell<K,V>>> set,
|
||||||
|
int size)
|
||||||
|
{
|
||||||
|
this.set = set;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Cell<K,V> implements Cloneable {
|
||||||
|
public final K key;
|
||||||
|
public V value;
|
||||||
|
public Cell<K,V> next;
|
||||||
|
|
||||||
|
public Cell(K key, V value, Cell<K,V> next) {
|
||||||
|
this.key = key;
|
||||||
|
this.value = value;
|
||||||
|
this.next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cell<K,V> clone() {
|
||||||
|
try {
|
||||||
|
return (Cell<K,V>) super.clone();
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Node<T> implements Comparable<Node<T>> {
|
||||||
|
public final int key;
|
||||||
|
public T value;
|
||||||
|
|
||||||
|
public Node(int key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo(Node<T> n) {
|
||||||
|
return key - n.key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyEntry implements Map.Entry<K,V> {
|
||||||
|
private final K key;
|
||||||
|
private V value;
|
||||||
|
|
||||||
|
public MyEntry(Cell<K,V> cell) {
|
||||||
|
key = cell.key;
|
||||||
|
value = cell.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public K getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public V getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public V setValue(V value) {
|
||||||
|
V v = value;
|
||||||
|
this.value = value;
|
||||||
|
put(key, value);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MyIterator implements Iterator<Map.Entry<K, V>> {
|
||||||
|
private final Content<K,V> content;
|
||||||
|
private final Iterator<Node<Cell<K, V>>> iterator;
|
||||||
|
private Cell<K, V> currentCell;
|
||||||
|
private Cell<K, V> nextCell;
|
||||||
|
|
||||||
|
public MyIterator(Content<K,V> content) {
|
||||||
|
this.content = content;
|
||||||
|
this.iterator = content.set.iterator();
|
||||||
|
hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map.Entry<K, V> next() {
|
||||||
|
if (hasNext()) {
|
||||||
|
currentCell = nextCell;
|
||||||
|
|
||||||
|
nextCell = nextCell.next;
|
||||||
|
|
||||||
|
return new MyEntry(currentCell);
|
||||||
|
} else {
|
||||||
|
throw new NoSuchElementException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
if (nextCell == null && iterator.hasNext()) {
|
||||||
|
nextCell = iterator.next().value;
|
||||||
|
}
|
||||||
|
return nextCell != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
if (currentCell != null) {
|
||||||
|
ConcurrentHashMap.this.remove
|
||||||
|
(currentCell.key, RemoveCondition.Always, null);
|
||||||
|
currentCell = null;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
classpath/java/util/concurrent/ConcurrentMap.java
Normal file
23
classpath/java/util/concurrent/ConcurrentMap.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/* Copyright (c) 2008-2014, Avian Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
package java.util.concurrent;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public interface ConcurrentMap<K,V> extends Map<K,V> {
|
||||||
|
public V putIfAbsent(K key, V value);
|
||||||
|
|
||||||
|
public boolean remove(K key, V value);
|
||||||
|
|
||||||
|
public V replace(K key, V value);
|
||||||
|
|
||||||
|
public boolean replace(K key, V oldValue, V newValue);
|
||||||
|
}
|
@ -32,9 +32,9 @@ public class AtomicReference<T> implements java.io.Serializable {
|
|||||||
public T get() {
|
public T get() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(T newValue) {
|
public void set(T newValue) {
|
||||||
this.value = newValue;
|
value = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void lazySet(T newValue) {
|
public void lazySet(T newValue) {
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
/* Copyright (c) 2008-2014, Avian Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software
|
||||||
|
for any purpose with or without fee is hereby granted, provided
|
||||||
|
that the above copyright notice and this permission notice appear
|
||||||
|
in all copies.
|
||||||
|
|
||||||
|
There is NO WARRANTY for this software. See license.txt for
|
||||||
|
details. */
|
||||||
|
|
||||||
|
package java.util.concurrent.atomic;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import sun.misc.Unsafe;
|
||||||
|
|
||||||
|
public class AtomicReferenceArray<T> {
|
||||||
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||||
|
private static final long arrayOffset = unsafe.arrayBaseOffset(Object.class);
|
||||||
|
private static final long arrayScale = unsafe.arrayIndexScale(Object.class);
|
||||||
|
|
||||||
|
private final Object[] array;
|
||||||
|
|
||||||
|
public AtomicReferenceArray(int length) {
|
||||||
|
array = new Object[length];
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get(int index) {
|
||||||
|
return (T) unsafe.getObjectVolatile
|
||||||
|
(array, arrayOffset + (index * arrayScale));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(int index, T newValue) {
|
||||||
|
unsafe.putObjectVolatile
|
||||||
|
(array, arrayOffset + (index * arrayScale), newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void lazySet(int index, T newValue) {
|
||||||
|
unsafe.putOrderedObject
|
||||||
|
(array, arrayOffset + (index * arrayScale), newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean compareAndSet(int index, T expect, T update) {
|
||||||
|
return unsafe.compareAndSwapObject
|
||||||
|
(array, arrayOffset + (index * arrayScale), expect, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean weakCompareAndSet(int index, T expect, T update) {
|
||||||
|
return compareAndSet(index, expect, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final T getAndSet(int index, T newValue) {
|
||||||
|
while (true) {
|
||||||
|
T current = get(index);
|
||||||
|
if (compareAndSet(index, current, newValue)) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int length() {
|
||||||
|
return array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Arrays.toString(array);
|
||||||
|
}
|
||||||
|
}
|
@ -74,6 +74,8 @@ public final class Unsafe {
|
|||||||
|
|
||||||
public native int arrayBaseOffset(Class arrayClass);
|
public native int arrayBaseOffset(Class arrayClass);
|
||||||
|
|
||||||
|
public native int arrayIndexScale(Class arrayClass);
|
||||||
|
|
||||||
public native long objectFieldOffset(Field field);
|
public native long objectFieldOffset(Field field);
|
||||||
|
|
||||||
public native void park(boolean absolute, long time);
|
public native void park(boolean absolute, long time);
|
||||||
|
@ -663,6 +663,28 @@ Avian_sun_misc_Unsafe_arrayBaseOffset
|
|||||||
return ArrayBody;
|
return ArrayBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
||||||
|
Avian_sun_misc_Unsafe_arrayIndexScale
|
||||||
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
|
{
|
||||||
|
object c = jclassVmClass(t, reinterpret_cast<object>(arguments[1]));
|
||||||
|
|
||||||
|
if (c == type(t, Machine::JbooleanType)
|
||||||
|
|| c == type(t, Machine::JbyteType))
|
||||||
|
return 1;
|
||||||
|
else if (c == type(t, Machine::JshortType)
|
||||||
|
|| c == type(t, Machine::JcharType))
|
||||||
|
return 2;
|
||||||
|
else if (c == type(t, Machine::JintType)
|
||||||
|
|| c == type(t, Machine::JfloatType))
|
||||||
|
return 4;
|
||||||
|
else if (c == type(t, Machine::JlongType)
|
||||||
|
|| c == type(t, Machine::JdoubleType))
|
||||||
|
return 8;
|
||||||
|
else
|
||||||
|
return BytesPerWord;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" AVIAN_EXPORT int64_t JNICALL
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
||||||
Avian_java_nio_FixedArrayByteBuffer_allocateFixed
|
Avian_java_nio_FixedArrayByteBuffer_allocateFixed
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
|
@ -2558,28 +2558,6 @@ Avian_sun_misc_Unsafe_staticFieldOffset
|
|||||||
(t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield)));
|
(t, jclassVmClass(t, jfieldClazz(t, jfield))), jfieldSlot(t, jfield)));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" AVIAN_EXPORT int64_t JNICALL
|
|
||||||
Avian_sun_misc_Unsafe_arrayIndexScale
|
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
|
||||||
{
|
|
||||||
switch (byteArrayBody
|
|
||||||
(t, className
|
|
||||||
(t, jclassVmClass(t, reinterpret_cast<object>(arguments[1]))), 1))
|
|
||||||
{
|
|
||||||
case 'Z':
|
|
||||||
case 'B': return 1;
|
|
||||||
case 'S':
|
|
||||||
case 'C': return 2;
|
|
||||||
case 'I':
|
|
||||||
case 'F': return 4;
|
|
||||||
case 'J':
|
|
||||||
case 'D': return 8;
|
|
||||||
case '[':
|
|
||||||
case 'L': return BytesPerWord;
|
|
||||||
default: abort(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" AVIAN_EXPORT int64_t JNICALL
|
extern "C" AVIAN_EXPORT int64_t JNICALL
|
||||||
Avian_sun_misc_Unsafe_staticFieldBase
|
Avian_sun_misc_Unsafe_staticFieldBase
|
||||||
(Thread* t, object, uintptr_t* arguments)
|
(Thread* t, object, uintptr_t* arguments)
|
||||||
|
166
test/Concurrent.java
Normal file
166
test/Concurrent.java
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class Concurrent {
|
||||||
|
private static final int ThreadCount = 4;
|
||||||
|
private static final int IterationCount = 100;
|
||||||
|
private static final int Range = 10;
|
||||||
|
private static final int CommonBase = -Range;
|
||||||
|
|
||||||
|
private static void expect(boolean v) {
|
||||||
|
if (! v) throw new RuntimeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
final ConcurrentMap<Integer, Object> map = new ConcurrentHashMap();
|
||||||
|
final int[] counter = new int[1];
|
||||||
|
final int[] step = new int[1];
|
||||||
|
final Throwable[] exception = new Throwable[1];
|
||||||
|
|
||||||
|
synchronized (map) {
|
||||||
|
for (int i = 0; i < ThreadCount; ++i) {
|
||||||
|
final int index = i;
|
||||||
|
new Thread() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
synchronized (map) {
|
||||||
|
++ counter[0];
|
||||||
|
map.notifyAll();
|
||||||
|
while (exception[0] == null && step[0] == 0) {
|
||||||
|
map.wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < IterationCount; ++i) {
|
||||||
|
populateCommon(map);
|
||||||
|
populate(map, index * Range);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (map) {
|
||||||
|
-- counter[0];
|
||||||
|
map.notifyAll();
|
||||||
|
while (exception[0] == null && step[0] == 1) {
|
||||||
|
map.wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < IterationCount; ++i) {
|
||||||
|
populate(map, index * Range);
|
||||||
|
depopulate(map, index * Range);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (map) {
|
||||||
|
++ counter[0];
|
||||||
|
map.notifyAll();
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
synchronized (map) {
|
||||||
|
exception[0] = e;
|
||||||
|
map.notifyAll();
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (exception[0] == null && counter[0] < ThreadCount) {
|
||||||
|
map.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
step[0] = 1;
|
||||||
|
map.notifyAll();
|
||||||
|
|
||||||
|
while (exception[0] == null && counter[0] > 0) {
|
||||||
|
map.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.size() != ThreadCount * Range) {
|
||||||
|
System.err.println
|
||||||
|
("expected " + (ThreadCount * Range) + " got " + map.size());
|
||||||
|
}
|
||||||
|
expect(map.size() == ThreadCount * Range);
|
||||||
|
for (int i = CommonBase, j = CommonBase + Range; i < j; ++i) {
|
||||||
|
expect(! map.containsKey(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
step[0] = 2;
|
||||||
|
map.notifyAll();
|
||||||
|
|
||||||
|
while (exception[0] == null && counter[0] < ThreadCount) {
|
||||||
|
map.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(map.isEmpty());
|
||||||
|
expect(exception[0] == null);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
exception[0] = e;
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
map.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void populateCommon(ConcurrentMap<Integer, Object> map) {
|
||||||
|
Object value = new Object();
|
||||||
|
for (int i = CommonBase, j = CommonBase + Range; i < j; ++i) {
|
||||||
|
map.remove(i);
|
||||||
|
map.put(i, value);
|
||||||
|
map.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void populate(ConcurrentMap<Integer, Object> map, int base) {
|
||||||
|
for (int i = base, j = base + Range; i < j; ++i) {
|
||||||
|
map.remove(i);
|
||||||
|
Object value = new Object();
|
||||||
|
expect(map.put(i, value) == null);
|
||||||
|
expect(map.containsKey(i));
|
||||||
|
expect(map.get(i).equals(value));
|
||||||
|
expect(map.putIfAbsent(i, new Object()) == value);
|
||||||
|
expect(map.get(i).equals(value));
|
||||||
|
expect(! map.remove(i, new Object()));
|
||||||
|
expect(map.remove(i, value));
|
||||||
|
expect(map.replace(i, value) == null);
|
||||||
|
expect(! map.containsKey(i));
|
||||||
|
expect(map.get(i) == null);
|
||||||
|
expect(map.putIfAbsent(i, value) == null);
|
||||||
|
expect(map.containsKey(i));
|
||||||
|
expect(map.get(i) == value);
|
||||||
|
Object newValue = new Object();
|
||||||
|
expect(map.replace(i, newValue) == value);
|
||||||
|
expect(map.get(i) == newValue);
|
||||||
|
|
||||||
|
boolean found = false;
|
||||||
|
for (Iterator<Map.Entry<Integer, Object>> it = map.entrySet().iterator();
|
||||||
|
it.hasNext();)
|
||||||
|
{
|
||||||
|
Map.Entry<Integer, Object> e = it.next();
|
||||||
|
if (e.getKey() == i) {
|
||||||
|
expect(! found);
|
||||||
|
expect(e.getValue() == newValue);
|
||||||
|
found = true;
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(found);
|
||||||
|
expect(! map.containsKey(i));
|
||||||
|
expect(map.putIfAbsent(i, value) == null);
|
||||||
|
expect(map.containsKey(i));
|
||||||
|
expect(map.get(i) == value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void depopulate(ConcurrentMap<Integer, Object> map, int base)
|
||||||
|
{
|
||||||
|
for (int i = base, j = base + Range; i < j; ++i) {
|
||||||
|
expect(map.containsKey(i));
|
||||||
|
expect(map.remove(i) != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user