001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.mappaint; 003 004import java.util.Arrays; 005 006import org.openstreetmap.josm.data.osm.Storage; 007import org.openstreetmap.josm.tools.Pair; 008 009/** 010 * Caches styles for a single primitive. 011 */ 012public final class StyleCache { 013 014 // TODO: clean up the intern pool from time to time (after purge or layer removal) 015 private static final Storage<StyleCache> internPool = new Storage<>(); 016 017 public static final StyleCache EMPTY_STYLECACHE = (new StyleCache()).intern(); 018 019 private static final int PLAIN = 0; 020 private static final int SELECTED = 1; 021 022 @SuppressWarnings("unchecked") 023 private final DividedScale<StyleElementList>[] states = new DividedScale[2]; 024 025 private StyleCache(StyleCache sc) { 026 states[0] = sc.states[0]; 027 states[1] = sc.states[1]; 028 } 029 030 private StyleCache() { 031 } 032 033 public StyleCache put(StyleElementList o, Range r, boolean selected) { 034 StyleCache s = new StyleCache(this); 035 036 int idx = getIndex(selected); 037 DividedScale<StyleElementList> ds = s.states[idx]; 038 if (ds == null) { 039 ds = s.states[idx] = new DividedScale<>(); 040 } 041 ds.putImpl(o, r.getLower(), r.getUpper()); 042 ds.consistencyTest(); 043 s.intern(); 044 return s; 045 } 046 047 public Pair<StyleElementList, Range> getWithRange(double scale, boolean selected) { 048 int idx = getIndex(selected); 049 if (states[idx] == null) { 050 return Pair.create(null, Range.ZERO_TO_INFINITY); 051 } 052 return states[idx].getWithRange(scale); 053 } 054 055 private int getIndex(boolean selected) { 056 return selected ? SELECTED : PLAIN; 057 } 058 059 @Override 060 public int hashCode() { 061 return Arrays.deepHashCode(this.states); 062 } 063 064 @Override 065 public boolean equals(Object obj) { 066 if (obj == null) { 067 return false; 068 } 069 if (getClass() != obj.getClass()) { 070 return false; 071 } 072 final StyleCache other = (StyleCache) obj; 073 return Arrays.deepEquals(this.states, other.states); 074 } 075 076 /** 077 * Like String.intern() (reduce memory consumption). 078 * StyleCache must not be changed after it has been added to the intern pool. 079 * @return style cache 080 */ 081 private StyleCache intern() { 082 return internPool.putUnique(this); 083 } 084 085 /** 086 * Get the size of the intern pool. Only for tests! 087 * @return size of the intern pool 088 */ 089 public static int getInternPoolSize() { 090 return internPool.size(); 091 } 092}