blob: 3480da1c3110c467f441143a121db8d59439e947 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2007 QNX Software Systems and others.
* 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
*
* Contributors:
* QNX - Initial API and implementation
* Andrew Ferguson (Symbian)
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.rephraserengine.internal.db.org.eclipse.cdt.internal.core.pdom.db;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.rephraserengine.internal.db.org.eclipse.cdt.core.CCorePlugin;
/**
* This is for strings that fit inside a single chunk.
*
* @author Doug Schaefer
*/
public class ShortString implements IString {
private final Database db;
private final int record;
private static final int LENGTH = 0;
private static final int CHARS = 4;
public static final int MAX_LENGTH = (Database.MAX_SIZE - CHARS) / 2;
public ShortString(Database db, int offset) {
this.db = db;
this.record = offset;
}
public ShortString(Database db, char[] chars) throws CoreException {
this.db = db;
this.record = db.malloc(CHARS + chars.length * 2);
Chunk chunk = db.getChunk(record);
chunk.putInt(record + LENGTH, (char)chars.length);
int n = chars.length;
int p = record + CHARS;
for (int i = 0; i < n; ++i) {
chunk.putChar(p, chars[i]);
p += 2;
}
}
public ShortString(Database db, String string) throws CoreException {
this.db = db;
this.record = db.malloc(CHARS + string.length() * 2);
Chunk chunk = db.getChunk(record);
chunk.putInt(record + LENGTH, string.length());
int n = string.length();
int p = record + CHARS;
for (int i = 0; i < n; ++i) {
chunk.putChar(p, string.charAt(i));
p += 2;
}
}
public int getRecord() {
return record;
}
public void delete() throws CoreException {
db.free(record);
}
public char[] getChars() throws CoreException {
Chunk chunk = db.getChunk(record);
int length = chunk.getInt(record + LENGTH);
char[] chars = new char[length];
chunk.getCharArray(record+CHARS, chars);
return chars;
}
public String getString() throws CoreException {
return new String(getChars());
}
public boolean equals(Object obj) {
if (obj == this)
return true;
try {
if (obj instanceof ShortString) {
ShortString string = (ShortString)obj;
if (db == string.db && record == string.record)
return true;
Chunk chunk1 = db.getChunk(record);
Chunk chunk2 = string.db.getChunk(string.record);
int n1 = chunk1.getInt(record);
int n2 = chunk2.getInt(string.record);
if (n1 != n2)
return false;
int p1 = record + CHARS;
int p2 = string.record + CHARS;
for (int i = 0; i < n1; ++i) {
if (chunk1.getChar(p1) != chunk2.getChar(p2))
return false;
p1 += 2;
p2 += 2;
}
return true;
} else if (obj instanceof char[]) {
char[] chars = (char[])obj;
Chunk chunk = db.getChunk(record);
// Make sure size is the same
int n = chunk.getInt(record);
if (n != chars.length)
return false;
// Check each character
int p = record + CHARS;
for (int i = 0; i < n; ++i) {
if (chunk.getChar(p) != chars[i])
return false;
p += 2;
}
return true;
} else if (obj instanceof String) {
String string = (String)obj;
Chunk chunk = db.getChunk(record);
// Make sure size is the same
int n = chunk.getInt(record);
if (n != string.length())
return false;
// Check each character
int p = record + CHARS;
for (int i = 0; i < n; ++i) {
if (chunk.getChar(p) != string.charAt(i))
return false;
p += 2;
}
return true;
}
} catch (CoreException e) {
CCorePlugin.log(e);
}
return false;
}
public int hashCode() {
// Custom hash code function to allow DBStrings in hashmaps.
return record;
}
public int compare(char[] other, boolean caseSensitive) throws CoreException {
Chunk chunk = db.getChunk(record);
int i1 = record + CHARS;
int i2 = 0;
int n1 = i1 + chunk.getInt(record + LENGTH) * 2;
int n2 = other.length;
while (i1 < n1 && i2 < n2) {
int cmp= compareChars(chunk.getChar(i1), other[i2], caseSensitive);
if(cmp!=0)
return cmp;
i1 += 2;
++i2;
}
if (i1 == n1 && i2 != n2)
return -1;
else if (i2 == n2 && i1 != n1)
return 1;
else
return 0;
}
public int compare(IString string, boolean caseSensitive) throws CoreException {
if (string instanceof ShortString)
return compare((ShortString)string, caseSensitive);
else if (string instanceof LongString)
return - ((LongString)string).compare(this, caseSensitive);
else
throw new IllegalArgumentException();
}
public int compare(ShortString other, boolean caseSensitive) throws CoreException {
Chunk chunk1 = db.getChunk(record);
Chunk chunk2 = other.db.getChunk(other.record);
int i1 = record + CHARS;
int i2 = other.record + CHARS;
int n1 = i1 + chunk1.getInt(record + LENGTH) * 2;
int n2 = i2 + chunk2.getInt(other.record + LENGTH) * 2;
while (i1 < n1 && i2 < n2) {
int cmp= compareChars(chunk1.getChar(i1), chunk2.getChar(i2), caseSensitive);
if(cmp!=0)
return cmp;
i1 += 2;
i2 += 2;
}
if (i1 == n1 && i2 != n2)
return -1;
else if (i2 == n2 && i1 != n1)
return 1;
else
return 0;
}
public int compare(String other, boolean caseSensitive) throws CoreException {
Chunk chunk = db.getChunk(record);
int i1 = record + CHARS;
int i2 = 0;
int n1 = i1 + chunk.getInt(record + LENGTH) * 2;
int n2 = other.length();
while (i1 < n1 && i2 < n2) {
int cmp= compareChars(chunk.getChar(i1), other.charAt(i2), caseSensitive);
if(cmp!=0)
return cmp;
i1 += 2;
++i2;
}
if (i1 == n1 && i2 != n2)
return -1;
else if (i2 == n2 && i1 != n1)
return 1;
else
return 0;
}
public int compareCompatibleWithIgnoreCase(IString string) throws CoreException {
if (string instanceof ShortString)
return compareCompatibleWithIgnoreCase((ShortString)string);
else if (string instanceof LongString)
return - ((LongString)string).compareCompatibleWithIgnoreCase(this);
else
throw new IllegalArgumentException();
}
public int compareCompatibleWithIgnoreCase(ShortString other) throws CoreException {
Chunk chunk1 = db.getChunk(record);
Chunk chunk2 = other.db.getChunk(other.record);
int i1 = record + CHARS;
int i2 = other.record + CHARS;
int n1 = i1 + chunk1.getInt(record + LENGTH) * 2;
int n2 = i2 + chunk2.getInt(other.record + LENGTH) * 2;
int sensitiveCmp= 0;
while (i1 < n1 && i2 < n2) {
final char c1= chunk1.getChar(i1);
final char c2= chunk2.getChar(i2);
if (c1 != c2) {
int cmp= compareChars(c1, c2, false); // insensitive
if(cmp!=0)
return cmp;
if (sensitiveCmp == 0) {
if (c1 < c2) {
sensitiveCmp= -1;
}
else {
sensitiveCmp= 1;
}
}
}
i1 += 2;
i2 += 2;
}
if (i1 == n1 && i2 != n2)
return -1;
else if (i2 == n2 && i1 != n1)
return 1;
return sensitiveCmp;
}
public int compareCompatibleWithIgnoreCase(char[] chars) throws CoreException {
Chunk chunk1 = db.getChunk(record);
int i1 = record + CHARS;
int i2 = 0;
int n1 = i1 + chunk1.getInt(record + LENGTH) * 2;
int n2 = chars.length;
int sensitiveCmp= 0;
while (i1 < n1 && i2 < n2) {
final char c1= chunk1.getChar(i1);
final char c2= chars[i2];
if (c1 != c2) {
int cmp= compareChars(c1, c2, false); // insensitive
if(cmp!=0)
return cmp;
if (sensitiveCmp == 0) {
if (c1 < c2) {
sensitiveCmp= -1;
}
else {
sensitiveCmp= 1;
}
}
}
i1 += 2;
i2++;
}
if (i1 == n1 && i2 != n2)
return -1;
else if (i2 == n2 && i1 != n1)
return 1;
return sensitiveCmp;
}
public int comparePrefix(char[] other, boolean caseSensitive) throws CoreException {
Chunk chunk = db.getChunk(record);
int i1 = record + CHARS;
int i2 = 0;
int n1 = i1 + chunk.getInt(record + LENGTH) * 2;
int n2 = other.length;
while (i1 < n1 && i2 < n2) {
int cmp= compareChars(chunk.getChar(i1), other[i2], caseSensitive);
if(cmp!=0)
return cmp;
i1 += 2;
++i2;
}
if (i1 == n1 && i2 != n2)
return -1;
else
return 0;
}
public char charAt(int i) throws CoreException {
int ptr = record + CHARS + (i*2);
return db.getChar(ptr);
}
public int getLength() throws CoreException {
return db.getInt(record + LENGTH);
}
/**
* Compare characters case-sensitively, or case-insensitively.
*
* <b>Limitation</b> This only maps the range a-z,A-Z onto each other
* @param a a character
* @param b a character
* @param caseSensitive whether to compare case-sensitively
* @return
* <ul>
* <li>-1 if a < b
* <li>0 if a == b
* <li>1 if a > b
* </ul>
*/
public static int compareChars(char a, char b, boolean caseSensitive) {
if(caseSensitive) {
if (a < b)
return -1;
if (a > b)
return 1;
} else {
if (a != b) {
a= a >= 'a' && a <='z' ? (char) (a - 32) : a;
b= b >= 'a' && b <='z' ? (char) (b - 32) : b;
if (a < b)
return -1;
if (a > b)
return 1;
}
}
return 0;
}
/* TODO - this is more correct than the above implementation, but we need to
* benchmark first.
*
* public static int compareChars(char a, char b, boolean caseSensitive) {
if(caseSensitive) {
if (a < b)
return -1;
if (a > b)
return 1;
} else {
if (a != b) {
a = Character.toUpperCase(a);
b = Character.toUpperCase(b);
if (a != b) {
a = Character.toLowerCase(a);
b = Character.toLowerCase(b);
if (a != b) {
if (a < b)
return -1;
if (a > b)
return 1;
}
}
}
}
return 0;
}
*/
}