Created
April 11, 2015 01:26
-
-
Save buchgr/b2c2f5afe2c4b4ffbf96 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package better.headers; | |
import io.netty.handler.codec.AsciiString; | |
import sun.misc.Unsafe; | |
import java.lang.reflect.Field; | |
public class Headers { | |
private static final Unsafe theUnsafe; | |
private static final int baseOffset; | |
static { | |
try { | |
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); | |
unsafeField.setAccessible(true); | |
theUnsafe = (Unsafe) unsafeField.get(null); | |
baseOffset = theUnsafe.arrayBaseOffset(byte[].class); | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
private AsciiString[] names; | |
private int[] namesHashCode; | |
private AsciiString[] values; | |
private int idx; | |
public Headers(int numHeaders) { | |
names = new AsciiString[nextMultipleOfEight(numHeaders)]; | |
namesHashCode = new int[nextMultipleOfEight(numHeaders)]; | |
values = new AsciiString[nextMultipleOfEight(numHeaders)]; | |
} | |
public void add(AsciiString name, AsciiString value) { | |
resizeIfNecessary(); | |
names[idx] = name; | |
namesHashCode[idx] = name.hashCode(); | |
values[idx] = value; | |
idx++; | |
} | |
public AsciiString get(AsciiString name) { | |
final int nameHashCode = name.hashCode(); | |
final byte[] nameArray = name.array(); | |
for (int i = 0; i < names.length; i += 8) { | |
if (compare(nameHashCode, nameArray, i)) return values[i]; | |
if (compare(nameHashCode, nameArray, i+1)) return values[i+1]; | |
if (compare(nameHashCode, nameArray, i+2)) return values[i+2]; | |
if (compare(nameHashCode, nameArray, i+3)) return values[i+3]; | |
if (compare(nameHashCode, nameArray, i+4)) return values[i+4]; | |
if (compare(nameHashCode, nameArray, i+5)) return values[i+5]; | |
if (compare(nameHashCode, nameArray, i+6)) return values[i+6]; | |
if (compare(nameHashCode, nameArray, i+7)) return values[i+7]; | |
} | |
return null; | |
} | |
private void resizeIfNecessary() { | |
if (idx == names.length) { | |
AsciiString[] newNames = new AsciiString[idx + 8]; | |
System.arraycopy(names, 0, newNames, 0, idx); | |
AsciiString[] newValues = new AsciiString[idx + 8]; | |
System.arraycopy(values, 0, newValues, 0, idx); | |
int[] newNamesHashCode = new int[idx + 8]; | |
System.arraycopy(values, 0, newNamesHashCode, 0, idx); | |
names = newNames; | |
values = newValues; | |
namesHashCode = newNamesHashCode; | |
} | |
} | |
private boolean compare(final int nameHashCode, final byte[] bytes1, final int nameIdx) { | |
if (nameHashCode != namesHashCode[nameIdx]) return false; | |
final byte[] bytes2 = names[nameIdx].array(); | |
int remainingLen = bytes1.length & 7; | |
for (int i = bytes1.length - 8; i >= remainingLen; i -= 8) { | |
final long word1 = theUnsafe.getLong(bytes1, baseOffset + (long) i); | |
final long word2 = theUnsafe.getLong(bytes2, baseOffset + (long) i); | |
if (word1 != word2) return false; | |
} | |
if (remainingLen >= 4) { | |
remainingLen -= 4; | |
final int word1 = theUnsafe.getInt(bytes1, baseOffset + (long) remainingLen); | |
final int word2 = theUnsafe.getInt(bytes2, baseOffset + (long) remainingLen); | |
if (word1 != word2) return false; | |
} | |
if (remainingLen == 3) return bytes1[2] == bytes2[2] && bytes1[1] == bytes2[1] && bytes1[0] == bytes2[0]; | |
if (remainingLen == 2) return bytes1[1] == bytes2[1] && bytes1[0] == bytes2[0]; | |
if (remainingLen == 1) return bytes1[0] == bytes2[0]; | |
return true; | |
} | |
private static int nextMultipleOfEight(int num) { | |
return num + 7 & ~7; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment