summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar 2xsaiko2020-05-19 08:19:19 +0200
committerGravatar GitHub2020-05-19 02:19:19 -0400
commit2b906a2c19d9c564808d4391be90c84de3b17581 (patch)
tree0e9a72e9a8f6953346b041896c96e8209abc87ef /src
parentQOL fixes - Volume 2 (#239) (diff)
downloadenigma-2b906a2c19d9c564808d4391be90c84de3b17581.tar.gz
enigma-2b906a2c19d9c564808d4391be90c84de3b17581.tar.xz
enigma-2b906a2c19d9c564808d4391be90c84de3b17581.zip
Async search (#245)
* Async search * Define index when it's used
Diffstat (limited to 'src')
-rw-r--r--src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java13
-rw-r--r--src/main/java/cuchaz/enigma/utils/search/SearchUtil.java73
2 files changed, 81 insertions, 5 deletions
diff --git a/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java
index b36ebfb4..b283a377 100644
--- a/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java
+++ b/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java
@@ -36,12 +36,13 @@ import cuchaz.enigma.utils.search.SearchUtil;
36public class SearchDialog { 36public class SearchDialog {
37 37
38 private final JTextField searchField; 38 private final JTextField searchField;
39 private final DefaultListModel<SearchEntryImpl> classListModel; 39 private DefaultListModel<SearchEntryImpl> classListModel;
40 private final JList<SearchEntryImpl> classList; 40 private final JList<SearchEntryImpl> classList;
41 private final JDialog dialog; 41 private final JDialog dialog;
42 42
43 private final Gui parent; 43 private final Gui parent;
44 private final SearchUtil<SearchEntryImpl> su; 44 private final SearchUtil<SearchEntryImpl> su;
45 private SearchUtil.SearchControl currentSearch;
45 46
46 public SearchDialog(Gui parent) { 47 public SearchDialog(Gui parent) {
47 this.parent = parent; 48 this.parent = parent;
@@ -173,11 +174,13 @@ public class SearchDialog {
173 174
174 // Updates the list of class names 175 // Updates the list of class names
175 private void updateList() { 176 private void updateList() {
176 classListModel.clear(); 177 if (currentSearch != null) currentSearch.stop();
177 178
178 su.search(searchField.getText()) 179 DefaultListModel<SearchEntryImpl> classListModel = new DefaultListModel<>();
179 .limit(100) 180 this.classListModel = classListModel;
180 .forEach(classListModel::addElement); 181 classList.setModel(classListModel);
182
183 currentSearch = su.asyncSearch(searchField.getText(), (idx, e) -> SwingUtilities.invokeLater(() -> classListModel.insertElementAt(e, idx)));
181 } 184 }
182 185
183 public void dispose() { 186 public void dispose() {
diff --git a/src/main/java/cuchaz/enigma/utils/search/SearchUtil.java b/src/main/java/cuchaz/enigma/utils/search/SearchUtil.java
index e5ed35fd..a51afbb0 100644
--- a/src/main/java/cuchaz/enigma/utils/search/SearchUtil.java
+++ b/src/main/java/cuchaz/enigma/utils/search/SearchUtil.java
@@ -1,6 +1,12 @@
1package cuchaz.enigma.utils.search; 1package cuchaz.enigma.utils.search;
2 2
3import java.util.*; 3import java.util.*;
4import java.util.concurrent.Executor;
5import java.util.concurrent.Executors;
6import java.util.concurrent.atomic.AtomicBoolean;
7import java.util.concurrent.atomic.AtomicInteger;
8import java.util.concurrent.locks.Lock;
9import java.util.concurrent.locks.ReentrantLock;
4import java.util.function.BiFunction; 10import java.util.function.BiFunction;
5import java.util.stream.Collectors; 11import java.util.stream.Collectors;
6import java.util.stream.Stream; 12import java.util.stream.Stream;
@@ -11,6 +17,7 @@ public class SearchUtil<T extends SearchEntry> {
11 17
12 private final Map<T, Entry<T>> entries = new HashMap<>(); 18 private final Map<T, Entry<T>> entries = new HashMap<>();
13 private final Map<String, Integer> hitCount = new HashMap<>(); 19 private final Map<String, Integer> hitCount = new HashMap<>();
20 private final Executor searchExecutor = Executors.newWorkStealingPool();
14 21
15 public void add(T entry) { 22 public void add(T entry) {
16 Entry<T> e = Entry.from(entry); 23 Entry<T> e = Entry.from(entry);
@@ -46,6 +53,59 @@ public class SearchUtil<T extends SearchEntry> {
46 .sequential(); 53 .sequential();
47 } 54 }
48 55
56 public SearchControl asyncSearch(String term, SearchResultConsumer<T> consumer) {
57 Map<String, Integer> hitCount = new HashMap<>(this.hitCount);
58 Map<T, Entry<T>> entries = new HashMap<>(this.entries);
59 float[] scores = new float[entries.size()];
60 Lock scoresLock = new ReentrantLock();
61 AtomicInteger size = new AtomicInteger();
62 AtomicBoolean control = new AtomicBoolean(false);
63 AtomicInteger elapsed = new AtomicInteger();
64 for (Entry<T> value : entries.values()) {
65 searchExecutor.execute(() -> {
66 try {
67 if (control.get()) return;
68 float score = value.getScore(term, hitCount.getOrDefault(value.searchEntry.getIdentifier(), 0));
69 if (score <= 0) return;
70 score = -score; // sort descending
71 try {
72 scoresLock.lock();
73 if (control.get()) return;
74 int dataSize = size.getAndIncrement();
75 int index = Arrays.binarySearch(scores, 0, dataSize, score);
76 if (index < 0) {
77 index = ~index;
78 }
79 System.arraycopy(scores, index, scores, index + 1, dataSize - index);
80 scores[index] = score;
81 consumer.add(index, value.searchEntry);
82 } finally {
83 scoresLock.unlock();
84 }
85 } finally {
86 elapsed.incrementAndGet();
87 }
88 });
89 }
90
91 return new SearchControl() {
92 @Override
93 public void stop() {
94 control.set(true);
95 }
96
97 @Override
98 public boolean isFinished() {
99 return entries.size() == elapsed.get();
100 }
101
102 @Override
103 public float getProgress() {
104 return (float) elapsed.get() / entries.size();
105 }
106 };
107 }
108
49 public void hit(T entry) { 109 public void hit(T entry) {
50 if (entries.containsKey(entry)) { 110 if (entries.containsKey(entry)) {
51 hitCount.compute(entry.getIdentifier(), (_id, i) -> i == null ? 1 : i + 1); 111 hitCount.compute(entry.getIdentifier(), (_id, i) -> i == null ? 1 : i + 1);
@@ -192,4 +252,17 @@ public class SearchUtil<T extends SearchEntry> {
192 252
193 } 253 }
194 254
255 @FunctionalInterface
256 public interface SearchResultConsumer<T extends SearchEntry> {
257 void add(int index, T entry);
258 }
259
260 public interface SearchControl {
261 void stop();
262
263 boolean isFinished();
264
265 float getProgress();
266 }
267
195} 268}