/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.cpd; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; public class TokenEntry implements Comparable<TokenEntry> { public static final TokenEntry EOF = new TokenEntry(); private String tokenSrcID; private int beginLine; private int index; private int identifier; private int hashCode; private static final ThreadLocal<Map<String, Integer>> TOKENS = new ThreadLocal<Map<String, Integer>>() { @Override protected Map<String, Integer> initialValue() { return new HashMap<>(); } }; private static final ThreadLocal<AtomicInteger> TOKEN_COUNT = new ThreadLocal<AtomicInteger>() { @Override protected AtomicInteger initialValue() { return new AtomicInteger(0); } }; private TokenEntry() { this.identifier = 0; this.tokenSrcID = "EOFMarker"; } public TokenEntry(String image, String tokenSrcID, int beginLine) { setImage(image); this.tokenSrcID = tokenSrcID; this.beginLine = beginLine; this.index = TOKEN_COUNT.get().getAndIncrement(); } public static TokenEntry getEOF() { TOKEN_COUNT.get().getAndIncrement(); return EOF; } public static void clearImages() { TOKENS.get().clear(); TOKENS.remove(); TOKEN_COUNT.remove(); } /** * Helper class to preserve and restore the current state of the token * entries. */ public static class State { private int tokenCount; private Map<String, Integer> tokens; private List<TokenEntry> entries; public State(List<TokenEntry> entries) { this.tokenCount = TokenEntry.TOKEN_COUNT.get().intValue(); this.tokens = new HashMap<>(TokenEntry.TOKENS.get()); this.entries = new ArrayList<>(entries); } public List<TokenEntry> restore() { TokenEntry.TOKEN_COUNT.get().set(tokenCount); TOKENS.get().clear(); TOKENS.get().putAll(tokens); return entries; } } public String getTokenSrcID() { return tokenSrcID; } public int getBeginLine() { return beginLine; } public int getIdentifier() { return this.identifier; } public int getIndex() { return this.index; } @Override public int hashCode() { return hashCode; } public void setHashCode(int hashCode) { this.hashCode = hashCode; } @Override public boolean equals(Object o) { if (!(o instanceof TokenEntry)) { return false; } TokenEntry other = (TokenEntry) o; return other.hashCode == hashCode; } @Override public int compareTo(TokenEntry other) { return getIndex() - other.getIndex(); } @Override public String toString() { if (this == EOF) { return "EOF"; } for (Map.Entry<String, Integer> e : TOKENS.get().entrySet()) { if (e.getValue().intValue() == identifier) { return e.getKey(); } } return "--unkown--"; } final void setImage(String image) { Integer i = TOKENS.get().get(image); if (i == null) { i = TOKENS.get().size() + 1; TOKENS.get().put(image, i); } this.identifier = i.intValue(); } }