mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-23 09:05:54 +08:00
GP-6539 - Accumulator API - Fixed thread visibility issues; simplified the API to be write focused
This commit is contained in:
+2
-2
@@ -90,7 +90,7 @@ public class AddressRangeTableModel extends GhidraProgramTableModel<AddressRange
|
||||
range.getMaxAddress(), range.getLength(), isSameByte, numRefsTo, numRefsFrom);
|
||||
|
||||
accumulator.add(info);
|
||||
if (accumulator.size() >= resultsLimit) {
|
||||
if (accumulator.getProgress() >= resultsLimit) {
|
||||
Msg.showWarn(this, null, "Results Truncated",
|
||||
"Results are limited to " + resultsLimit + " address ranges.\n" +
|
||||
"This limit can be changed by the tool option \"" +
|
||||
@@ -99,7 +99,7 @@ public class AddressRangeTableModel extends GhidraProgramTableModel<AddressRange
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (accumulator.isEmpty()) {
|
||||
if (accumulator.getProgress() == 0) {
|
||||
Msg.showWarn(this, null, "No Ranges to Display",
|
||||
"No ranges to display - consider adjusting \"" +
|
||||
CodeBrowserSelectionPlugin.OPTION_CATEGORY_NAME + " -> " +
|
||||
|
||||
+1
-1
@@ -233,7 +233,7 @@ public class CodeBrowserSelectionPlugin extends Plugin {
|
||||
monitor.initialize(size);
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
if (accumulator.size() >= resultsLimit) {
|
||||
if (accumulator.getProgress() >= resultsLimit) {
|
||||
Msg.showWarn(this, null, "Results Truncated",
|
||||
"Results are limited to " + resultsLimit + " code units.\n" +
|
||||
"This limit can be changed by the tool option \"" +
|
||||
|
||||
+14
-7
@@ -31,6 +31,7 @@ import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.datastruct.Accumulator;
|
||||
import ghidra.util.datastruct.SetAccumulatorWrapper;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@@ -343,16 +344,22 @@ public abstract class LocationDescriptor {
|
||||
private void getReferenceAddressSet(Accumulator<LocationReference> accumulator,
|
||||
TaskMonitor monitor, boolean reload) throws CancelledException {
|
||||
|
||||
if (referenceAddressList == null || reload) {
|
||||
doGetReferences(accumulator, monitor);
|
||||
|
||||
// put into list so that we can later perform fast lookups of Addresses
|
||||
referenceAddressList = new ArrayList<>(accumulator.get());
|
||||
Collections.sort(referenceAddressList);
|
||||
if (referenceAddressList != null && !reload) {
|
||||
accumulator.addAll(referenceAddressList);
|
||||
return;
|
||||
}
|
||||
|
||||
accumulator.addAll(referenceAddressList);
|
||||
// We do not want duplicates. Use a known set accumulator here, which also allows us to get
|
||||
// the results when the loading is finished.
|
||||
SetAccumulatorWrapper<LocationReference> setAccumulator =
|
||||
new SetAccumulatorWrapper<>(accumulator);
|
||||
|
||||
doGetReferences(setAccumulator, monitor);
|
||||
|
||||
// Save results so we can later perform fast lookups of Addresses using a binary search
|
||||
referenceAddressList = new ArrayList<>(setAccumulator.asSet());
|
||||
Collections.sort(referenceAddressList);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+12
-29
@@ -16,7 +16,6 @@
|
||||
package ghidra.app.plugin.core.navigation.locationreferences;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Stack;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -24,14 +23,14 @@ import docking.widgets.search.SearchLocationContext;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Array;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.classfinder.ClassSearcher;
|
||||
import ghidra.util.datastruct.*;
|
||||
import ghidra.util.datastruct.Accumulator;
|
||||
import ghidra.util.datastruct.SetAccumulator;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@@ -74,16 +73,14 @@ public final class ReferenceUtils {
|
||||
public static void getReferences(Accumulator<LocationReference> accumulator,
|
||||
ProgramLocation location, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
Accumulator<LocationReference> asSet = asSet(accumulator);
|
||||
|
||||
Program program = location.getProgram();
|
||||
Address address = location.getAddress();
|
||||
Consumer<LocationReference> consumer = ref -> accumulator.add(ref);
|
||||
accumulateDirectReferences(consumer, program, address);
|
||||
accumulateThunkReferences(asSet, program, address, monitor);
|
||||
accumulateThunkReferences(accumulator, program, address, monitor);
|
||||
|
||||
if (isMemoryAddress(location)) {
|
||||
accumulateOffcutReferencesToCodeUnitAt(asSet, location, monitor);
|
||||
accumulateOffcutReferencesToCodeUnitAt(accumulator, location, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,23 +288,20 @@ public final class ReferenceUtils {
|
||||
|
||||
monitor.initialize(totalCount);
|
||||
|
||||
// Mimic a set in case the client passes in an accumulator that allows duplicates. This
|
||||
// seems a bit cleaner than adding checks for 'accumulator.contains(ref)' throughout
|
||||
// the code.
|
||||
Accumulator<LocationReference> asSet = asSet(accumulator);
|
||||
|
||||
if (fieldMatcher.isIgnored()) {
|
||||
//
|
||||
// It only makes sense to search here when we do not have a field to match
|
||||
//
|
||||
boolean localsOnly = discoverTypes;
|
||||
FunctionIterator iterator = listing.getFunctions(false);
|
||||
findDataTypeMatchesInFunctionHeaders(asSet, iterator, dataType, localsOnly, monitor);
|
||||
findDataTypeMatchesInFunctionHeaders(accumulator, iterator, dataType, localsOnly,
|
||||
monitor);
|
||||
|
||||
// external functions don't get searched by type discovery
|
||||
localsOnly = false;
|
||||
iterator = listing.getExternalFunctions();
|
||||
findDataTypeMatchesInFunctionHeaders(asSet, iterator, dataType, localsOnly, monitor);
|
||||
findDataTypeMatchesInFunctionHeaders(accumulator, iterator, dataType, localsOnly,
|
||||
monitor);
|
||||
}
|
||||
|
||||
Predicate<Data> dataMatcher = data -> {
|
||||
@@ -316,25 +310,16 @@ public final class ReferenceUtils {
|
||||
return matches;
|
||||
};
|
||||
|
||||
findDataTypeMatchesInDefinedData(asSet, program, dataMatcher, fieldMatcher, monitor);
|
||||
findDataTypeMatchesInDefinedData(accumulator, program, dataMatcher, fieldMatcher, monitor);
|
||||
|
||||
if (discoverTypes) {
|
||||
findDataTypeMatchesOutsideOfListing(asSet, program, dataType, fieldMatcher, monitor);
|
||||
findDataTypeMatchesOutsideOfListing(accumulator, program, dataType, fieldMatcher,
|
||||
monitor);
|
||||
}
|
||||
|
||||
monitor.checkCancelled();
|
||||
}
|
||||
|
||||
private static Accumulator<LocationReference> asSet(
|
||||
Accumulator<LocationReference> accumulator) {
|
||||
|
||||
if (accumulator instanceof SetAccumulator) {
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
return new FilteringAccumulatorWrapper<>(accumulator, ref -> !accumulator.contains(ref));
|
||||
}
|
||||
|
||||
private static void findDataTypeMatchesOutsideOfListing(
|
||||
Accumulator<LocationReference> accumulator, Program program, DataType dataType,
|
||||
FieldMatcher fieldMatcher, TaskMonitor monitor) throws CancelledException {
|
||||
@@ -1173,9 +1158,7 @@ public final class ReferenceUtils {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!accumulator.contains(ref)) {
|
||||
accumulator.add(ref);
|
||||
}
|
||||
accumulator.add(ref);
|
||||
|
||||
// this address will either be the data, or the field's, if it exists
|
||||
Address dataAddress = ref.getLocationOfUse();
|
||||
|
||||
+2
-17
@@ -247,11 +247,6 @@ public class FunctionReachabilityTableModel
|
||||
this.accumulator = accumulator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<List<FRVertex>> iterator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(List<FRVertex> t) {
|
||||
accumulator.add(new FunctionReachabilityResult(fromFunction, toFunction, t));
|
||||
@@ -265,18 +260,8 @@ public class FunctionReachabilityTableModel
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(List<FRVertex> t) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<List<FRVertex>> get() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return accumulator.size();
|
||||
public int getProgress() {
|
||||
return accumulator.getProgress();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-17
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -34,7 +34,6 @@ import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.program.util.ProgramSelection;
|
||||
import ghidra.util.datastruct.Accumulator;
|
||||
import ghidra.util.datastruct.SizeLimitedAccumulatorWrapper;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.table.AddressBasedTableModel;
|
||||
import ghidra.util.table.column.AbstractGColumnRenderer;
|
||||
@@ -50,7 +49,7 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
|
||||
static final int PREVIEW_COLUMN = 1;
|
||||
static final int HEX_COLUMN = 2;
|
||||
|
||||
static final int TEMP_MAX_RESULTS = 1_000_000;
|
||||
static final int MAX_RESULTS = 100_000;
|
||||
|
||||
private Listing listing;
|
||||
|
||||
@@ -58,7 +57,7 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
|
||||
private long minValue;
|
||||
private long maxValue;
|
||||
|
||||
private SizeLimitedAccumulatorWrapper<ScalarRowObject> sizedAccumulator;
|
||||
private Accumulator<ScalarRowObject> currentAccumulator;
|
||||
|
||||
ScalarSearchModel(ScalarSearchPlugin plugin, ProgramSelection currentSelection) {
|
||||
super("Scalars", plugin.getTool(), null, null);
|
||||
@@ -92,7 +91,7 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
|
||||
return;
|
||||
}
|
||||
|
||||
sizedAccumulator = new SizeLimitedAccumulatorWrapper<>(accumulator, TEMP_MAX_RESULTS);
|
||||
currentAccumulator = accumulator;
|
||||
|
||||
if (currentSelection != null) {
|
||||
loadTableFromSelection(monitor);
|
||||
@@ -106,11 +105,7 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
|
||||
iterateOverInstructions(monitor, instructions);
|
||||
iterateOverData(monitor, dataIterator);
|
||||
|
||||
sizedAccumulator = null;
|
||||
}
|
||||
|
||||
private boolean tooManyResults() {
|
||||
return sizedAccumulator.hasReachedSizeLimit();
|
||||
currentAccumulator = null;
|
||||
}
|
||||
|
||||
void initialize(Program p, long newMinValue, long newMaxValue) {
|
||||
@@ -153,12 +148,11 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
|
||||
monitor.checkCancelled();
|
||||
monitor.incrementProgress(1);
|
||||
|
||||
if (tooManyResults()) {
|
||||
if (currentAccumulator.getProgress() > MAX_RESULTS) {
|
||||
return;
|
||||
}
|
||||
|
||||
int numOperands = instruction.getNumOperands();
|
||||
|
||||
for (int opIndex = 0; opIndex <= numOperands; opIndex++) {
|
||||
|
||||
monitor.checkCancelled();
|
||||
@@ -181,14 +175,12 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
|
||||
monitor.checkCancelled();
|
||||
monitor.incrementProgress(1);
|
||||
|
||||
if (tooManyResults()) {
|
||||
if (currentAccumulator.getProgress() > MAX_RESULTS) {
|
||||
return;
|
||||
}
|
||||
|
||||
Data data = dataIterator.next();
|
||||
|
||||
int numComponents = data.getNumComponents();
|
||||
|
||||
if (numComponents > 0) {
|
||||
findScalarsInCompositeData(data, numComponents, monitor);
|
||||
}
|
||||
@@ -223,7 +215,7 @@ public class ScalarSearchModel extends AddressBasedTableModel<ScalarRowObject> {
|
||||
return;
|
||||
}
|
||||
|
||||
sizedAccumulator.add(rowObject);
|
||||
currentAccumulator.add(rowObject);
|
||||
}
|
||||
|
||||
private void findScalarsInCompositeData(Data data, int numComponents, TaskMonitor monitor)
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ public abstract class AbstractSearchTableModel extends ProgramLocationPreviewTab
|
||||
Searcher searcher = getSearcher(tool, monitor);
|
||||
monitor.checkCancelled();
|
||||
TextSearchResult result = searcher.search();
|
||||
while (result != null && accumulator.size() < searchLimit) {
|
||||
while (result != null && accumulator.getProgress() < searchLimit) {
|
||||
accumulator.add(result.programLocation());
|
||||
monitor.checkCancelled();
|
||||
result = searcher.search();
|
||||
|
||||
-5
@@ -64,11 +64,6 @@ public class CombinedMatchTableLoader implements MemoryMatchTableLoader {
|
||||
previousResults = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemoryMatch getFirstMatch() {
|
||||
return firstMatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasResults() {
|
||||
return firstMatch != null;
|
||||
|
||||
-5
@@ -40,11 +40,6 @@ public class EmptyMemoryMatchTableLoader implements MemoryMatchTableLoader {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemoryMatch<SearchData> getFirstMatch() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasResults() {
|
||||
return false;
|
||||
|
||||
-5
@@ -78,11 +78,6 @@ public class FindOnceTableLoader implements MemoryMatchTableLoader {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemoryMatch getFirstMatch() {
|
||||
return match;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
previousResults = null;
|
||||
|
||||
-6
@@ -47,12 +47,6 @@ public interface MemoryMatchTableLoader {
|
||||
*/
|
||||
public void dispose();
|
||||
|
||||
/**
|
||||
* Returns the first match found. Typically used to navigate the associated navigatable.
|
||||
* @return the first match found
|
||||
*/
|
||||
public MemoryMatch getFirstMatch();
|
||||
|
||||
/**
|
||||
* Returns true if at least one match was found.
|
||||
* @return true if at least one match was found
|
||||
|
||||
+3
-13
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package ghidra.features.base.memsearch.gui;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import ghidra.features.base.memsearch.matcher.SearchData;
|
||||
import ghidra.features.base.memsearch.searcher.MemoryMatch;
|
||||
import ghidra.features.base.memsearch.searcher.MemorySearcher;
|
||||
@@ -30,7 +28,7 @@ public class NewSearchTableLoader implements MemoryMatchTableLoader {
|
||||
|
||||
private MemorySearcher<SearchData> memSearcher;
|
||||
private boolean completedSearch;
|
||||
private MemoryMatch<SearchData> firstMatch;
|
||||
private boolean hasResults;
|
||||
|
||||
NewSearchTableLoader(MemorySearcher<SearchData> memSearcher) {
|
||||
this.memSearcher = memSearcher;
|
||||
@@ -39,10 +37,7 @@ public class NewSearchTableLoader implements MemoryMatchTableLoader {
|
||||
@Override
|
||||
public void loadResults(Accumulator<MemoryMatch<SearchData>> accumulator, TaskMonitor monitor) {
|
||||
completedSearch = memSearcher.findAll(accumulator, monitor);
|
||||
Iterator<MemoryMatch<SearchData>> iterator = accumulator.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
firstMatch = iterator.next();
|
||||
}
|
||||
hasResults = accumulator.getProgress() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,14 +50,9 @@ public class NewSearchTableLoader implements MemoryMatchTableLoader {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemoryMatch getFirstMatch() {
|
||||
return firstMatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasResults() {
|
||||
return firstMatch != null;
|
||||
return hasResults;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-6
@@ -38,7 +38,7 @@ public class RefreshResultsTableLoader implements MemoryMatchTableLoader {
|
||||
@Override
|
||||
public void loadResults(Accumulator<MemoryMatch<SearchData>> accumulator, TaskMonitor monitor) {
|
||||
accumulator.addAll(matches);
|
||||
hasResults = !accumulator.isEmpty();
|
||||
hasResults = accumulator.getProgress() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,11 +52,6 @@ public class RefreshResultsTableLoader implements MemoryMatchTableLoader {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemoryMatch getFirstMatch() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasResults() {
|
||||
return hasResults;
|
||||
|
||||
+1
-1
@@ -327,7 +327,7 @@ public class MemorySearcher<T> {
|
||||
byte[] bytes = searchSequence.getBytes((int) match.getStart(), match.getLength());
|
||||
MemoryMatch<T> memMatch = new MemoryMatch<>(address, bytes, match.getPattern());
|
||||
if (filter.test(memMatch)) {
|
||||
if (accumulator.size() >= searchLimit) {
|
||||
if (accumulator.getProgress() >= searchLimit) {
|
||||
return false;
|
||||
}
|
||||
accumulator.add(memMatch);
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class SearchAndReplaceQuckFixTableLoader implements TableDataLoader<Quick
|
||||
searchLimitExceeded = true;
|
||||
}
|
||||
finally {
|
||||
hasResults = !accumulator.isEmpty();
|
||||
hasResults = accumulator.getProgress() != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -56,9 +56,10 @@ public class DatatypeCategorySearchAndReplaceHandler extends SearchAndReplaceHan
|
||||
Matcher matcher = pattern.matcher(category.getName());
|
||||
if (matcher.find()) {
|
||||
String newName = matcher.replaceAll(query.getReplacementText());
|
||||
RenameCategoryQuickFix item = new RenameCategoryQuickFix(program, category, newName);
|
||||
RenameCategoryQuickFix item =
|
||||
new RenameCategoryQuickFix(program, category, newName);
|
||||
accumulator.add(item);
|
||||
if (accumulator.size() >= query.getSearchLimit()) {
|
||||
if (accumulator.getProgress() >= query.getSearchLimit()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,7 @@ import ghidra.app.script.GhidraScript;
|
||||
import ghidra.features.base.memsearch.bytesource.AddressableByteSource;
|
||||
import ghidra.features.base.memsearch.bytesource.ProgramByteSource;
|
||||
import ghidra.features.base.memsearch.gui.SearchSettings;
|
||||
import ghidra.features.base.memsearch.matcher.ByteMatcher;
|
||||
import ghidra.features.base.memsearch.matcher.RegExByteMatcher;
|
||||
import ghidra.features.base.memsearch.matcher.*;
|
||||
import ghidra.features.base.memsearch.searcher.MemoryMatch;
|
||||
import ghidra.features.base.memsearch.searcher.MemorySearcher;
|
||||
import ghidra.framework.main.AppInfo;
|
||||
@@ -54,7 +53,6 @@ import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.program.util.AddressEvaluator;
|
||||
import ghidra.program.util.string.*;
|
||||
import ghidra.util.ascii.AsciiCharSetRecognizer;
|
||||
import ghidra.util.datastruct.Accumulator;
|
||||
import ghidra.util.datastruct.ListAccumulator;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -815,13 +813,14 @@ public class FlatProgramAPI {
|
||||
}
|
||||
|
||||
SearchSettings settings = new SearchSettings().withAlignment(alignment);
|
||||
ByteMatcher matcher = new RegExByteMatcher(byteString, settings);
|
||||
ByteMatcher<SearchData> matcher = new RegExByteMatcher(byteString, settings);
|
||||
AddressableByteSource byteSource = new ProgramByteSource(currentProgram);
|
||||
Memory memory = currentProgram.getMemory();
|
||||
AddressSet intersection = memory.getLoadedAndInitializedAddressSet().intersect(set);
|
||||
|
||||
MemorySearcher searcher = new MemorySearcher(byteSource, matcher, intersection, matchLimit);
|
||||
Accumulator<MemoryMatch> accumulator = new ListAccumulator<>();
|
||||
MemorySearcher<SearchData> searcher =
|
||||
new MemorySearcher<>(byteSource, matcher, intersection, matchLimit);
|
||||
ListAccumulator<MemoryMatch<SearchData>> accumulator = new ListAccumulator<>();
|
||||
searcher.findAll(accumulator, monitor);
|
||||
|
||||
//@formatter:off
|
||||
|
||||
@@ -264,7 +264,7 @@ public class ProgramMemoryUtil {
|
||||
public static void loadDirectReferenceList(Program program, int alignment, Address toAddress,
|
||||
AddressSetView toAddressSet, List<ReferenceAddressPair> directReferenceList,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
Accumulator<ReferenceAddressPair> accumulator = new ListAccumulator<>();
|
||||
ListAccumulator<ReferenceAddressPair> accumulator = new ListAccumulator<>();
|
||||
loadDirectReferenceList(program, alignment, toAddress, toAddressSet, accumulator, monitor);
|
||||
directReferenceList.addAll(accumulator.get());
|
||||
}
|
||||
|
||||
+4
-5
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -45,8 +45,7 @@ import ghidra.program.util.FieldNameFieldLocation;
|
||||
import ghidra.test.AbstractProgramBasedTest;
|
||||
import ghidra.test.ClassicSampleX86ProgramBuilder;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.datastruct.Accumulator;
|
||||
import ghidra.util.datastruct.ListAccumulator;
|
||||
import ghidra.util.datastruct.SetAccumulator;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -248,7 +247,7 @@ public abstract class AbstractLocationReferencesTest extends AbstractProgramBase
|
||||
|
||||
waitForTable();
|
||||
|
||||
Accumulator<LocationReference> accumulator = new ListAccumulator<>();
|
||||
SetAccumulator<LocationReference> accumulator = new SetAccumulator<>();
|
||||
runSwing(() -> {
|
||||
try {
|
||||
locationDescriptor.getReferences(accumulator, TaskMonitor.DUMMY, false);
|
||||
|
||||
+2
-3
@@ -27,7 +27,6 @@ import ghidra.features.base.memsearch.bytesource.SearchRegion;
|
||||
import ghidra.features.base.memsearch.matcher.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.datastruct.Accumulator;
|
||||
import ghidra.util.datastruct.ListAccumulator;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@@ -38,7 +37,7 @@ public class MemSearcherTest {
|
||||
private AddressSpace space;
|
||||
private TaskMonitor monitor = TaskMonitor.DUMMY;
|
||||
private ByteMatcher<SearchData> bobMatcher = new RegExByteMatcher("bob", null);
|
||||
private Accumulator<MemoryMatch<SearchData>> accumulator = new ListAccumulator<>();
|
||||
private ListAccumulator<MemoryMatch<SearchData>> accumulator = new ListAccumulator<>();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@@ -340,7 +339,7 @@ public class MemSearcherTest {
|
||||
public void invalidate() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ProgramLocation getCanonicalLocation(Address address) {
|
||||
return AddressableByteSource.generateProgramLocation(null, address);
|
||||
|
||||
@@ -43,7 +43,7 @@ import ghidra.program.util.ProgramMemoryUtil;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.bytesearch.*;
|
||||
import ghidra.util.datastruct.ListAccumulator;
|
||||
import ghidra.util.datastruct.SetAccumulator;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
@@ -4287,14 +4287,13 @@ public class RecoveredClassHelper {
|
||||
|
||||
monitor.checkCancelled();
|
||||
|
||||
ListAccumulator<LocationReference> accumulator = new ListAccumulator<>();
|
||||
|
||||
boolean discoverTypes = true;
|
||||
ReferenceUtils.findDataTypeReferences(accumulator, badStructure, program, discoverTypes,
|
||||
monitor);
|
||||
|
||||
List<LocationReference> referenceList = accumulator.asList();
|
||||
if (referenceList.isEmpty()) {
|
||||
SetAccumulator<LocationReference> accumulator = new SetAccumulator<>();
|
||||
ReferenceUtils.findDataTypeReferences(accumulator, badStructure, program,
|
||||
discoverTypes, monitor);
|
||||
|
||||
if (accumulator.size() == 0) {
|
||||
// delete empty class data type and empty parent folders
|
||||
removeEmptyStructure(badStructure.getDataTypePath().getCategoryPath(),
|
||||
badStructure.getName());
|
||||
|
||||
+32
-17
@@ -17,12 +17,12 @@ package docking.widgets.table.threaded;
|
||||
|
||||
import static org.apache.commons.lang3.exception.ExceptionUtils.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.Swing;
|
||||
import ghidra.util.datastruct.SynchronizedListAccumulator;
|
||||
import ghidra.util.datastruct.Accumulator;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.SwingUpdateManager;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -218,7 +218,9 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
||||
* An accumulator that will essentially periodically update the table with the data that
|
||||
* is being provided to the accumulator.
|
||||
*/
|
||||
private class IncrementalUpdatingAccumulator extends SynchronizedListAccumulator<ROW_OBJECT> {
|
||||
private class IncrementalUpdatingAccumulator implements Accumulator<ROW_OBJECT> {
|
||||
|
||||
private List<ROW_OBJECT> list = new ArrayList<>();
|
||||
private volatile boolean isDone;
|
||||
private Runnable runnable = () -> {
|
||||
|
||||
@@ -245,12 +247,6 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
||||
new SwingUpdateManager((int) threadedModel.getMinDelay(),
|
||||
(int) threadedModel.getMaxDelay(), "Incremental Table Load Update", runnable);
|
||||
|
||||
@Override
|
||||
public synchronized void add(ROW_OBJECT t) {
|
||||
super.add(t);
|
||||
swingUpdateManager.update();
|
||||
}
|
||||
|
||||
private boolean isCancelledOrDone() {
|
||||
return isCancelled || isDone;
|
||||
}
|
||||
@@ -259,18 +255,37 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
|
||||
swingUpdateManager.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addAll(Collection<ROW_OBJECT> collection) {
|
||||
super.addAll(collection);
|
||||
if (collection.size() > 0) {
|
||||
swingUpdateManager.update();
|
||||
}
|
||||
}
|
||||
|
||||
void flushData() {
|
||||
isDone = true;
|
||||
swingUpdateManager.dispose();
|
||||
updateManager.reloadSpecificData(asList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void add(ROW_OBJECT t) {
|
||||
list.add(t);
|
||||
swingUpdateManager.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addAll(Collection<ROW_OBJECT> collection) {
|
||||
list.addAll(collection);
|
||||
if (collection.size() > 0) {
|
||||
swingUpdateManager.update();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized List<ROW_OBJECT> asList() {
|
||||
return new ArrayList<>(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getProgress() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
private synchronized void clear() {
|
||||
list.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@ package ghidra.util.datastruct;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* The interface provides a mechanism for clients to pass around an object that is effectively
|
||||
@@ -30,27 +28,23 @@ import java.util.stream.StreamSupport;
|
||||
* to be returned by it) so that the client can make use of data as it is discovered. This
|
||||
* allows for long searching processes to report data as they work.
|
||||
*
|
||||
* <P>
|
||||
* Using this class implies that data will be added asynchronously. Implementations of this
|
||||
* interface should properly synchronize storage so that the data written is visible to the client
|
||||
* thread.
|
||||
*
|
||||
* @param <T> the type
|
||||
*/
|
||||
public interface Accumulator<T> extends Iterable<T>, Consumer<T> {
|
||||
public interface Accumulator<T> extends Consumer<T> {
|
||||
|
||||
public void add(T t);
|
||||
|
||||
public void addAll(Collection<T> collection);
|
||||
|
||||
public boolean contains(T t);
|
||||
|
||||
public Collection<T> get();
|
||||
|
||||
public int size();
|
||||
|
||||
default boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
default Stream<T> stream() {
|
||||
return StreamSupport.stream(spliterator(), false);
|
||||
}
|
||||
/**
|
||||
* {@return the number of items that have been added to this accumulator}
|
||||
*/
|
||||
public int getProgress();
|
||||
|
||||
@Override
|
||||
default void accept(T t) {
|
||||
|
||||
+11
-28
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -15,23 +15,20 @@
|
||||
*/
|
||||
package ghidra.util.datastruct;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An implementation of {@link Accumulator} that allows clients to easily process items as
|
||||
* they arrive.
|
||||
* they arrive.
|
||||
*
|
||||
* <P>This class is different than normal accumulators in that the values are <b>not</b>
|
||||
* stored internally. As such, calls to {@link #get()}, {@link #iterator()} and
|
||||
* {@link #size()} will reflect having no data.
|
||||
*
|
||||
* @param <T> the type of the item being accumulated
|
||||
*/
|
||||
public class CallbackAccumulator<T> implements Accumulator<T> {
|
||||
|
||||
private final Collection<T> NULL_COLLECTION = Collections.emptyList();
|
||||
|
||||
private AtomicInteger counter;
|
||||
private Consumer<T> consumer;
|
||||
|
||||
/**
|
||||
@@ -46,33 +43,19 @@ public class CallbackAccumulator<T> implements Accumulator<T> {
|
||||
@Override
|
||||
public void add(T t) {
|
||||
consumer.accept(t);
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(Collection<T> collection) {
|
||||
for (T t : collection) {
|
||||
consumer.accept(t);
|
||||
add(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(T t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> get() {
|
||||
return NULL_COLLECTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return NULL_COLLECTION.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
public int getProgress() {
|
||||
return counter.intValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -20,6 +20,8 @@ import org.apache.commons.lang3.mutable.MutableInt;
|
||||
/**
|
||||
* Simple class used to avoid immutable objects and autoboxing when storing changing integer
|
||||
* primitives in a collection.
|
||||
* <P>
|
||||
* @apiNote This class is not thread-safe.
|
||||
*/
|
||||
public class Counter extends MutableInt {
|
||||
/**
|
||||
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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 ghidra.util.datastruct;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A class that allows clients to wrap a given accumulator, only adding elements that pass the
|
||||
* given filter.
|
||||
*
|
||||
* @param <T> the type of the accumulator
|
||||
*/
|
||||
public class FilteringAccumulatorWrapper<T> implements Accumulator<T> {
|
||||
|
||||
private Accumulator<T> accumulator;
|
||||
private Predicate<T> predicate;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param accumulator the accumulator to pass items to
|
||||
* @param passesFilterPredicate the predicate that will return true for items that should be
|
||||
* allowed to pass
|
||||
*/
|
||||
public FilteringAccumulatorWrapper(Accumulator<T> accumulator,
|
||||
Predicate<T> passesFilterPredicate) {
|
||||
this.predicate = passesFilterPredicate;
|
||||
this.accumulator = Objects.requireNonNull(accumulator);
|
||||
}
|
||||
|
||||
private boolean passesFilter(T t) {
|
||||
return predicate.test(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return accumulator.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(T t) {
|
||||
if (passesFilter(t)) {
|
||||
accumulator.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(Collection<T> collection) {
|
||||
collection.forEach(t -> {
|
||||
if (passesFilter(t)) {
|
||||
accumulator.add(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(T t) {
|
||||
return accumulator.contains(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> get() {
|
||||
return accumulator.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return accumulator.size();
|
||||
}
|
||||
|
||||
}
|
||||
+24
-15
@@ -1,13 +1,12 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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.
|
||||
@@ -17,18 +16,22 @@
|
||||
package ghidra.util.datastruct;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class ListAccumulator<T> implements Accumulator<T> {
|
||||
/**
|
||||
* An accumulator backed by a thread safe list. This class has methods to retrieve the data once
|
||||
* all loading has finished.
|
||||
*
|
||||
* <P>
|
||||
* API uses of the accumulator are inherently multi-threaded. The list in this class is
|
||||
* synchronized so that the data in the accumulator will be visible to the client thread.
|
||||
*
|
||||
* @param <T> the type
|
||||
*/
|
||||
public class ListAccumulator<T> implements Accumulator<T>, Iterable<T> {
|
||||
|
||||
private List<T> list;
|
||||
|
||||
public ListAccumulator() {
|
||||
this.list = new ArrayList<T>();
|
||||
}
|
||||
|
||||
public ListAccumulator(List<T> list) {
|
||||
this.list = list;
|
||||
}
|
||||
private List<T> list = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
@Override
|
||||
public void add(T t) {
|
||||
@@ -41,11 +44,14 @@ public class ListAccumulator<T> implements Accumulator<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProgress() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public boolean contains(T t) {
|
||||
return list.contains(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> get() {
|
||||
return list;
|
||||
}
|
||||
@@ -54,7 +60,6 @@ public class ListAccumulator<T> implements Accumulator<T> {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return list.size();
|
||||
}
|
||||
@@ -64,6 +69,10 @@ public class ListAccumulator<T> implements Accumulator<T> {
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
public Stream<T> stream() {
|
||||
return StreamSupport.stream(spliterator(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return list.toString();
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* 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.
|
||||
@@ -17,18 +16,23 @@
|
||||
package ghidra.util.datastruct;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class SetAccumulator<T> implements Accumulator<T> {
|
||||
/**
|
||||
* An accumulator backed by a thread safe set. This class has methods to retrieve the data once all
|
||||
* loading has finished.
|
||||
*
|
||||
* <P>
|
||||
* API uses of the accumulator are inherently multi-threaded. The set in this class is
|
||||
* synchronized so that the data in the accumulator will be visible to the client thread.
|
||||
*
|
||||
* @param <T> the type
|
||||
*/
|
||||
public class SetAccumulator<T> implements Accumulator<T>, Iterable<T> {
|
||||
|
||||
private Set<T> set;
|
||||
|
||||
public SetAccumulator() {
|
||||
this.set = new HashSet<T>();
|
||||
}
|
||||
|
||||
public SetAccumulator(Set<T> set) {
|
||||
this.set = set;
|
||||
}
|
||||
private Set<T> set = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
public void add(T t) {
|
||||
@@ -40,12 +44,10 @@ public class SetAccumulator<T> implements Accumulator<T> {
|
||||
set.addAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(T t) {
|
||||
return set.contains(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> get() {
|
||||
return set;
|
||||
}
|
||||
@@ -55,6 +57,10 @@ public class SetAccumulator<T> implements Accumulator<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProgress() {
|
||||
return set.size();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return set.size();
|
||||
}
|
||||
@@ -64,6 +70,10 @@ public class SetAccumulator<T> implements Accumulator<T> {
|
||||
return set.iterator();
|
||||
}
|
||||
|
||||
public Stream<T> stream() {
|
||||
return StreamSupport.stream(spliterator(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return set.toString();
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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 ghidra.util.datastruct;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* An accumulator that will only pass on unique items to the wrapped accumulator. This class uses
|
||||
* a concurrent set, which means that the data will be copied in this accumulator while it is being
|
||||
* used.
|
||||
*
|
||||
* @param <T> the type
|
||||
*/
|
||||
public class SetAccumulatorWrapper<T> implements Accumulator<T> {
|
||||
|
||||
private Set<T> set = ConcurrentHashMap.newKeySet();
|
||||
private Accumulator<T> accumulator;
|
||||
|
||||
public SetAccumulatorWrapper(Accumulator<T> accumulator) {
|
||||
this.accumulator = accumulator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(T t) {
|
||||
if (set.add(t)) {
|
||||
accumulator.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(Collection<T> collection) {
|
||||
for (T t : collection) {
|
||||
add(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProgress() {
|
||||
return set.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the internal Set used by this class. This should only be called when the data is
|
||||
* finished loading.
|
||||
* @return the set
|
||||
*/
|
||||
public Set<T> asSet() {
|
||||
return set;
|
||||
}
|
||||
}
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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 ghidra.util.datastruct;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SizeLimitedAccumulatorWrapper<T> implements Accumulator<T> {
|
||||
|
||||
private Accumulator<T> accumulator;
|
||||
private int maxSize;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param accumulator the accumulator to pass items to
|
||||
* @param maxSize the maximum number of items this accumulator will hold
|
||||
*/
|
||||
public SizeLimitedAccumulatorWrapper(Accumulator<T> accumulator, int maxSize) {
|
||||
this.accumulator = Objects.requireNonNull(accumulator);
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return accumulator.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(T t) {
|
||||
accumulator.add(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(Collection<T> collection) {
|
||||
accumulator.addAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(T t) {
|
||||
return accumulator.contains(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> get() {
|
||||
return accumulator.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return accumulator.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this size of this accumulator is greater than or equal to the given
|
||||
* maximum size
|
||||
*
|
||||
* @return true if the max size has been reachged
|
||||
*/
|
||||
public boolean hasReachedSizeLimit() {
|
||||
return accumulator.size() >= maxSize;
|
||||
}
|
||||
}
|
||||
+6
-20
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
package ghidra.util.datastruct;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
public class SizeRestrictedAccumulatorWrapper<T> implements Accumulator<T> {
|
||||
|
||||
@@ -33,14 +34,9 @@ public class SizeRestrictedAccumulatorWrapper<T> implements Accumulator<T> {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return accumulator.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(T t) {
|
||||
if (accumulator.size() >= maxSize) {
|
||||
if (accumulator.getProgress() >= maxSize) {
|
||||
throw new AccumulatorSizeException(maxSize);
|
||||
}
|
||||
accumulator.add(t);
|
||||
@@ -49,23 +45,13 @@ public class SizeRestrictedAccumulatorWrapper<T> implements Accumulator<T> {
|
||||
@Override
|
||||
public void addAll(Collection<T> collection) {
|
||||
for (T t : collection) {
|
||||
accumulator.add(t);
|
||||
add(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(T t) {
|
||||
return accumulator.contains(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<T> get() {
|
||||
return accumulator.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return accumulator.size();
|
||||
public int getProgress() {
|
||||
return accumulator.getProgress();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* 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 ghidra.util.datastruct;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class SynchronizedListAccumulator<T> implements Accumulator<T> {
|
||||
|
||||
private List<T> list;
|
||||
|
||||
public SynchronizedListAccumulator() {
|
||||
this.list = new ArrayList<T>();
|
||||
}
|
||||
|
||||
public SynchronizedListAccumulator(List<T> list) {
|
||||
this.list = new ArrayList<T>(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void add(T t) {
|
||||
list.add(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void addAll(Collection<T> collection) {
|
||||
list.addAll(collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean contains(T t) {
|
||||
return list.contains(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Collection<T> get() {
|
||||
return new ArrayList<T>(list);
|
||||
}
|
||||
|
||||
public synchronized List<T> asList() {
|
||||
return new ArrayList<T>(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int size() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
list.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Iterator<T> iterator() {
|
||||
return asList().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
return list.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user