/* This program is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package org.opentripplanner.routing.trippattern;
import com.google.common.collect.Maps;
import java.io.Serializable;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Map;
/**
* Does the same thing as String.intern, but for several different types.
* Java's String.intern uses perm gen space and is broken anyway.
*/
public class Deduplicator implements Serializable {
private static final long serialVersionUID = 20140524L;
private final Map<IntArray, IntArray> canonicalIntArrays = Maps.newHashMap();
private final Map<String, String> canonicalStrings = Maps.newHashMap();
private final Map<BitSet, BitSet> canonicalBitSets = Maps.newHashMap();
private final Map<StringArray, StringArray> canonicalStringArrays = Maps.newHashMap();
/** Free up any memory used by the deduplicator. */
public void reset() {
canonicalIntArrays.clear();
canonicalStrings.clear();
canonicalBitSets.clear();
canonicalStringArrays.clear();
}
/** Used to deduplicate time and stop sequence arrays. The same times may occur in many trips. */
public int[] deduplicateIntArray(int[] original) {
if (original == null) return null;
IntArray intArray = new IntArray(original);
IntArray canonical = canonicalIntArrays.get(intArray);
if (canonical == null) {
canonical = intArray;
canonicalIntArrays.put(canonical, canonical);
}
return canonical.array;
}
public String deduplicateString(String original) {
if (original == null) return null;
String canonical = canonicalStrings.get(original);
if (canonical == null) {
canonical = new String(original.toCharArray()); // Trim String if necessary (older JDKs)
canonicalStrings.put(canonical, canonical);
}
return canonical;
}
public BitSet deduplicateBitSet(BitSet original) {
if (original == null) return null;
BitSet canonical = canonicalBitSets.get(original);
if (canonical == null) {
canonical = original;
canonicalBitSets.put(canonical, canonical);
}
return canonical;
}
public String[] deduplicateStringArray(String[] original) {
if (original == null) return null;
StringArray canonical = canonicalStringArrays.get(new StringArray(original, false));
if (canonical == null) {
canonical = new StringArray(original, true);
canonicalStringArrays.put(canonical, canonical);
}
return canonical.array;
}
/** A wrapper for a primitive int array. This is insane but necessary in Java. */
private class IntArray implements Serializable {
private static final long serialVersionUID = 20140524L;
final int[] array;
IntArray(int[] array) {
this.array = array;
}
@Override
public boolean equals (Object other) {
if (other instanceof IntArray) {
return Arrays.equals(array, ((IntArray) other).array);
} else return false;
}
@Override
public int hashCode() {
return Arrays.hashCode(array);
}
}
/** A wrapper for a String array. Optionally, the individual Strings may be deduplicated too. */
private class StringArray implements Serializable {
private static final long serialVersionUID = 20140524L;
final String[] array;
StringArray(String[] array, boolean deduplicateStrings) {
if (deduplicateStrings) {
this.array = new String[array.length];
for (int i = 0; i < array.length; i++) {
this.array[i] = deduplicateString(array[i]);
}
} else this.array = array;
}
@Override
public boolean equals (Object other) {
if (other instanceof StringArray) {
return Arrays.equals(array, ((StringArray) other).array);
} else return false;
}
@Override
public int hashCode() {
return Arrays.hashCode(array);
}
}
}