org.aspectj.org.eclipse.jdt.internal.core.nd.db.ShortString Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/*******************************************************************************
* Copyright (c) 2006, 2016 QNX Software Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* QNX - Initial API and implementation
* Andrew Ferguson (Symbian)
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.core.nd.db;
import org.aspectj.org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
/**
* This is for strings that fit inside a single chunk.
*/
public class ShortString implements IString {
private final Database db;
private final long record;
private int hash;
private static final int LENGTH = 0;
private static final int CHARS = 4;
public static final int MAX_BYTE_LENGTH = Database.MAX_SINGLE_BLOCK_MALLOC_SIZE - CHARS;
public ShortString(Database db, long offset) {
this.db = db;
this.record = offset;
}
public ShortString(Database db, char[] chars, boolean useBytes) throws IndexException {
final int n = chars.length;
this.db = db;
this.record = db.malloc(CHARS + (useBytes ? n : 2 * n), Database.POOL_STRING_SHORT);
Chunk chunk = db.getChunk(this.record);
chunk.putInt(this.record + LENGTH, useBytes ? -n : n);
long p = this.record + CHARS;
if (useBytes) {
chunk.putCharsAsBytes(p, chars, 0, n);
} else {
chunk.putChars(p, chars, 0, n);
}
}
@Override
public long getRecord() {
return this.record;
}
@Override
public void delete() throws IndexException {
this.db.free(this.record, Database.POOL_STRING_SHORT);
}
@Override
public char[] getChars() throws IndexException {
final Chunk chunk = this.db.getChunk(this.record);
final int l = chunk.getInt(this.record + LENGTH);
final int length = Math.abs(l);
final char[] chars = new char[length];
if (l < 0) {
chunk.getCharsFromBytes(this.record + CHARS, chars, 0, length);
} else {
chunk.getChars(this.record + CHARS, chars, 0, length);
}
return chars;
}
@Override
public String getString() throws IndexException {
return new String(getChars());
}
@Override
public boolean equals(Object obj) {
if (obj == this)
return true;
try {
if (obj instanceof ShortString) {
ShortString string = (ShortString)obj;
if (this.db == string.db && this.record == string.record)
return true;
Chunk chunk1 = this.db.getChunk(this.record);
Chunk chunk2 = string.db.getChunk(string.record);
int n1 = chunk1.getInt(this.record);
int n2 = chunk2.getInt(string.record);
if (n1 != n2)
return false;
return CharArrayUtils.equals(getChars(), string.getChars());
}
if (obj instanceof char[]) {
char[] chars = (char[])obj;
// Make sure size is the same
if (length() != chars.length)
return false;
return CharArrayUtils.equals(getChars(), chars);
} else if (obj instanceof String) {
String string = (String)obj;
if (length() != string.length())
return false;
return CharArrayUtils.equals(getChars(), string.toCharArray());
}
} catch (IndexException e) {
Package.log(e);
}
return false;
}
/**
* Compatible with {@link String#hashCode()}
*/
@Override
public int hashCode() {
int h = this.hash;
if (h == 0) {
char chars[];
chars = getChars();
final int len = chars.length;
for (int i = 0; i < len; i++) {
h = 31 * h + chars[i];
}
this.hash = h;
}
return h;
}
public static int compare(final char[] chars, char[] other, boolean caseSensitive) {
final int n = Math.min(chars.length, other.length);
for (int i = 0; i < n; i++) {
int cmp= compareChars(chars[i], other[i], caseSensitive);
if (cmp != 0)
return cmp;
}
return chars.length - other.length;
}
@Override
public int compare(char[] other, boolean caseSensitive) throws IndexException {
return compare(getChars(), other, caseSensitive);
}
@Override
public int compare(IString string, boolean caseSensitive) throws IndexException {
return compare(getChars(), string.getChars(), caseSensitive);
}
@Override
public int compare(String other, boolean caseSensitive) throws IndexException {
return compare(getChars(), other.toCharArray(), caseSensitive);
}
@Override
public int compareCompatibleWithIgnoreCase(IString string) throws IndexException {
return compareCompatibleWithIgnoreCase(string.getChars());
}
@Override
public int compareCompatibleWithIgnoreCase(char[] other) throws IndexException {
return compareCompatibleWithIgnoreCase(getChars(), other);
}
public static int compareCompatibleWithIgnoreCase(final char[] chars, char[] other) {
final int n = Math.min(chars.length, other.length);
int sensitiveCmp= 0;
for (int i = 0; i < n; i++) {
final char c1= chars[i];
final char c2= other[i];
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;
}
}
}
}
int cmp= chars.length - other.length;
if (cmp != 0)
return cmp;
return sensitiveCmp;
}
@Override
public int comparePrefix(char[] other, boolean caseSensitive) throws IndexException {
return comparePrefix(getChars(), other, caseSensitive);
}
public static int comparePrefix(final char[] chars, char[] other, boolean caseSensitive) {
final int n = Math.min(chars.length, other.length);
for (int i = 0; i < n; i++) {
int cmp= compareChars(chars[i], other[i], caseSensitive);
if (cmp != 0)
return cmp;
}
if (chars.length < other.length)
return -1;
return 0;
}
/**
* Compare characters case-sensitively, or case-insensitively.
*
* Limitation 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
*
* - -1 if a < b
*
- 0 if a == b
*
- 1 if a > b
*
*/
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;
}
*/
@Override
public String toString() {
try {
return getString();
} catch (IndexException e) {
return super.toString();
}
}
@Override
public int length() {
return Math.abs(this.db.getInt(this.record + LENGTH));
}
}