source: josm/trunk/src/org/openstreetmap/josm/data/tagging/ac/AutoCompletionSet.java@ 13121

Last change on this file since 13121 was 13121, checked in by Don-vip, 6 years ago

fix #15547 - fix major performance drawback of AutoCompletionSet (regression from r12859)

  • Property svn:eol-style set to native
File size: 3.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.tagging.ac;
3
4import java.util.Collection;
5import java.util.Objects;
6import java.util.Optional;
7import java.util.Set;
8import java.util.TreeSet;
9import java.util.stream.Collectors;
10
11/**
12 * A sorted set of {@link AutoCompletionItem}s.
13 *
14 * Items are sorted with higher priority first, then according to lexicographic order
15 * on the value of the {@code AutoCompletionListItem}.
16 *
17 * @since 12859 (extracted from {@code gui.tagging.ac.AutoCompletionList})
18 */
19public class AutoCompletionSet extends TreeSet<AutoCompletionItem> {
20
21 // Keep a separate tree set of values for determining fast if a value is present
22 private final Set<String> values = new TreeSet<>();
23
24 @Override
25 public boolean add(AutoCompletionItem e) {
26 // Is there already an item for the value?
27 String value = e.getValue();
28 if (contains(value)) { // Fast
29 Optional<AutoCompletionItem> result = stream().filter(i -> i.getValue().equals(e.getValue())).findFirst(); // Slow
30 if (result.isPresent()) {
31 AutoCompletionItem item = result.get();
32 // yes: merge priorities
33 AutoCompletionPriority newPriority = item.getPriority().mergeWith(e.getPriority());
34 // if needed, remove/re-add the updated item to maintain set ordering
35 if (!item.getPriority().equals(newPriority)) {
36 super.remove(item);
37 item.setPriority(newPriority);
38 return super.add(item);
39 } else {
40 return false;
41 }
42 } else {
43 // Should never happen if values is correctly synchronized with this set
44 throw new IllegalStateException(value);
45 }
46 } else {
47 values.add(value);
48 return super.add(e);
49 }
50 }
51
52 @Override
53 public boolean remove(Object o) {
54 if (o instanceof AutoCompletionItem) {
55 values.remove(((AutoCompletionItem) o).getValue());
56 }
57 return super.remove(o);
58 }
59
60 @Override
61 public void clear() {
62 values.clear();
63 super.clear();
64 }
65
66 /**
67 * Adds a list of strings to this list. Only strings which
68 * are not null and which do not exist yet in the list are added.
69 *
70 * @param values a list of strings to add
71 * @param priority the priority to use
72 * @return {@code true} if this set changed as a result of the call
73 */
74 public boolean addAll(Collection<String> values, AutoCompletionPriority priority) {
75 return addAll(values.stream().filter(Objects::nonNull).map(v -> new AutoCompletionItem(v, priority)).collect(Collectors.toList()));
76 }
77
78 /**
79 * Adds values that have been entered by the user.
80 * @param values values that have been entered by the user
81 * @return {@code true} if this set changed as a result of the call
82 */
83 public boolean addUserInput(Collection<String> values) {
84 int i = 0;
85 boolean modified = false;
86 for (String value : values) {
87 if (value != null && add(new AutoCompletionItem(value, new AutoCompletionPriority(false, false, false, i++)))) {
88 modified = true;
89 }
90 }
91 return modified;
92 }
93
94 /**
95 * Checks whether an item with the given value is already in the list. Ignores priority of the items.
96 *
97 * @param value the value of an auto completion item
98 * @return true, if value is in the list; false, otherwise
99 */
100 public boolean contains(String value) {
101 return values.contains(value);
102 }
103
104 /**
105 * Removes the auto completion item with key <code>key</code>
106 * @param key the key
107 * @return {@code true} if an element was removed
108 */
109 public boolean remove(String key) {
110 return values.remove(key) && removeIf(i -> i.getValue().equals(key));
111 }
112}
Note: See TracBrowser for help on using the repository browser.