diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AddressRangeTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AddressRangeTableModel.java index 9bf1f6281d..433711e4b4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AddressRangeTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/AddressRangeTableModel.java @@ -90,7 +90,7 @@ public class AddressRangeTableModel extends GhidraProgramTableModel= 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 " + diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeBrowserSelectionPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeBrowserSelectionPlugin.java index 33eba0a28c..a574346b9b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeBrowserSelectionPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/CodeBrowserSelectionPlugin.java @@ -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 \"" + diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationDescriptor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationDescriptor.java index e2e37780f8..91816961f2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationDescriptor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationDescriptor.java @@ -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 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 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); + } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/ReferenceUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/ReferenceUtils.java index 3999c1d6b2..0ae801b137 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/ReferenceUtils.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/ReferenceUtils.java @@ -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 accumulator, ProgramLocation location, TaskMonitor monitor) throws CancelledException { - Accumulator asSet = asSet(accumulator); - Program program = location.getProgram(); Address address = location.getAddress(); Consumer 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 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 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 asSet( - Accumulator accumulator) { - - if (accumulator instanceof SetAccumulator) { - return accumulator; - } - - return new FilteringAccumulatorWrapper<>(accumulator, ref -> !accumulator.contains(ref)); - } - private static void findDataTypeMatchesOutsideOfListing( Accumulator 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(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityTableModel.java index b50b0fc62f..f467d985bd 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/reachability/FunctionReachabilityTableModel.java @@ -247,11 +247,6 @@ public class FunctionReachabilityTableModel this.accumulator = accumulator; } - @Override - public Iterator> iterator() { - throw new UnsupportedOperationException(); - } - @Override public void add(List t) { accumulator.add(new FunctionReachabilityResult(fromFunction, toFunction, t)); @@ -265,18 +260,8 @@ public class FunctionReachabilityTableModel } @Override - public boolean contains(List t) { - throw new UnsupportedOperationException(); - } - - @Override - public Collection> get() { - throw new UnsupportedOperationException(); - } - - @Override - public int size() { - return accumulator.size(); + public int getProgress() { + return accumulator.getProgress(); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/scalartable/ScalarSearchModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/scalartable/ScalarSearchModel.java index 61abea9a46..81977c277a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/scalartable/ScalarSearchModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/scalartable/ScalarSearchModel.java @@ -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 { 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 { private long minValue; private long maxValue; - private SizeLimitedAccumulatorWrapper sizedAccumulator; + private Accumulator currentAccumulator; ScalarSearchModel(ScalarSearchPlugin plugin, ProgramSelection currentSelection) { super("Scalars", plugin.getTool(), null, null); @@ -92,7 +91,7 @@ public class ScalarSearchModel extends AddressBasedTableModel { return; } - sizedAccumulator = new SizeLimitedAccumulatorWrapper<>(accumulator, TEMP_MAX_RESULTS); + currentAccumulator = accumulator; if (currentSelection != null) { loadTableFromSelection(monitor); @@ -106,11 +105,7 @@ public class ScalarSearchModel extends AddressBasedTableModel { 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 { 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 { 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 { return; } - sizedAccumulator.add(rowObject); + currentAccumulator.add(rowObject); } private void findScalarsInCompositeData(Data data, int numComponents, TaskMonitor monitor) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/AbstractSearchTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/AbstractSearchTableModel.java index d8af0b33f5..e39d4b3fff 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/AbstractSearchTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/searchtext/AbstractSearchTableModel.java @@ -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(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/CombinedMatchTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/CombinedMatchTableLoader.java index 1f5978ae20..4f6e375b73 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/CombinedMatchTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/CombinedMatchTableLoader.java @@ -64,11 +64,6 @@ public class CombinedMatchTableLoader implements MemoryMatchTableLoader { previousResults = null; } - @Override - public MemoryMatch getFirstMatch() { - return firstMatch; - } - @Override public boolean hasResults() { return firstMatch != null; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/EmptyMemoryMatchTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/EmptyMemoryMatchTableLoader.java index 7888153638..e8c9c32e0b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/EmptyMemoryMatchTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/EmptyMemoryMatchTableLoader.java @@ -40,11 +40,6 @@ public class EmptyMemoryMatchTableLoader implements MemoryMatchTableLoader { return false; } - @Override - public MemoryMatch getFirstMatch() { - return null; - } - @Override public boolean hasResults() { return false; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/FindOnceTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/FindOnceTableLoader.java index 1d36f1742b..79d0dd050a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/FindOnceTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/FindOnceTableLoader.java @@ -78,11 +78,6 @@ public class FindOnceTableLoader implements MemoryMatchTableLoader { return false; } - @Override - public MemoryMatch getFirstMatch() { - return match; - } - @Override public void dispose() { previousResults = null; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableLoader.java index 29de239188..43c3169175 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/MemoryMatchTableLoader.java @@ -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 diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/NewSearchTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/NewSearchTableLoader.java index e07227f1b2..95edeb24ec 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/NewSearchTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/NewSearchTableLoader.java @@ -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 memSearcher; private boolean completedSearch; - private MemoryMatch firstMatch; + private boolean hasResults; NewSearchTableLoader(MemorySearcher memSearcher) { this.memSearcher = memSearcher; @@ -39,10 +37,7 @@ public class NewSearchTableLoader implements MemoryMatchTableLoader { @Override public void loadResults(Accumulator> accumulator, TaskMonitor monitor) { completedSearch = memSearcher.findAll(accumulator, monitor); - Iterator> 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; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/RefreshResultsTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/RefreshResultsTableLoader.java index d27a8725f5..0b4e39f4a3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/RefreshResultsTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/gui/RefreshResultsTableLoader.java @@ -38,7 +38,7 @@ public class RefreshResultsTableLoader implements MemoryMatchTableLoader { @Override public void loadResults(Accumulator> 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; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemorySearcher.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemorySearcher.java index 522beb742b..d0f70f5170 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemorySearcher.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/memsearch/searcher/MemorySearcher.java @@ -327,7 +327,7 @@ public class MemorySearcher { byte[] bytes = searchSequence.getBytes((int) match.getStart(), match.getLength()); MemoryMatch memMatch = new MemoryMatch<>(address, bytes, match.getPattern()); if (filter.test(memMatch)) { - if (accumulator.size() >= searchLimit) { + if (accumulator.getProgress() >= searchLimit) { return false; } accumulator.add(memMatch); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/features/base/replace/SearchAndReplaceQuckFixTableLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/features/base/replace/SearchAndReplaceQuckFixTableLoader.java index 67899f852c..8089dbb208 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/features/base/replace/SearchAndReplaceQuckFixTableLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/features/base/replace/SearchAndReplaceQuckFixTableLoader.java @@ -50,7 +50,7 @@ public class SearchAndReplaceQuckFixTableLoader implements TableDataLoader= query.getSearchLimit()) { + if (accumulator.getProgress() >= query.getSearchLimit()) { return; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java b/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java index d7dd774432..afaac89556 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/flatapi/FlatProgramAPI.java @@ -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 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 accumulator = new ListAccumulator<>(); + MemorySearcher searcher = + new MemorySearcher<>(byteSource, matcher, intersection, matchLimit); + ListAccumulator> accumulator = new ListAccumulator<>(); searcher.findAll(accumulator, monitor); //@formatter:off diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java index 955c997a49..1130aa7fa6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/ProgramMemoryUtil.java @@ -264,7 +264,7 @@ public class ProgramMemoryUtil { public static void loadDirectReferenceList(Program program, int alignment, Address toAddress, AddressSetView toAddressSet, List directReferenceList, TaskMonitor monitor) throws CancelledException { - Accumulator accumulator = new ListAccumulator<>(); + ListAccumulator accumulator = new ListAccumulator<>(); loadDirectReferenceList(program, alignment, toAddress, toAddressSet, accumulator, monitor); directReferenceList.addAll(accumulator.get()); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/locationreferences/AbstractLocationReferencesTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/locationreferences/AbstractLocationReferencesTest.java index cd37ddbcdd..5b14645d57 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/locationreferences/AbstractLocationReferencesTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/navigation/locationreferences/AbstractLocationReferencesTest.java @@ -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 accumulator = new ListAccumulator<>(); + SetAccumulator accumulator = new SetAccumulator<>(); runSwing(() -> { try { locationDescriptor.getReferences(accumulator, TaskMonitor.DUMMY, false); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/searcher/MemSearcherTest.java b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/searcher/MemSearcherTest.java index 03a561ce62..bb47f7eda7 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/searcher/MemSearcherTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/features/base/memsearch/searcher/MemSearcherTest.java @@ -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 bobMatcher = new RegExByteMatcher("bob", null); - private Accumulator> accumulator = new ListAccumulator<>(); + private ListAccumulator> 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); diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java index b70ac04371..30f44bfddb 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/RecoveredClassHelper.java @@ -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 accumulator = new ListAccumulator<>(); - boolean discoverTypes = true; - ReferenceUtils.findDataTypeReferences(accumulator, badStructure, program, discoverTypes, - monitor); - List referenceList = accumulator.asList(); - if (referenceList.isEmpty()) { + SetAccumulator 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()); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/threaded/IncrementalLoadJob.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/threaded/IncrementalLoadJob.java index b11de86a0c..f367c705db 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/threaded/IncrementalLoadJob.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/threaded/IncrementalLoadJob.java @@ -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 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 { + private class IncrementalUpdatingAccumulator implements Accumulator { + + private List list = new ArrayList<>(); private volatile boolean isDone; private Runnable runnable = () -> { @@ -245,12 +247,6 @@ public class IncrementalLoadJob 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 extends Job implements ThreadedTable swingUpdateManager.dispose(); } - @Override - public synchronized void addAll(Collection 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 collection) { + list.addAll(collection); + if (collection.size() > 0) { + swingUpdateManager.update(); + } + } + + private synchronized List asList() { + return new ArrayList<>(list); + } + + @Override + public synchronized int getProgress() { + return list.size(); + } + + private synchronized void clear() { + list.clear(); + } } } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Accumulator.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Accumulator.java index 0915871d53..9f6c43dbae 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Accumulator.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Accumulator.java @@ -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. * + *

+ * 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 the type */ -public interface Accumulator extends Iterable, Consumer { +public interface Accumulator extends Consumer { public void add(T t); public void addAll(Collection collection); - public boolean contains(T t); - - public Collection get(); - - public int size(); - - default boolean isEmpty() { - return size() == 0; - } - - default Stream 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) { diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/CallbackAccumulator.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/CallbackAccumulator.java index e4c1af7780..382bea5fe7 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/CallbackAccumulator.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/CallbackAccumulator.java @@ -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. * - *

This class is different than normal accumulators in that the values are not - * stored internally. As such, calls to {@link #get()}, {@link #iterator()} and - * {@link #size()} will reflect having no data. - * * @param the type of the item being accumulated */ public class CallbackAccumulator implements Accumulator { - private final Collection NULL_COLLECTION = Collections.emptyList(); - + private AtomicInteger counter; private Consumer consumer; /** @@ -46,33 +43,19 @@ public class CallbackAccumulator implements Accumulator { @Override public void add(T t) { consumer.accept(t); + counter.incrementAndGet(); } @Override public void addAll(Collection collection) { for (T t : collection) { - consumer.accept(t); + add(t); } } @Override - public boolean contains(T t) { - return false; - } - - @Override - public Collection get() { - return NULL_COLLECTION; - } - - @Override - public Iterator iterator() { - return NULL_COLLECTION.iterator(); - } - - @Override - public int size() { - return 0; + public int getProgress() { + return counter.intValue(); } } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Counter.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Counter.java index 275b73c0c3..7d6b6868fd 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Counter.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/Counter.java @@ -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. + *

+ * @apiNote This class is not thread-safe. */ public class Counter extends MutableInt { /** diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/FilteringAccumulatorWrapper.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/FilteringAccumulatorWrapper.java deleted file mode 100644 index ef1b64a806..0000000000 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/FilteringAccumulatorWrapper.java +++ /dev/null @@ -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 the type of the accumulator - */ -public class FilteringAccumulatorWrapper implements Accumulator { - - private Accumulator accumulator; - private Predicate 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 accumulator, - Predicate passesFilterPredicate) { - this.predicate = passesFilterPredicate; - this.accumulator = Objects.requireNonNull(accumulator); - } - - private boolean passesFilter(T t) { - return predicate.test(t); - } - - @Override - public Iterator iterator() { - return accumulator.iterator(); - } - - @Override - public void add(T t) { - if (passesFilter(t)) { - accumulator.add(t); - } - } - - @Override - public void addAll(Collection collection) { - collection.forEach(t -> { - if (passesFilter(t)) { - accumulator.add(t); - } - }); - } - - @Override - public boolean contains(T t) { - return accumulator.contains(t); - } - - @Override - public Collection get() { - return accumulator.get(); - } - - @Override - public int size() { - return accumulator.size(); - } - -} diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/ListAccumulator.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/ListAccumulator.java index 5780a72864..5f163d2b5b 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/ListAccumulator.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/ListAccumulator.java @@ -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 implements Accumulator { +/** + * An accumulator backed by a thread safe list. This class has methods to retrieve the data once + * all loading has finished. + * + *

+ * 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 the type + */ +public class ListAccumulator implements Accumulator, Iterable { - private List list; - - public ListAccumulator() { - this.list = new ArrayList(); - } - - public ListAccumulator(List list) { - this.list = list; - } + private List list = Collections.synchronizedList(new ArrayList<>()); @Override public void add(T t) { @@ -41,11 +44,14 @@ public class ListAccumulator implements Accumulator { } @Override + public int getProgress() { + return list.size(); + } + public boolean contains(T t) { return list.contains(t); } - @Override public Collection get() { return list; } @@ -54,7 +60,6 @@ public class ListAccumulator implements Accumulator { return list; } - @Override public int size() { return list.size(); } @@ -64,6 +69,10 @@ public class ListAccumulator implements Accumulator { return list.iterator(); } + public Stream stream() { + return StreamSupport.stream(spliterator(), false); + } + @Override public String toString() { return list.toString(); diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SetAccumulator.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SetAccumulator.java index 5f82b80e41..fd5ae0e668 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SetAccumulator.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SetAccumulator.java @@ -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 implements Accumulator { +/** + * An accumulator backed by a thread safe set. This class has methods to retrieve the data once all + * loading has finished. + * + *

+ * 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 the type + */ +public class SetAccumulator implements Accumulator, Iterable { - private Set set; - - public SetAccumulator() { - this.set = new HashSet(); - } - - public SetAccumulator(Set set) { - this.set = set; - } + private Set set = ConcurrentHashMap.newKeySet(); @Override public void add(T t) { @@ -40,12 +44,10 @@ public class SetAccumulator implements Accumulator { set.addAll(collection); } - @Override public boolean contains(T t) { return set.contains(t); } - @Override public Collection get() { return set; } @@ -55,6 +57,10 @@ public class SetAccumulator implements Accumulator { } @Override + public int getProgress() { + return set.size(); + } + public int size() { return set.size(); } @@ -64,6 +70,10 @@ public class SetAccumulator implements Accumulator { return set.iterator(); } + public Stream stream() { + return StreamSupport.stream(spliterator(), false); + } + @Override public String toString() { return set.toString(); diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SetAccumulatorWrapper.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SetAccumulatorWrapper.java new file mode 100644 index 0000000000..1259463ee0 --- /dev/null +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SetAccumulatorWrapper.java @@ -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 the type + */ +public class SetAccumulatorWrapper implements Accumulator { + + private Set set = ConcurrentHashMap.newKeySet(); + private Accumulator accumulator; + + public SetAccumulatorWrapper(Accumulator accumulator) { + this.accumulator = accumulator; + } + + @Override + public void add(T t) { + if (set.add(t)) { + accumulator.add(t); + } + } + + @Override + public void addAll(Collection 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 asSet() { + return set; + } +} diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SizeLimitedAccumulatorWrapper.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SizeLimitedAccumulatorWrapper.java deleted file mode 100644 index a153812fe8..0000000000 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SizeLimitedAccumulatorWrapper.java +++ /dev/null @@ -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 implements Accumulator { - - private Accumulator 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 accumulator, int maxSize) { - this.accumulator = Objects.requireNonNull(accumulator); - this.maxSize = maxSize; - } - - @Override - public Iterator iterator() { - return accumulator.iterator(); - } - - @Override - public void add(T t) { - accumulator.add(t); - } - - @Override - public void addAll(Collection collection) { - accumulator.addAll(collection); - } - - @Override - public boolean contains(T t) { - return accumulator.contains(t); - } - - @Override - public Collection 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; - } -} diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SizeRestrictedAccumulatorWrapper.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SizeRestrictedAccumulatorWrapper.java index 3f82b69eaf..cfa1d543f3 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SizeRestrictedAccumulatorWrapper.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SizeRestrictedAccumulatorWrapper.java @@ -15,7 +15,8 @@ */ package ghidra.util.datastruct; -import java.util.*; +import java.util.Collection; +import java.util.Objects; public class SizeRestrictedAccumulatorWrapper implements Accumulator { @@ -33,14 +34,9 @@ public class SizeRestrictedAccumulatorWrapper implements Accumulator { this.maxSize = maxSize; } - @Override - public Iterator 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 implements Accumulator { @Override public void addAll(Collection collection) { for (T t : collection) { - accumulator.add(t); + add(t); } } @Override - public boolean contains(T t) { - return accumulator.contains(t); - } - - @Override - public Collection get() { - return accumulator.get(); - } - - @Override - public int size() { - return accumulator.size(); + public int getProgress() { + return accumulator.getProgress(); } } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SynchronizedListAccumulator.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SynchronizedListAccumulator.java deleted file mode 100644 index 3ecd2fdb09..0000000000 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/SynchronizedListAccumulator.java +++ /dev/null @@ -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 implements Accumulator { - - private List list; - - public SynchronizedListAccumulator() { - this.list = new ArrayList(); - } - - public SynchronizedListAccumulator(List list) { - this.list = new ArrayList(list); - } - - @Override - public synchronized void add(T t) { - list.add(t); - } - - @Override - public synchronized void addAll(Collection collection) { - list.addAll(collection); - } - - @Override - public synchronized boolean contains(T t) { - return list.contains(t); - } - - @Override - public synchronized Collection get() { - return new ArrayList(list); - } - - public synchronized List asList() { - return new ArrayList(list); - } - - @Override - public synchronized int size() { - return list.size(); - } - - public void clear() { - list.clear(); - } - - @Override - public synchronized Iterator iterator() { - return asList().iterator(); - } - - @Override - public synchronized String toString() { - return list.toString(); - } -}