source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/StyleCache.java@ 17101

Last change on this file since 17101 was 17101, checked in by simon04, 4 years ago

fix #19752 - StyleCache.intern: use HashMap instead of Storage

  • Property svn:eol-style set to native
File size: 3.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import java.util.Arrays;
5import java.util.Map;
6import java.util.Optional;
7import java.util.concurrent.ConcurrentHashMap;
8import java.util.function.Function;
9
10import org.openstreetmap.josm.tools.Pair;
11
12/**
13 * Caches styles for a single primitive.
14 * <p>
15 * This object is immutable.
16 */
17public final class StyleCache {
18
19 // TODO: clean up the intern pool from time to time (after purge or layer removal)
20 private static final Map<StyleCache, StyleCache> internPool = new ConcurrentHashMap<>();
21
22 /**
23 * An empty style cache entry
24 */
25 public static final StyleCache EMPTY_STYLECACHE = new StyleCache().intern();
26
27 private static final int PLAIN = 0;
28 private static final int SELECTED = 1;
29
30 @SuppressWarnings("unchecked")
31 private final DividedScale<StyleElementList>[] states = new DividedScale[2];
32
33 private StyleCache(StyleCache sc) {
34 states[0] = sc.states[0];
35 states[1] = sc.states[1];
36 }
37
38 private StyleCache() {
39 }
40
41 /**
42 * Creates a new copy of this style cache with a new entry added.
43 * @param o The style to cache.
44 * @param r The range the style is for.
45 * @param selected The style list we should use (selected/unselected)
46 * @return The new object.
47 */
48 public StyleCache put(StyleElementList o, Range r, boolean selected) {
49 StyleCache s = new StyleCache(this);
50
51 int idx = getIndex(selected);
52 s.states[idx] = Optional.ofNullable(s.states[idx]).orElseGet(DividedScale::new).put(o, r);
53 return s.intern();
54 }
55
56 /**
57 * Get the style for a specific style. Returns the range as well.
58 * @param scale The current scale
59 * @param selected true to get the state for a selected element,
60 * @return The style and the range it is valid for.
61 */
62 public Pair<StyleElementList, Range> getWithRange(double scale, boolean selected) {
63 int idx = getIndex(selected);
64 if (states[idx] == null) {
65 return Pair.create(null, Range.ZERO_TO_INFINITY);
66 }
67 return states[idx].getWithRange(scale);
68 }
69
70 private static int getIndex(boolean selected) {
71 return selected ? SELECTED : PLAIN;
72 }
73
74 @Override
75 public String toString() {
76 return "StyleCache{PLAIN: " + this.states[PLAIN] + " SELECTED: " + this.states[SELECTED] + "}";
77 }
78
79 @Override
80 public int hashCode() {
81 return Arrays.deepHashCode(this.states);
82 }
83
84 @Override
85 public boolean equals(Object obj) {
86 if (obj == null) {
87 return false;
88 }
89 if (getClass() != obj.getClass()) {
90 return false;
91 }
92 final StyleCache other = (StyleCache) obj;
93 return Arrays.deepEquals(this.states, other.states);
94 }
95
96 /**
97 * Like String.intern() (reduce memory consumption).
98 * StyleCache must not be changed after it has been added to the intern pool.
99 * @return style cache
100 */
101 private StyleCache intern() {
102 return internPool.computeIfAbsent(this, Function.identity());
103 }
104
105 /**
106 * Clears the style cache. This should only be used for testing.
107 * It may be removed some day and replaced by a WeakReference implementation that automatically forgets old entries.
108 */
109 static void clearStyleCachePool() {
110 internPool.clear();
111 }
112
113 /**
114 * Get the size of the intern pool. Only for tests!
115 * @return size of the intern pool
116 */
117 public static int getInternPoolSize() {
118 return internPool.size();
119 }
120}
Note: See TracBrowser for help on using the repository browser.