blob: 6023eea89f706356a3e63b1ad8a8da3261e4b1d1 [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.util.containers;
import com.intellij.util.text.StringFactory;
import java.util.ArrayList;
public class CharTrie {
private ArrayList<Node> myAllNodes;
private static class Node {
private final char myChar;
private final int myParent;
private IntArrayList myChildren;
Node(int parent, char c) {
myChar = c;
myParent = parent;
}
}
public CharTrie() {
init();
}
private void init() {
myAllNodes = new ArrayList<Node>();
final Node root = new Node(-1, (char)0);
myAllNodes.add(root);
}
public int size() {
return myAllNodes.size();
}
/**
* Returns reversed string by unique hash code.
*/
public String getReversedString(int hashCode) {
return StringFactory.createShared(getReversedChars(hashCode));
}
public String getString(int hashCode) {
return StringFactory.createShared(getChars(hashCode));
}
public int getHashCode(char[] chars) {
return getHashCode(chars, 0, chars.length);
}
public int getHashCode(char[] chars, int offset, int length) {
int index = 0;
for (int i = offset; i < offset + length; i++) {
index = getSubNode(index, chars[i], true);
}
return index;
}
public int getHashCode(CharSequence seq) {
int index = 0;
final int l = seq.length();
for (int i = 0; i < l; i++) {
index = getSubNode(index, seq.charAt(i), true);
}
return index;
}
public long getMaximumMatch(CharSequence seq, int offset, int length) {
int index = 0;
int resultingLength = 0;
while (length-- > 0) {
int nextIndex = findSubNode(index, seq.charAt(offset++));
if (nextIndex == 0) {
break;
}
index = nextIndex;
resultingLength++;
}
return index + (((long)resultingLength) << 32);
}
public char[] getChars(int hashCode) {
int length = 0;
int run = hashCode;
while (run > 0) {
final CharTrie.Node node = myAllNodes.get(run);
length++;
run = node.myParent;
}
char[] result = new char[length];
run = hashCode;
for (int i = 0; i < length; i++) {
assert run > 0;
final CharTrie.Node node = myAllNodes.get(run);
result[length - i - 1] = node.myChar;
run = node.myParent;
}
return result;
}
public int getHashCodeForReversedChars(char[] chars) {
return getHashCodeForReversedChars(chars, chars.length - 1, chars.length);
}
public int getHashCodeForReversedChars(char[] chars, int offset, int length) {
int index = 0;
while (length-- > 0) {
index = getSubNode(index, chars[offset--], true);
}
return index;
}
public char[] getReversedChars(final int hashCode) {
int length = 0;
int run = hashCode;
while (run > 0) {
final CharTrie.Node node = myAllNodes.get(run);
length++;
run = node.myParent;
}
char[] result = new char[length];
run = hashCode;
for (int i = 0; i < length; i++) {
assert run > 0;
final CharTrie.Node node = myAllNodes.get(run);
result[i] = node.myChar;
run = node.myParent;
}
return result;
}
public int findSubNode(int parentIndex, char c) {
return getSubNode(parentIndex, c, false);
}
private int getSubNode(int parentIndex, char c, boolean createIfNotExists) {
CharTrie.Node parentNode = myAllNodes.get(parentIndex);
if (parentNode.myChildren == null) {
if (!createIfNotExists) {
return 0;
}
parentNode.myChildren = new IntArrayList(1);
}
IntArrayList children = parentNode.myChildren;
int left = 0;
int right = children.size() - 1;
while (left <= right) {
int middle = (left + right) >> 1;
int index = children.get(middle);
CharTrie.Node node = myAllNodes.get(index);
int comp = node.myChar - c;
if (comp == 0) {
return index;
}
if (comp < 0) {
left = middle + 1;
}
else {
right = middle - 1;
}
}
if (!createIfNotExists) {
return 0;
}
int index = myAllNodes.size();
children.add(left, index);
myAllNodes.add(new CharTrie.Node(parentIndex, c));
return index;
}
public void clear() {
init();
}
}