mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
Merge remote-tracking branch 'origin/GP-361-dragonmacher-copy-on-read-fixes--SQUASHED'
This commit is contained in:
@@ -16,53 +16,43 @@
|
|||||||
package ghidra.util.datastruct;
|
package ghidra.util.datastruct;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class CopyOnReadWeakSet<T> extends WeakSet<T> {
|
/**
|
||||||
|
* A copy on read set that will create a copy of its internal data for iteration operations. This
|
||||||
|
* allows clients to avoid concurrency issue by allowing mutates during reads. All operations
|
||||||
|
* of this class are synchronized to allow clients to use non-iterative methods without the need
|
||||||
|
* for a copy operation.
|
||||||
|
*
|
||||||
|
* @param <T> the type
|
||||||
|
*/
|
||||||
|
class CopyOnReadWeakSet<T> extends WeakSet<T> {
|
||||||
|
|
||||||
protected CopyOnReadWeakSet() {
|
protected CopyOnReadWeakSet() {
|
||||||
// restrict access; use factory method in WeakDataStructureFactory
|
// restrict access; use factory method in WeakDataStructureFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private synchronized Collection<T> createCopy() {
|
||||||
* Add the given object to the set.
|
Set<T> ks = weakHashStorage.keySet();
|
||||||
*/
|
return new ArrayList<>(ks);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void add(T t) {
|
public synchronized void add(T t) {
|
||||||
maybeWarnAboutAnonymousValue(t);
|
maybeWarnAboutAnonymousValue(t);
|
||||||
weakHashStorage.put(t, null);
|
weakHashStorage.put(t, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the given object from the data structure
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void remove(T t) {
|
public synchronized void remove(T t) {
|
||||||
weakHashStorage.remove(t);
|
weakHashStorage.remove(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all elements from this data structure
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void clear() {
|
public synchronized void clear() {
|
||||||
weakHashStorage.clear();
|
weakHashStorage.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an iterator over the elements in this data structure.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public synchronized Iterator<T> iterator() {
|
|
||||||
Set<T> ks = weakHashStorage.keySet();
|
|
||||||
List<T> list = new ArrayList<>(ks);
|
|
||||||
return list.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized Collection<T> values() {
|
|
||||||
return weakHashStorage.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isEmpty() {
|
public synchronized boolean isEmpty() {
|
||||||
return weakHashStorage.isEmpty();
|
return weakHashStorage.isEmpty();
|
||||||
@@ -77,4 +67,25 @@ public class CopyOnReadWeakSet<T> extends WeakSet<T> {
|
|||||||
public synchronized boolean contains(T t) {
|
public synchronized boolean contains(T t) {
|
||||||
return weakHashStorage.containsKey(t);
|
return weakHashStorage.containsKey(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized String toString() {
|
||||||
|
return weakHashStorage.keySet().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized Iterator<T> iterator() {
|
||||||
|
return createCopy().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized Collection<T> values() {
|
||||||
|
return createCopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized Stream<T> stream() {
|
||||||
|
return createCopy().stream();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package ghidra.util.datastruct;
|
package ghidra.util.datastruct;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.apache.commons.collections4.IteratorUtils;
|
import org.apache.commons.collections4.IteratorUtils;
|
||||||
|
|
||||||
@@ -25,12 +26,12 @@ import org.apache.commons.collections4.IteratorUtils;
|
|||||||
* number of event notification operations significantly out numbers mutations to this structure
|
* number of event notification operations significantly out numbers mutations to this structure
|
||||||
* (e.g., adding and removing items.
|
* (e.g., adding and removing items.
|
||||||
* <p>
|
* <p>
|
||||||
* An example use cases where using this class is a good fit would be a listener list where
|
* An example use case where using this class is a good fit would be a listener list where
|
||||||
* listeners are added during initialization, but not after that. Further, this hypothetical
|
* listeners are added during initialization, but not after that. Further, this hypothetical
|
||||||
* list is used to fire a large number of events.
|
* list is used to fire a large number of events.
|
||||||
* <p>
|
* <p>
|
||||||
* A bad use of this class would be as a container to store widgets where the container the
|
* A bad use of this class would be as a container to store widgets where the container the
|
||||||
* contents are changed often, but iterated over very little.
|
* contents are changed often, but iterated very little.
|
||||||
* <p>
|
* <p>
|
||||||
* Finally, if this structure is only ever used from a single thread, like the Swing thread, then
|
* Finally, if this structure is only ever used from a single thread, like the Swing thread, then
|
||||||
* you do not need the overhead of this class, as the Swing thread synchronous access guarantees
|
* you do not need the overhead of this class, as the Swing thread synchronous access guarantees
|
||||||
@@ -47,7 +48,7 @@ class CopyOnWriteWeakSet<T> extends WeakSet<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Iterator<T> iterator() {
|
public Iterator<T> iterator() {
|
||||||
return IteratorUtils.unmodifiableIterator(weakHashStorage.keySet().iterator());
|
return IteratorUtils.unmodifiableIterator(weakHashStorage.keySet().iterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,26 +61,29 @@ class CopyOnWriteWeakSet<T> extends WeakSet<T> {
|
|||||||
* @param it the items
|
* @param it the items
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void addAll(Iterable<T> it) {
|
public synchronized void addAll(Iterable<T> it) {
|
||||||
// only make one copy for the entire set of changes instead of for each change, as calling
|
// only make one copy for the entire set of changes instead of for each change, as calling
|
||||||
// add() would do
|
// add() would do
|
||||||
weakHashStorage = new WeakHashMap<>(weakHashStorage);
|
WeakHashMap<T, T> newStorage = new WeakHashMap<>(weakHashStorage);
|
||||||
for (T t : it) {
|
for (T t : it) {
|
||||||
weakHashStorage.put(t, null);
|
newStorage.put(t, null);
|
||||||
}
|
}
|
||||||
|
weakHashStorage = newStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void add(T t) {
|
public synchronized void add(T t) {
|
||||||
maybeWarnAboutAnonymousValue(t);
|
maybeWarnAboutAnonymousValue(t);
|
||||||
weakHashStorage = new WeakHashMap<>(weakHashStorage);
|
WeakHashMap<T, T> newStorage = new WeakHashMap<>(weakHashStorage);
|
||||||
weakHashStorage.put(t, null);
|
newStorage.put(t, null);
|
||||||
|
weakHashStorage = newStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void remove(T t) {
|
public synchronized void remove(T t) {
|
||||||
weakHashStorage = new WeakHashMap<>(weakHashStorage);
|
WeakHashMap<T, T> newStorage = new WeakHashMap<>(weakHashStorage);
|
||||||
weakHashStorage.remove(t);
|
newStorage.remove(t);
|
||||||
|
weakHashStorage = newStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -88,22 +92,32 @@ class CopyOnWriteWeakSet<T> extends WeakSet<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Collection<T> values() {
|
public Collection<T> values() {
|
||||||
return weakHashStorage.keySet();
|
return weakHashStorage.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return weakHashStorage.isEmpty();
|
return weakHashStorage.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized int size() {
|
public int size() {
|
||||||
return weakHashStorage.size();
|
return weakHashStorage.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean contains(T t) {
|
public boolean contains(T t) {
|
||||||
return weakHashStorage.containsKey(t);
|
return weakHashStorage.containsKey(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<T> stream() {
|
||||||
|
return values().stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return values().toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package ghidra.util.datastruct;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
class ThreadUnsafeWeakSet<T> extends WeakSet<T> {
|
class ThreadUnsafeWeakSet<T> extends WeakSet<T> {
|
||||||
|
|
||||||
@@ -24,34 +25,22 @@ class ThreadUnsafeWeakSet<T> extends WeakSet<T> {
|
|||||||
// restrict access; use factory method in base class
|
// restrict access; use factory method in base class
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the given object to the set.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void add(T t) {
|
public void add(T t) {
|
||||||
maybeWarnAboutAnonymousValue(t);
|
maybeWarnAboutAnonymousValue(t);
|
||||||
weakHashStorage.put(t, null);
|
weakHashStorage.put(t, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the given object from the data structure
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(T t) {
|
public void remove(T t) {
|
||||||
weakHashStorage.remove(t);
|
weakHashStorage.remove(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all elements from this data structure
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
weakHashStorage.clear();
|
weakHashStorage.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an iterator over the elements in this data structure.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<T> iterator() {
|
public Iterator<T> iterator() {
|
||||||
return weakHashStorage.keySet().iterator();
|
return weakHashStorage.keySet().iterator();
|
||||||
@@ -81,4 +70,10 @@ class ThreadUnsafeWeakSet<T> extends WeakSet<T> {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return weakHashStorage.toString();
|
return weakHashStorage.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<T> stream() {
|
||||||
|
return values().stream();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,12 +136,5 @@ public abstract class WeakSet<T> implements Iterable<T> {
|
|||||||
* Returns a stream of the values of this collection.
|
* Returns a stream of the values of this collection.
|
||||||
* @return a stream of the values of this collection.
|
* @return a stream of the values of this collection.
|
||||||
*/
|
*/
|
||||||
public Stream<T> stream() {
|
public abstract Stream<T> stream();
|
||||||
return values().stream();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return values().toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user