package test;
import java.io.*;
import javax.xml.stream.*;
import com.fasterxml.aalto.in.*;
import com.fasterxml.aalto.util.*;
public final class TestPNamePerf
{
final static int INT_A = 'A';
final int mRepCount;
int mTmpChar = 0;
final byte[] mInputBuffer;
final ByteBasedPNameTable mSymbols;
final XmlCharTypes mCharTypes;
int mInputPtr;
int mInputLen;
protected int[] mQuadBuffer = new int[64];
protected char[] mNameBuffer = new char[100];
public TestPNamePerf(byte[] data, int repCount)
{
mInputBuffer = data;
mInputLen = data.length;
mRepCount = repCount;
ReaderConfig cfg = new ReaderConfig();
cfg.setActualEncoding(CharsetNames.CS_UTF8);
mSymbols = cfg.getBBSymbols();
mCharTypes = cfg.getCharTypes();
}
public void test()
throws IOException, XMLStreamException
{
int round = 0;
for (; true; ++round) {
String msg = "[null]";
int total = 0;
final int TYPES = 3;
long now = System.currentTimeMillis();
switch (0) {
case 1:
msg = "[Regular]";
total = testRegularA();
break;
case 2:
msg = "[New]";
total = testNewA();
break;
case 0:
msg = "[New/2]";
total = testNew2A();
break;
default:
throw new Error("Unexpected round, #"+round);
}
now = System.currentTimeMillis() - now;
System.out.println(msg+" -> "+now+" msecs (total "+total+")");
if ((round % TYPES) == 0) {
System.out.println();
}
try { Thread.sleep(200L); } catch (Exception e) { }
System.gc();
try { Thread.sleep(200L); } catch (Exception e) { }
}
}
private int testRegularA()
throws IOException, XMLStreamException
{
int total = 0;
for (int i = 0; i < mRepCount; ++i) {
mInputPtr = 0;
total += testRegular();
}
return total;
}
private int testNewA()
throws IOException, XMLStreamException
{
int total = 0;
for (int i = 0; i < mRepCount; ++i) {
mInputPtr = 0;
total += testNew();
}
return total;
}
private int testNew2A()
throws IOException, XMLStreamException
{
int total = 0;
for (int i = 0; i < mRepCount; ++i) {
mInputPtr = 0;
total += testNew2();
}
return total;
}
private int testRegular()
throws IOException, XMLStreamException
{
ByteBasedPName name = null;
int count = 0;
while (mInputPtr < mInputLen) {
byte b = mInputBuffer[mInputPtr++];
int ch = (int) b & 0xFF;
if (ch >= INT_A) {
name = parsePName(b);
count += name.sizeInQuads();
}
}
return count + name.sizeInQuads();
}
private int testNew()
throws IOException, XMLStreamException
{
ByteBasedPName name = null;
int count = 0;
while (mInputPtr < mInputLen) {
byte b = mInputBuffer[mInputPtr++];
int ch = (int) b & 0xFF;
if (ch >= INT_A) {
name = parsePNameNew(b);
count += name.sizeInQuads();
}
}
return count + name.sizeInQuads();
}
private int testNew2()
throws IOException, XMLStreamException
{
ByteBasedPName name = null;
int count = 0;
while (mInputPtr < mInputLen) {
byte b = mInputBuffer[mInputPtr++];
int ch = (int) b & 0xFF;
if (ch >= INT_A) {
name = parsePNameNew2(b);
count += name.sizeInQuads();
}
}
return count + name.sizeInQuads();
}
protected ByteBasedPName parsePName(byte b)
throws XMLStreamException
{
int q = b & 0xFF;
if (q < INT_A) {
reportError("; expected a name start character");
}
int[] quads = mQuadBuffer;
int qix = 0;
int firstQuad = 0;
while (true) {
if (mInputPtr >= mInputLen) {
loadMoreGuaranteed();
}
int i2 = mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q, 1, firstQuad, qix, quads);
}
}
q = (q << 8) | i2;
i2 = (int) ((mInputPtr < mInputLen) ? mInputBuffer[mInputPtr++] : loadOne()) & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q, 2, firstQuad, qix, quads);
}
}
q = (q << 8) | i2;
i2 = (int) ((mInputPtr < mInputLen) ? mInputBuffer[mInputPtr++] : loadOne()) & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q, 3, firstQuad, qix, quads);
}
}
q = (q << 8) | i2;
i2 = (int) ((mInputPtr < mInputLen) ? mInputBuffer[mInputPtr++] : loadOne()) & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q, 4, firstQuad, qix, quads);
}
}
if (qix == 0) {
firstQuad = q;
} else if (qix == 1) {
quads[0] = firstQuad;
quads[1] = q;
} else {
if (qix >= quads.length) {
mQuadBuffer = quads = DataUtil.growArrayBy(quads, quads.length);
}
quads[qix] = q;
}
++qix;
q = i2;
}
}
protected ByteBasedPName parsePNameNew(byte b)
throws XMLStreamException
{
if ((mInputLen - mInputPtr) < 8) {
return parsePName(b);
}
int q1 = b & 0xFF;
if (q1 < INT_A) {
reportError("; expected a name start character");
}
int i2 = mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, 1);
}
}
q1 = (q1 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, 2);
}
}
q1 = (q1 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, 3);
}
}
q1 = (q1 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, 4);
}
}
int q2 = i2;
i2 = mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, q2, 1);
}
}
q2 = (q2 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, q2, 2);
}
}
q2 = (q2 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, q2, 3);
}
}
q2 = (q2 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, q2, 4);
}
}
int[] quads = mQuadBuffer;
quads[0] = q1;
quads[1] = q2;
return parsePNameNewLong(i2, quads);
}
protected ByteBasedPName parsePNameNew2(byte b)
throws XMLStreamException
{
if ((mInputLen - mInputPtr) < 8) {
return parsePName(b);
}
int q1 = b & 0xFF;
if (q1 < INT_A) {
reportError("; expected a name start character");
}
int i2 = mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, 1);
}
}
q1 = (q1 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, 2);
}
}
q1 = (q1 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, 3);
}
}
q1 = (q1 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, 4);
}
}
return parsePNameNewMedium(i2, q1);
}
protected ByteBasedPName parsePNameNewMedium(int i2, int q1)
throws XMLStreamException
{
int q2 = i2;
i2 = mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, q2, 1);
}
}
q2 = (q2 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, q2, 2);
}
}
q2 = (q2 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, q2, 3);
}
}
q2 = (q2 << 8) | i2;
i2 = (int) mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q1, q2, 4);
}
}
int[] quads = mQuadBuffer;
quads[0] = q1;
quads[1] = q2;
return parsePNameNewLong(i2, quads);
}
protected ByteBasedPName parsePNameNewLong(int q, int[] quads)
throws XMLStreamException
{
int qix = 2;
while (true) {
if (mInputPtr >= mInputLen) {
loadMoreGuaranteed();
}
int i2 = mInputBuffer[mInputPtr++] & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q, quads, qix, 1);
}
}
q = (q << 8) | i2;
i2 = (int) ((mInputPtr < mInputLen) ? mInputBuffer[mInputPtr++] : loadOne()) & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q, quads, qix, 2);
}
}
q = (q << 8) | i2;
i2 = (int) ((mInputPtr < mInputLen) ? mInputBuffer[mInputPtr++] : loadOne()) & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q, quads, qix, 3);
}
}
q = (q << 8) | i2;
i2 = (int) ((mInputPtr < mInputLen) ? mInputBuffer[mInputPtr++] : loadOne()) & 0xFF;
if (i2 < 65) {
if (i2 < 45 || i2 > 58 || i2 == 47) {
return findPName(q, quads, qix, 4);
}
}
if (qix >= quads.length) {
mQuadBuffer = quads = DataUtil.growArrayBy(quads, quads.length);
}
quads[qix] = q;
++qix;
q = i2;
}
}
private final ByteBasedPName findPName(int onlyQuad, int lastByteCount)
throws XMLStreamException
{
--mInputPtr;
int hash = ByteBasedPNameTable.calcHash(onlyQuad);
ByteBasedPName name = mSymbols.findSymbol(hash, onlyQuad, 0);
if (name == null) {
mQuadBuffer[0] = onlyQuad;
name = addPName(hash, mQuadBuffer, 1, lastByteCount);
}
return name;
}
private final ByteBasedPName findPName(int firstQuad, int secondQuad,
int lastByteCount)
throws XMLStreamException
{
--mInputPtr;
int hash = ByteBasedPNameTable.calcHash(firstQuad, secondQuad);
ByteBasedPName name = mSymbols.findSymbol(hash, firstQuad, secondQuad);
if (name == null) {
mQuadBuffer[0] = firstQuad;
mQuadBuffer[1] = secondQuad;
name = addPName(hash, mQuadBuffer, 2, lastByteCount);
}
return name;
}
private final ByteBasedPName findPName(int lastQuad, int[] quads, int qlen, int lastByteCount)
throws XMLStreamException
{
--mInputPtr;
if (qlen >= quads.length) {
mQuadBuffer = quads = DataUtil.growArrayBy(quads, quads.length);
}
quads[qlen++] = lastQuad;
int hash = ByteBasedPNameTable.calcHash(quads, qlen);
ByteBasedPName name = mSymbols.findSymbol(hash, quads, qlen);
if (name == null) {
name = addPName(hash, quads, qlen, lastByteCount);
}
return name;
}
private final ByteBasedPName findPName(int lastQuad, int lastByteCount, int firstQuad,
int qlen, int[] quads)
throws XMLStreamException
{
--mInputPtr;
if (qlen <= 1) {
if (qlen == 0) {
int hash = ByteBasedPNameTable.calcHash(lastQuad, 0);
ByteBasedPName name = mSymbols.findSymbol(hash, lastQuad, 0);
if (name == null) {
quads = mQuadBuffer;
quads[0] = lastQuad;
name = addPName(hash, quads, 1, lastByteCount);
}
return name;
}
int hash = ByteBasedPNameTable.calcHash(firstQuad, lastQuad);
ByteBasedPName name = mSymbols.findSymbol(hash, firstQuad, lastQuad);
if (name == null) {
quads = mQuadBuffer;
quads[0] = firstQuad;
quads[1] = lastQuad;
name = addPName(hash, quads, 2, lastByteCount);
}
return name;
}
if (qlen >= quads.length) {
mQuadBuffer = quads = DataUtil.growArrayBy(quads, quads.length);
}
quads[qlen++] = lastQuad;
int hash = ByteBasedPNameTable.calcHash(quads, qlen);
ByteBasedPName name = mSymbols.findSymbol(hash, quads, qlen);
if (name == null) {
name = addPName(hash, quads, qlen, lastByteCount);
}
return name;
}
protected final ByteBasedPName addPName(int hash, int[] quads, int qlen, int lastQuadBytes)
throws XMLStreamException
{
int byteLen = (qlen << 2) - 4 + lastQuadBytes;
int lastQuad;
if (lastQuadBytes < 4) {
lastQuad = quads[qlen-1];
quads[qlen-1] = (lastQuad << ((4 - lastQuadBytes) << 3));
} else {
lastQuad = 0;
}
int ch = (quads[0] >>> 24);
boolean ok;
int ix = 1;
char[] cbuf = mNameBuffer;
int cix = 0;
final int[] TYPES = mCharTypes.NAME_CHARS;
switch (TYPES[ch]) {
case XmlCharTypes.CT_NAME_NONE:
case XmlCharTypes.CT_NAME_COLON:
case XmlCharTypes.CT_NAME_NONFIRST:
case InputCharTypes.CT_INPUT_NAME_MB_N:
ok = false;
break;
case XmlCharTypes.CT_NAME_ANY:
ok = true;
break;
default:
{
int needed;
if ((ch & 0xE0) == 0xC0) {
ch &= 0x1F;
needed = 1;
} else if ((ch & 0xF0) == 0xE0) {
ch &= 0x0F;
needed = 2;
} else if ((ch & 0xF8) == 0xF0) {
ch &= 0x07;
needed = 3;
} else {
reportError(ch);
needed = ch = 1;
}
if ((ix + needed) > byteLen) {
reportError(ch);
}
ix += needed;
int q = quads[0];
int ch2 = (q >> 16) & 0xFF;
if ((ch2 & 0xC0) != 0x080) {
reportError(ch2);
}
ch = (ch << 6) | (ch2 & 0x3F);
if (needed > 1) {
ch2 = (q >> 8) & 0xFF;
if ((ch2 & 0xC0) != 0x080) {
reportError(ch2);
}
ch = (ch << 6) | (ch2 & 0x3F);
if (needed > 2) {
ch2 = q & 0xFF;
if ((ch2 & 0xC0) != 0x080) {
reportError(ch2 & 0xFF);
}
ch = (ch << 6) | (ch2 & 0x3F);
}
}
ok = XmlChars.is10NameStartChar(ch);
if (needed > 2) {
ch -= 0x10000;
cbuf[cix++] = (char) (0xD800 + (ch >> 10));
ch = (0xDC00 | (ch & 0x03FF));
}
}
}
if (!ok) {
reportError(ch);
}
cbuf[cix++] = (char) ch;
int last_colon = -1;
for (; ix < byteLen; ) {
ch = quads[ix >> 2];
int byteIx = (ix & 3);
ch = (ch >> ((3 - byteIx) << 3)) & 0xFF;
++ix;
switch (TYPES[ch]) {
case XmlCharTypes.CT_NAME_NONE:
case XmlCharTypes.CT_MULTIBYTE_N:
ok = false;
break;
case XmlCharTypes.CT_NAME_COLON:
if (last_colon >= 0) {
reportError(0);
}
last_colon = cix;
ok = true;
break;
case XmlCharTypes.CT_NAME_NONFIRST:
case XmlCharTypes.CT_NAME_ANY:
ok = true;
break;
default:
{
int needed;
if ((ch & 0xE0) == 0xC0) {
ch &= 0x1F;
needed = 1;
} else if ((ch & 0xF0) == 0xE0) {
ch &= 0x0F;
needed = 2;
} else if ((ch & 0xF8) == 0xF0) {
ch &= 0x07;
needed = 3;
} else {
reportError(ch);
needed = ch = 1;
}
if ((ix + needed) > byteLen) {
reportError(cix);
}
int ch2 = quads[ix >> 2];
byteIx = (ix & 3);
ch2 = (ch2 >> ((3 - byteIx) << 3));
++ix;
if ((ch2 & 0xC0) != 0x080) {
reportError(ch2);
}
ch = (ch << 6) | (ch2 & 0x3F);
if (needed > 1) {
ch2 = quads[ix >> 2];
byteIx = (ix & 3);
ch2 = (ch2 >> ((3 - byteIx) << 3));
++ix;
if ((ch2 & 0xC0) != 0x080) {
reportError(ch2);
}
ch = (ch << 6) | (ch2 & 0x3F);
if (needed > 2) {
ch2 = quads[ix >> 2];
byteIx = (ix & 3);
ch2 = (ch2 >> ((3 - byteIx) << 3));
++ix;
if ((ch2 & 0xC0) != 0x080) {
reportError(ch2 & 0xFF);
}
ch = (ch << 6) | (ch2 & 0x3F);
}
}
ok = XmlChars.is10NameChar(ch);
if (needed > 2) {
ch -= 0x10000;
if (cix >= cbuf.length) {
mNameBuffer = cbuf = DataUtil.growArrayBy(cbuf, cbuf.length);
}
cbuf[cix++] = (char) (0xD800 + (ch >> 10));
ch = 0xDC00 | (ch & 0x03FF);
}
}
}
if (!ok) {
reportError(cix);
}
if (cix >= cbuf.length) {
mNameBuffer = cbuf = DataUtil.growArrayBy(cbuf, cbuf.length);
}
cbuf[cix++] = (char) ch;
}
String baseName = new String(cbuf, 0, cix);
if (lastQuadBytes < 4) {
quads[qlen-1] = lastQuad;
}
return mSymbols.addSymbol(hash, baseName, last_colon, quads, qlen);
}
private void loadMoreGuaranteed()
{
throw new IllegalStateException();
}
private int loadOne()
{
throw new IllegalStateException();
}
private void reportError(int arg)
{
throw new IllegalStateException();
}
private void reportError(String msg)
{
throw new IllegalStateException(msg);
}
private static byte[] readData(File f)
throws IOException
{
int len = (int) f.length();
byte[] data = new byte[len];
int offset = 0;
FileInputStream fis = new FileInputStream(f);
while (len > 0) {
int count = fis.read(data, offset, len-offset);
offset += count;
len -= count;
}
fis.close();
return data;
}
public static void main(String[] args)
throws Exception
{
if (args.length != 1) {
System.err.println("Usage: java ... [input file]");
System.exit(1);
}
byte[] data = readData(new File(args[0]));
int len = data.length;
int repCount = 1;
int THRESHOLD = 10 * 1000 * 1000;
if (len < THRESHOLD) {
repCount = (THRESHOLD / len);
}
System.out.println("Ok, read in test data, "+len+" bytes; using "+repCount+" repetitions");
new TestPNamePerf(data, repCount).test();
}
}