From 2dea3d4a339d49579b06d13399e66adb03556fd8 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Wed, 21 Dec 2011 13:56:22 +0100 Subject: [PATCH] Bug 362442: Considering all expansions for significant macros. --- .../cdt/internal/pdom/tests/DBTest.java | 14 +- .../core/parser/scanner/CPreprocessor.java | 19 +- .../core/parser/scanner/ScannerContext.java | 7 +- .../parser/scanner/SignificantMacros.java | 74 ++-- .../eclipse/cdt/internal/core/pdom/PDOM.java | 7 +- .../cdt/internal/core/pdom/db/Chunk.java | 36 +- .../cdt/internal/core/pdom/db/Database.java | 39 +- .../cdt/internal/core/pdom/db/LongString.java | 386 ++++++------------ .../internal/core/pdom/db/ShortString.java | 301 ++++---------- 9 files changed, 331 insertions(+), 552 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/DBTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/DBTest.java index 932fc73b827..08275ed495a 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/DBTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/DBTest.java @@ -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 { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java index 0cd5d9e9944..c84bd8ff4da 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java @@ -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 mdefs= fi.getMacroDefinitions(); for (IIndexMacro macro : mdefs) { addMacroDefinition(macro); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ScannerContext.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ScannerContext.java index 256fb07825e..9a059e6f9ad 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ScannerContext.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ScannerContext.java @@ -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); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SignificantMacros.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SignificantMacros.java index a997540fd5b..909b930f61b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SignificantMacros.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/SignificantMacros.java @@ -28,11 +28,10 @@ import org.eclipse.cdt.core.parser.util.CharArrayUtils; * A null 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 SORTER = new Comparator() { + @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; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 3b588970ca5..decb09a25c5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -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; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java index cc366d97fa0..a7402792bfd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java @@ -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; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java index fe34fa1ca35..4c883a97467 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java @@ -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); } /** diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/LongString.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/LongString.java index ebf5eda9383..6b9751836b2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/LongString.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/LongString.java @@ -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 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