1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-23 22:52:11 +02:00

Bug 362442: Considering all expansions for significant macros.

This commit is contained in:
Markus Schorn 2011-12-21 13:56:22 +01:00
parent b680564684
commit 2dea3d4a33
9 changed files with 331 additions and 552 deletions

View file

@ -136,10 +136,12 @@ public class DBTest extends BaseTestCase {
this.key = key;
}
@Override
public int compare(long record) throws CoreException {
return db.getString(db.getRecPtr(record + 4)).compare(key, true);
}
@Override
public boolean visit(long record) throws CoreException {
this.record = record;
return false;
@ -185,6 +187,7 @@ public class DBTest extends BaseTestCase {
};
IBTreeComparator comparator = new IBTreeComparator() {
@Override
public int compare(long record1, long record2) throws CoreException {
IString string1 = db.getString(db.getRecPtr(record1 + 4));
IString string2 = db.getString(db.getRecPtr(record2 + 4));
@ -221,9 +224,10 @@ public class DBTest extends BaseTestCase {
assertCMP("", EQ, "", true);
assertCMP("", EQ, "", false);
doTrials(1000, 1, ShortString.MAX_LENGTH, r, true);
doTrials(1000, 1, ShortString.MAX_LENGTH, r, false);
doTrials(1000, 1, ShortString.MAX_BYTE_LENGTH/2, r, true);
doTrials(1000, 1, ShortString.MAX_BYTE_LENGTH/2, r, false);
doTrials(1000, 1, ShortString.MAX_BYTE_LENGTH, r, true);
doTrials(1000, 1, ShortString.MAX_BYTE_LENGTH, r, false);
assertCMP("a", LT, "b", true);
assertCMP("aa", LT, "ab", true);
@ -239,8 +243,8 @@ public class DBTest extends BaseTestCase {
public void testLongStringComparison() throws CoreException {
Random r= new Random(314159265);
doTrials(100, ShortString.MAX_LENGTH+1, ShortString.MAX_LENGTH*2, r, true);
doTrials(100, ShortString.MAX_LENGTH+1, ShortString.MAX_LENGTH*2, r, false);
doTrials(100, ShortString.MAX_BYTE_LENGTH+1, ShortString.MAX_BYTE_LENGTH*2, r, true);
doTrials(100, ShortString.MAX_BYTE_LENGTH+1, ShortString.MAX_BYTE_LENGTH*2, r, false);
}
private void doTrials(int n, int min, int max, Random r, boolean caseSensitive) throws CoreException {

View file

@ -133,7 +133,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
@Override
public boolean visitValue(char[] macro, char[] value) {
PreprocessorMacro m = fMacroDictionary.get(macro);
return m != null && CharArrayUtils.equals(m.getExpansion(), value);
return m != null && CharArrayUtils.equals(SignificantMacros.shortenValue(m.getExpansion()), value);
}
private boolean isDefined(char[] macro) {
@ -246,7 +246,6 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
private final LocationMap fLocationMap;
private CharArraySet fPreventInclusion= new CharArraySet(0);
private final Lexer fRootLexer;
private final ScannerContext fRootContext;
protected ScannerContext fCurrentContext;
@ -302,8 +301,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
setupMacroDictionary(configuration, info, language);
ILocationCtx ctx= fLocationMap.pushTranslationUnit(filePath, fRootContent.getSource());
fRootLexer= new Lexer(fRootContent.getSource(), fLexOptions, this, this);
fRootContext= fCurrentContext= new ScannerContext(ctx, null, fRootLexer);
Lexer lexer = new Lexer(fRootContent.getSource(), fLexOptions, this, this);
fRootContext= fCurrentContext= new ScannerContext(ctx, null, lexer);
if (info instanceof IExtendedScannerInfo) {
final IExtendedScannerInfo einfo= (IExtendedScannerInfo) info;
fPreIncludedFiles= new String[][] { einfo.getMacroFiles(), einfo.getIncludeFiles() };
@ -346,11 +345,11 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
@Override
public void setContentAssistMode(int offset) {
fContentAssistLimit= offset;
fRootLexer.setContentAssistMode(offset);
fRootContext.getLexer().setContentAssistMode(offset);
}
public boolean isContentAssistMode() {
return fRootLexer.isContentAssistMode();
return fRootContext.getLexer().isContentAssistMode();
}
@Override
@ -469,7 +468,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
InternalFileContent content= fFileContentProvider.getContentForContextToHeaderGap(location,
fMacroDictionaryFacade);
if (content != null && content.getKind() == InclusionKind.FOUND_IN_INDEX) {
processInclusionFromIndex(0, location, content, false);
processInclusionFromIndex(0, content, false);
}
detectIncludeGuard(location, fRootContent.getSource(), fRootContext);
@ -577,7 +576,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
}
try {
t= internalFetchToken(fRootContext, CHECK_NUMBERS, false);
t= internalFetchToken(fRootContext, CHECK_NUMBERS | REPORT_SIGNIFICANT_MACROS | IGNORE_UNDEFINED_SIGNIFICANT_MACROS, false);
} catch (OffsetLimitReachedException e) {
fHandledCompletion= true;
throw e;
@ -1463,7 +1462,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
} catch (CoreException e) {
}
processInclusionFromIndex(poundOffset, path, fi, true);
processInclusionFromIndex(poundOffset, fi, true);
break;
case USE_SOURCE:
// Will be parsed
@ -1502,7 +1501,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
}
}
private void processInclusionFromIndex(int offset, String path, InternalFileContent fi, boolean updateContext) {
private void processInclusionFromIndex(int offset, InternalFileContent fi, boolean updateContext) {
List<IIndexMacro> mdefs= fi.getMacroDefinitions();
for (IIndexMacro macro : mdefs) {
addMacroDefinition(macro);

View file

@ -337,7 +337,9 @@ final class ScannerContext {
public void significantMacro(IMacroBinding macro) {
final char[] macroName= macro.getNameCharArray();
if (fInternalModifications != null && !fInternalModifications.containsKey(macroName)) {
fSignificantMacros.put(macroName, macro.getExpansion());
final char[] expansion = macro.getExpansion();
if (expansion != null)
fSignificantMacros.put(macroName, SignificantMacros.shortenValue(expansion));
}
}
@ -398,18 +400,21 @@ final class ScannerContext {
return;
sm.accept(new ISignificantMacros.IVisitor() {
@Override
public boolean visitValue(char[] macro, char[] value) {
if (!fInternalModifications.containsKey(macro)) {
fSignificantMacros.put(macro, value);
}
return true;
}
@Override
public boolean visitUndefined(char[] macro) {
if (!fInternalModifications.containsKey(macro)) {
fSignificantMacros.put(macro, SignificantMacros.UNDEFINED);
}
return true;
}
@Override
public boolean visitDefined(char[] macro) {
if (!fInternalModifications.containsKey(macro)) {
fSignificantMacros.put(macro, SignificantMacros.DEFINED);

View file

@ -28,11 +28,10 @@ import org.eclipse.cdt.core.parser.util.CharArrayUtils;
* A <code>null</code> string is encoded as a single comma.
*/
public class SignificantMacros implements ISignificantMacros {
public static final char[] UNDEFINED = {};
public static final char[] DEFINED = {};
private static final int ENCODED_UNDEFINED = Character.MAX_VALUE;
private static final int ENCODED_DEFINED = Character.MAX_VALUE-1;
public static final char[] DEFINED = {0};
public static final char[] UNDEFINED = {1};
private static final Comparator<Object> SORTER = new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return CharArrayUtils.compare((char[])o1, (char[])o2);
}
@ -58,13 +57,7 @@ public class SignificantMacros implements ISignificantMacros {
char[] name= (char[]) key;
char[] value= sigMacros.get(name);
buffer.append((char) name.length).append(name);
if (value == DEFINED) {
buffer.append((char) ENCODED_DEFINED);
} else if (value == UNDEFINED) {
buffer.append((char) ENCODED_UNDEFINED);
} else {
buffer.append((char) value.length).append(value);
}
buffer.append((char) value.length).append(value);
}
int len= buffer.length();
char[] result= new char[len];
@ -93,6 +86,7 @@ public class SignificantMacros implements ISignificantMacros {
&& CharArrayUtils.equals(fEncoded, ((SignificantMacros) obj).fEncoded);
}
@Override
public boolean accept(IVisitor visitor) {
final char[] encoded = fEncoded;
final int len = encoded.length;
@ -102,28 +96,27 @@ public class SignificantMacros implements ISignificantMacros {
int v= i + len1;
if (v >= len)
break;
final int len2 = encoded[v++];
if (v+len2 > len)
break;
char[] macro= extract(encoded, i, len1);
final int len2 = encoded[v++];
switch(len2) {
case ENCODED_UNDEFINED:
i= v;
if (!visitor.visitUndefined(macro))
return false;
break;
case ENCODED_DEFINED:
i= v;
if (!visitor.visitDefined(macro))
return false;
break;
default:
i= v+len2;
if (i > len)
break;
if (!visitor.visitValue(macro, extract(encoded, v, len2)))
return false;
break;
}
i= v+len2;
if (len2 == 1) {
if (encoded[v] == UNDEFINED[0]) {
if (!visitor.visitUndefined(macro))
return false;
continue;
}
if (encoded[v] == DEFINED[0]) {
if (!visitor.visitDefined(macro))
return false;
continue;
}
}
final char[] value = extract(encoded, v, len2);
if (!visitor.visitValue(macro, value))
return false;
}
return true;
}
@ -134,6 +127,7 @@ public class SignificantMacros implements ISignificantMacros {
return value;
}
@Override
public char[] encode() {
return fEncoded;
}
@ -147,14 +141,17 @@ public class SignificantMacros implements ISignificantMacros {
final StringBuilder buf= new StringBuilder();
buf.append('{');
accept(new IVisitor() {
@Override
public boolean visitValue(char[] macro, char[] value) {
buf.append(macro).append('=').append(value).append(',');
return true;
}
@Override
public boolean visitUndefined(char[] macro) {
buf.append(macro).append('=').append("null,");
return true;
}
@Override
public boolean visitDefined(char[] macro) {
buf.append(macro).append('=').append("*,");
return true;
@ -166,4 +163,19 @@ public class SignificantMacros implements ISignificantMacros {
buf.append('}');
return buf.toString();
}
public static char[] shortenValue(char[] expansion) {
if (expansion.length <= 16)
return expansion;
char[] result= new char[16];
System.arraycopy(expansion, 0, result, 0, 8);
StreamHasher hasher= new StreamHasher();
hasher.addChunk(expansion);
long hash= hasher.computeHash();
for(int i= 0; i<8; i++) {
result[8+i]= (char) (hash & 0xff);
hash= hash >> 1;
}
return result;
}
}

View file

@ -212,10 +212,11 @@ public class PDOM extends PlatformObject implements IPDOM {
* 120.0 - Enumerators in global index, bug 356235
* 120.1 - Specializations of using declarations, bug 357293.
* 121.0 - Multiple variants of included header file, bug 197989.
* 122.0 - Compacting strings
*/
private static final int MIN_SUPPORTED_VERSION= version(121, 0);
private static final int MAX_SUPPORTED_VERSION= version(121, Short.MAX_VALUE);
private static final int DEFAULT_VERSION = version(121, 0);
private static final int MIN_SUPPORTED_VERSION= version(122, 0);
private static final int MAX_SUPPORTED_VERSION= version(122, Short.MAX_VALUE);
private static final int DEFAULT_VERSION = version(122, 0);
private static int version(int major, int minor) {
return (major << 16) + minor;

View file

@ -252,17 +252,47 @@ final class Chunk {
fBuffer[++idx]= (byte)(value);
}
public void putChars(final long offset, char[] chars, int start, int len) {
assert fLocked;
fDirty= true;
int idx= recPtrToIndex(offset)-1;
final int end= start+len;
for (int i = start; i < end; i++) {
char value= chars[i];
fBuffer[++idx]= (byte)(value >> 8);
fBuffer[++idx]= (byte)(value);
}
}
public void putCharsAsBytes(final long offset, char[] chars, int start, int len) {
assert fLocked;
fDirty= true;
int idx= recPtrToIndex(offset)-1;
final int end= start+len;
for (int i = start; i < end; i++) {
char value= chars[i];
fBuffer[++idx]= (byte)(value);
}
}
public char getChar(final long offset) {
int idx= recPtrToIndex( offset );
return (char) (((fBuffer[idx] << 8) | (fBuffer[++idx] & 0xff)));
}
public void getCharArray(final long offset, final char[] result) {
public void getChars(final long offset, final char[] result, int start, int len) {
final ByteBuffer buf= ByteBuffer.wrap(fBuffer);
buf.position(recPtrToIndex( offset ));
buf.asCharBuffer().get(result);
buf.asCharBuffer().get(result, start, len);
}
public void getCharsFromBytes(final long offset, final char[] result, int start, int len) {
final int pos = recPtrToIndex(offset);
for (int i = 0; i < len; i++) {
result[start+i] = (char) (fBuffer[pos+i] & 0xff);
}
}
void clear(final long offset, final int length) {
assert fLocked;
fDirty= true;

View file

@ -530,25 +530,42 @@ public class Database {
}
public IString newString(String string) throws CoreException {
if (string.length() > ShortString.MAX_LENGTH)
return new LongString(this, string);
else
return new ShortString(this, string);
return newString(string.toCharArray());
}
public IString newString(char[] chars) throws CoreException {
if (chars.length > ShortString.MAX_LENGTH)
return new LongString(this, chars);
int len= chars.length;
int bytelen;
final boolean useBytes = useBytes(chars);
if (useBytes) {
bytelen= len;
} else {
bytelen= 2*len;
}
if (bytelen > ShortString.MAX_BYTE_LENGTH)
return new LongString(this, chars, useBytes);
else
return new ShortString(this, chars);
return new ShortString(this, chars, useBytes);
}
private boolean useBytes(char[] chars) {
for (char c : chars) {
if ((c & 0xff00) != 0)
return false;
}
return true;
}
public IString getString(long offset) throws CoreException {
int length = getInt(offset);
if (length > ShortString.MAX_LENGTH)
final int l = getInt(offset);
int bytelen= l<0 ? -l : 2*l;
if (bytelen > ShortString.MAX_BYTE_LENGTH) {
return new LongString(this, offset);
else
return new ShortString(this, offset);
}
return new ShortString(this, offset);
}
/**

View file

@ -13,8 +13,6 @@
package org.eclipse.cdt.internal.core.pdom.db;
import java.util.NoSuchElementException;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.core.runtime.CoreException;
@ -48,73 +46,117 @@ public class LongString implements IString {
this.record = record;
}
private interface IWriter {
public void writeChars(int start, int length, long p) throws CoreException;
}
public LongString(Database db, final char[] chars, boolean useBytes) throws CoreException {
final int numChars1 = useBytes ? NUM_CHARS1*2 : NUM_CHARS1;
final int numCharsn = useBytes ? NUM_CHARSN*2 : NUM_CHARSN;
private long createString(int length, IWriter writer) throws CoreException {
// write the first record
long firstRecord = db.malloc(Database.MAX_MALLOC_SIZE);
int start = 0;
db.putInt(firstRecord, length);
writer.writeChars(start, NUM_CHARS1, firstRecord + CHARS1);
this.db = db;
this.record = db.malloc(Database.MAX_MALLOC_SIZE);
// Write the first record
final int length = chars.length;
db.putInt(this.record, useBytes ? -length : length);
Chunk chunk= db.getChunk(this.record);
if (useBytes) {
chunk.putCharsAsBytes(this.record + CHARS1, chars, 0, numChars1);
} else {
chunk.putChars(this.record + CHARS1, chars, 0, numChars1);
}
// write the subsequent records
long lastNext = firstRecord + NEXT1;
start += NUM_CHARS1;
while (length - start > NUM_CHARSN) {
long lastNext = this.record + NEXT1;
int start = numChars1;
while (length-start > numCharsn) {
long nextRecord = db.malloc(Database.MAX_MALLOC_SIZE);
db.putRecPtr(lastNext, nextRecord);
writer.writeChars(start, NUM_CHARSN, nextRecord + CHARSN);
start += NUM_CHARSN;
chunk= db.getChunk(nextRecord);
if (useBytes) {
chunk.putCharsAsBytes(nextRecord + CHARSN, chars, start, numCharsn);
} else {
chunk.putChars(nextRecord + CHARSN, chars, start, numCharsn);
}
start += numCharsn;
lastNext = nextRecord + NEXTN;
}
// Write the final record
length -= start;
long finalRecord = db.malloc(CHARSN + (length) * 2);
db.putRecPtr(lastNext, finalRecord);
writer.writeChars(start, length, finalRecord + CHARSN);
return firstRecord;
}
public LongString(Database db, final String string) throws CoreException {
this.db = db;
this.record = createString(string.length(), new IWriter() {
public void writeChars(int start, int length, long p) throws CoreException {
for (int i = start; i < start + length; ++i) {
LongString.this.db.putChar(p, string.charAt(i));
p += 2;
}
}
});
}
public LongString(Database db, final char[] chars) throws CoreException {
this.db = db;
this.record = createString(chars.length, new IWriter() {
public void writeChars(int start, int length, long p) throws CoreException {
for (int i = start; i < start + length; ++i) {
LongString.this.db.putChar(p, chars[i]);
p += 2;
}
}
});
// Write last record
int remaining= length - start;
long nextRecord = db.malloc(CHARSN + (useBytes ? remaining : remaining*2));
db.putRecPtr(lastNext, nextRecord);
chunk= db.getChunk(nextRecord);
if (useBytes) {
chunk.putCharsAsBytes(nextRecord + CHARSN, chars, start, remaining);
} else {
chunk.putChars(nextRecord + CHARSN, chars, start, remaining);
}
}
@Override
public long getRecord() {
return record;
}
@Override
public char[] getChars() throws CoreException {
int length = db.getInt(record + LENGTH);
final boolean useBytes = length < 0;
int numChars1 = NUM_CHARS1;
int numCharsn = NUM_CHARSN;
if (useBytes) {
length= -length;
numChars1 *= 2;
numCharsn *= 2;
}
final char[] chars = new char[length];
// First record
long p = record;
Chunk chunk= db.getChunk(p);
if (useBytes) {
chunk.getCharsFromBytes(p+CHARS1, chars, 0, numChars1);
} else {
chunk.getChars(p+CHARS1, chars, 0, numChars1);
}
int start= numChars1;
p= record + NEXT1;
// Other records
while (start < length) {
p = db.getRecPtr(p);
int partLen= Math.min(length-start, numCharsn);
chunk= db.getChunk(p);
if (useBytes) {
chunk.getCharsFromBytes(p+CHARSN, chars, start, partLen);
} else {
chunk.getChars(p+CHARSN, chars, start, partLen);
}
start+= partLen;
p=p+NEXTN;
}
return chars;
}
@Override
public void delete() throws CoreException {
int length = db.getInt(record + LENGTH) - NUM_CHARS1;
int length = db.getInt(record + LENGTH);
final boolean useBytes = length < 0;
int numChars1 = NUM_CHARS1;
int numCharsn = NUM_CHARSN;
if (useBytes) {
length= -length;
numChars1 *= 2;
numCharsn *= 2;
}
long nextRecord = db.getRecPtr(record + NEXT1);
db.free(record);
length-= numChars1;
// Middle records
while (length > NUM_CHARSN) {
length -= NUM_CHARSN;
while (length > numCharsn) {
length -= numCharsn;
long nextnext = db.getRecPtr(nextRecord + NEXTN);
db.free(nextRecord);
nextRecord = nextnext;
@ -147,19 +189,6 @@ public class LongString implements IString {
return false;
}
private class HashCodeComputer implements IReader {
private int fHashcode= 0;
public int getHashcode() {
return fHashcode;
}
public void appendChar(char c) {
fHashcode = 31*fHashcode + c;
}
}
/**
* Compatible with {@link String#hashCode()}
*/
@ -167,224 +196,53 @@ public class LongString implements IString {
public int hashCode() {
int h = hash;
if (h == 0) {
HashCodeComputer hcc;
char chars[];
try {
int length = db.getInt(record + LENGTH);
hcc = new HashCodeComputer();
readChars(length, hcc);
h= hcc.getHashcode();
hash = h;
chars = getChars();
final int len = chars.length;
for (int i = 0; i < len; i++) {
h = 31*h + chars[i];
}
} catch (CoreException e) {
}
hash = h;
}
return h;
}
@Override
public int compare(IString string, boolean caseSensitive) throws CoreException {
if (string instanceof LongString)
return compare((LongString)string, caseSensitive);
else if (string instanceof ShortString)
return compare((ShortString)string, caseSensitive);
else
throw new IllegalArgumentException();
return ShortString.compare(getChars(), string.getChars(), caseSensitive);
}
public int compare(char[] other, boolean caseSensitive) throws CoreException {
CharIterator i1 = new CharIterator();
int i2 = 0;
int n2 = other.length;
while (i1.hasNext() && i2 < n2) {
int cmp= ShortString.compareChars(i1.next(), other[i2], caseSensitive);
if(cmp!=0)
return cmp;
++i2;
}
if (!i1.hasNext() && i2 != n2)
return -1;
else if (i2 == n2 && i1.hasNext())
return 1;
else
return 0;
}
public int compare(ShortString other, boolean caseSensitive) throws CoreException {
CharIterator i1 = new CharIterator();
int index2 = 0;
int length2 = other.getLength();
while (i1.hasNext() && index2<length2) {
int cmp= ShortString.compareChars(i1.next(), other.charAt(index2), caseSensitive);
if(cmp!=0)
return cmp;
index2++;
}
if (!i1.hasNext() && index2 != length2)
return -1;
else if (index2 == length2 && i1.hasNext())
return 1;
else
return 0;
}
public int compare(LongString other, boolean caseSensitive) throws CoreException {
CharIterator i1 = new CharIterator();
CharIterator i2 = other.new CharIterator();
while (i1.hasNext() && i2.hasNext()) {
int cmp= ShortString.compareChars(i1.next(), i2.next(), caseSensitive);
if(cmp!=0)
return cmp;
}
if (!i1.hasNext() && i2.hasNext())
return -1;
else if (!i2.hasNext() && i1.hasNext())
return 1;
else
return 0;
}
@Override
public int compare(String other, boolean caseSensitive) throws CoreException {
CharIterator i1 = new CharIterator();
int i2 = 0;
int n2 = other.length();
while (i1.hasNext() && i2 < n2) {
int cmp= ShortString.compareChars(i1.next(), other.charAt(i2), caseSensitive);
if(cmp!=0)
return cmp;
++i2;
}
if (!i1.hasNext() && i2 != n2)
return -1;
else if (i2 == n2 && i1.hasNext())
return 1;
else
return 0;
return ShortString.compare(getChars(), other.toCharArray(), caseSensitive);
}
public int comparePrefix(char[] other, boolean caseSensitive) throws CoreException {
CharIterator i1 = new CharIterator();
int i2 = 0;
int n2 = other.length;
while (i1.hasNext() && i2 < n2) {
int cmp= ShortString.compareChars(i1.next(), other[i2], caseSensitive);
if(cmp!=0)
return cmp;
++i2;
}
if (!i1.hasNext() && i2 != n2)
return -1;
else
return 0;
}
private interface IReader {
public void appendChar(char c);
@Override
public int compare(char[] other, boolean caseSensitive) throws CoreException {
return ShortString.compare(getChars(), other, caseSensitive);
}
private void readChars(int length, IReader reader) throws CoreException {
// First record
long p = record + CHARS1;
for (int i = 0; i < NUM_CHARS1; ++i) {
reader.appendChar(db.getChar(p));
p += 2;
}
length -= NUM_CHARS1;
long nextRecord = db.getRecPtr(record + NEXT1);
// Middle records
while (length > NUM_CHARSN) {
p = nextRecord + CHARSN;
for (int i = 0; i < NUM_CHARSN; ++i) {
reader.appendChar(db.getChar(p));
p += 2;
}
length -= NUM_CHARSN;
nextRecord = db.getRecPtr(nextRecord + NEXTN);
}
// Last record
p = nextRecord + CHARSN;
for (int i = 0; i < length; ++i) {
reader.appendChar(db.getChar(p));
p += 2;
}
}
/**
* Convenience class for sequential access to LongString characters
*/
private class CharIterator {
long p;
int count;
int length;
public CharIterator() throws CoreException {
p = record + CHARS1;
length = db.getInt(record + LENGTH);
}
public char next() throws CoreException {
char result = db.getChar(p);
p += 2;
count++;
if(count>length) {
throw new NoSuchElementException();
}
if(count == NUM_CHARS1) {
p = db.getRecPtr(record + NEXT1) + CHARSN;
}
if(count > NUM_CHARS1 && ((count-NUM_CHARS1) % NUM_CHARSN)==0) {
p = db.getRecPtr(p-(NUM_CHARSN*2)-4) + CHARSN;
}
return result;
}
public boolean hasNext() {
return count<length;
}
}
public char[] getChars() throws CoreException {
int length = db.getInt(record + LENGTH);
final char[] chars = new char[length];
readChars(length, new IReader() {
int cp = 0;
public void appendChar(char c) {
chars[cp++] = c;
}
});
return chars;
}
public String getString() throws CoreException {
int length = db.getInt(record + LENGTH);
final StringBuilder buffer = new StringBuilder(length);
readChars(length, new IReader() {
public void appendChar(char c) {
buffer.append(c);
}
});
return buffer.toString();
}
@Override
public int compareCompatibleWithIgnoreCase(IString string) throws CoreException {
int cmp= compare(string, false);
return cmp==0 ? compare(string, true) : cmp;
return ShortString.compareCompatibleWithIgnoreCase(getChars(), string.getChars());
}
@Override
public int comparePrefix(char[] other, boolean caseSensitive) throws CoreException {
return ShortString.comparePrefix(getChars(), other, caseSensitive);
}
public int compareCompatibleWithIgnoreCase(char[] chars) throws CoreException {
int cmp= compare(chars, false);
return cmp==0 ? compare(chars, true) : cmp;
@Override
public String getString() throws CoreException {
return new String(getChars());
}
@Override
public int compareCompatibleWithIgnoreCase(char[] other) throws CoreException {
return ShortString.compareCompatibleWithIgnoreCase(getChars(), other);
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2009 QNX Software Systems and others.
* Copyright (c) 2006, 2011 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
@ -13,6 +13,7 @@
package org.eclipse.cdt.internal.core.pdom.db;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.core.runtime.CoreException;
/**
@ -28,57 +29,53 @@ public class ShortString implements IString {
private static final int LENGTH = 0;
private static final int CHARS = 4;
public static final int MAX_LENGTH = (Database.MAX_MALLOC_SIZE - CHARS) / 2;
public static final int MAX_BYTE_LENGTH = Database.MAX_MALLOC_SIZE - CHARS;
public ShortString(Database db, long offset) {
this.db = db;
this.record = offset;
}
public ShortString(Database db, char[] chars) throws CoreException {
public ShortString(Database db, char[] chars, boolean useBytes) throws CoreException {
final int n = chars.length;
this.db = db;
this.record = db.malloc(CHARS + chars.length * 2);
this.record = db.malloc(CHARS + (useBytes ? n : 2*n));
Chunk chunk = db.getChunk(record);
chunk.putInt(record + LENGTH, (char)chars.length);
int n = chars.length;
chunk.putInt(record + LENGTH, useBytes ? -n : n);
long 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();
long p = record + CHARS;
for (int i = 0; i < n; ++i) {
chunk.putChar(p, string.charAt(i));
p += 2;
if (useBytes) {
chunk.putCharsAsBytes(p, chars, 0, n);
} else {
chunk.putChars(p, chars, 0, n);
}
}
@Override
public long getRecord() {
return record;
}
@Override
public void delete() throws CoreException {
db.free(record);
}
@Override
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);
final Chunk chunk = db.getChunk(record);
final int l = chunk.getInt(record + LENGTH);
final int length = Math.abs(l);
final char[] chars = new char[length];
if (l < 0) {
chunk.getCharsFromBytes(record + CHARS, chars, 0, length);
} else {
chunk.getChars(record + CHARS, chars, 0, length);
}
return chars;
}
@Override
public String getString() throws CoreException {
return new String(getChars());
}
@ -102,49 +99,22 @@ public class ShortString implements IString {
if (n1 != n2)
return false;
long p1 = record + CHARS;
long 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[]) {
return CharArrayUtils.equals(getChars(), string.getChars());
}
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)
if (getLength() != chars.length)
return false;
// Check each character
long p = record + CHARS;
for (int i = 0; i < n; ++i) {
if (chunk.getChar(p) != chars[i])
return false;
p += 2;
}
return true;
return CharArrayUtils.equals(getChars(), chars);
} 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())
if (getLength() != string.length())
return false;
// Check each character
long p = record + CHARS;
for (int i = 0; i < n; ++i) {
if (chunk.getChar(p) != string.charAt(i))
return false;
p += 2;
}
return true;
return CharArrayUtils.equals(getChars(), string.toCharArray());
}
} catch (CoreException e) {
CCorePlugin.log(e);
@ -173,112 +143,48 @@ public class ShortString implements IString {
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 CoreException {
Chunk chunk = db.getChunk(record);
long i1 = record + CHARS;
int i2 = 0;
long 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;
return compare(getChars(), other, caseSensitive);
}
@Override
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();
return compare(getChars(), string.getChars(), caseSensitive);
}
public int compare(ShortString other, boolean caseSensitive) throws CoreException {
Chunk chunk1 = db.getChunk(record);
Chunk chunk2 = other.db.getChunk(other.record);
long i1 = record + CHARS;
long i2 = other.record + CHARS;
long n1 = i1 + chunk1.getInt(record + LENGTH) * 2;
long 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;
}
@Override
public int compare(String other, boolean caseSensitive) throws CoreException {
Chunk chunk = db.getChunk(record);
long i1 = record + CHARS;
int i2 = 0;
long 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;
return compare(getChars(), other.toCharArray(), caseSensitive);
}
@Override
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();
return compareCompatibleWithIgnoreCase(string.getChars());
}
public int compareCompatibleWithIgnoreCase(ShortString other) throws CoreException {
Chunk chunk1 = db.getChunk(record);
Chunk chunk2 = other.db.getChunk(other.record);
@Override
public int compareCompatibleWithIgnoreCase(char[] other) throws CoreException {
return compareCompatibleWithIgnoreCase(getChars(), other);
}
long i1 = record + CHARS;
long i2 = other.record + CHARS;
long n1 = i1 + chunk1.getInt(record + LENGTH) * 2;
long n2 = i2 + chunk2.getInt(other.record + LENGTH) * 2;
public static int compareCompatibleWithIgnoreCase(final char[] chars, char[] other) {
final int n = Math.min(chars.length, other.length);
int sensitiveCmp= 0;
while (i1 < n1 && i2 < n2) {
final char c1= chunk1.getChar(i1);
final char c2= chunk2.getChar(i2);
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)
@ -287,93 +193,40 @@ public class ShortString implements IString {
if (sensitiveCmp == 0) {
if (c1 < c2) {
sensitiveCmp= -1;
}
else {
} else {
sensitiveCmp= 1;
}
}
}
i1 += 2;
i2 += 2;
}
int cmp= chars.length - other.length;
if (cmp != 0)
return cmp;
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);
long i1 = record + CHARS;
int i2 = 0;
long 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;
}
@Override
public int comparePrefix(char[] other, boolean caseSensitive) throws CoreException {
Chunk chunk = db.getChunk(record);
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);
long i1 = record + CHARS;
int i2 = 0;
long 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);
for (int i=0; i<n; i++) {
int cmp= compareChars(chars[i], other[i], caseSensitive);
if (cmp != 0)
return cmp;
i1 += 2;
++i2;
}
if (i1 == n1 && i2 != n2)
if (chars.length < other.length)
return -1;
else
return 0;
return 0;
}
public char charAt(int i) throws CoreException {
long ptr = record + CHARS + (i * 2);
return db.getChar(ptr);
}
public int getLength() throws CoreException {
return db.getInt(record + LENGTH);
public final int getLength() throws CoreException {
return Math.abs(db.getInt(record + LENGTH));
}
/**