/*
* Copyright (c) 2011 Google Inc.
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.google.eclipse.protobuf.ui.util.editor;
import org.apache.log4j.Logger;
import org.eclipse.compare.rangedifferencer.IRangeComparator;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
/**
* Adapted from CDT's {@code org.eclipse.cdt.internal.ui.text.LineSeparator}.
*
* This implementation of <code>IRangeComparator</code> compares lines of a document. The lines are compared using a DJB
* hash function.
*
* @author alruiz@google.com (Alex Ruiz)
*/
class LineComparator implements IRangeComparator {
private static final long UNKNOWN_HASH = Long.MIN_VALUE;
private static Logger logger = Logger.getLogger(LineComparator.class);
private final IDocument document;
private final long[] hashes;
public LineComparator(IDocument document) {
this.document = document;
hashes = new long[document.getNumberOfLines()];
for (int i = 0; i < hashes.length; i++) {
hashes[i] = UNKNOWN_HASH;
}
}
@Override public int getRangeCount() {
return document.getNumberOfLines();
}
@Override public boolean rangesEqual(int thisIndex, IRangeComparator other, int otherIndex) {
try {
return getHash(thisIndex) == ((LineComparator) other).getHash(otherIndex);
} catch (BadLocationException e) {
logger.error(e.getMessage(), e);
return false;
}
}
@Override public boolean skipRangeComparison(int length, int maxLength, IRangeComparator other) {
return false;
}
/**
* Returns the hash of the given line.
* @param line the number of the line in the document to get the hash for.
* @return the hash of the line.
* @throws BadLocationException if the line number is invalid.
*/
private int getHash(int line) throws BadLocationException {
long hash = hashes[line];
if (hash == UNKNOWN_HASH) {
IRegion lineRegion = document.getLineInformation(line);
String lineContents = document.get(lineRegion.getOffset(), lineRegion.getLength());
hash = computeDJBHash(lineContents);
hashes[line] = hash;
}
return (int) hash;
}
/**
* Compute a hash using the DJB hash algorithm.
* @param s the string for which to compute a hash.
* @return the DJB hash value of the {@code String}.
*/
private int computeDJBHash(String s) {
int hash = 5381;
int length = s.length();
for (int i = 0; i < length; i++) {
char ch = s.charAt(i);
hash = (hash << 5) + hash + ch;
}
return hash;
}
}