Skip to content

Commit

Permalink
Added mixing for hashes with primitive keys
Browse files Browse the repository at this point in the history
  • Loading branch information
leventov committed Jul 8, 2014
1 parent 23d7d22 commit 1725d4f
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 57 deletions.
1 change: 1 addition & 0 deletions .idea/dictionaries/leventov.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -114,29 +114,19 @@ static String capacityMask(MethodContext cxt, String table) {

static String keyHash(MethodContext cxt, String key, boolean distinctNullKey) {
String hash;
String mixingClass = (parallelKV(cxt) ? "Parallel" : "Separate") + "KV";
if (distinctNullKey && cxt.isNullKey()) {
return "0";
} else if (cxt.isObjectOrNullKey()) {
hash = (distinctNullKey ? "keyHashCode" : "nullableKeyHashCode") + "(" + key + ")";
mixingClass += "Obj";
} else {
hash = key;
PrimitiveType keyOption = (PrimitiveType) cxt.keyOption();
switch (keyOption) {
case BYTE: case SHORT: case CHAR:
hash = "((int) " + key + ")";
break;
case INT: case FLOAT:
hash = key;
break;
case LONG: case DOUBLE:
hash = format("((int) (%s ^ (%s >>> 32)))", key, key);
break;
default:
throw new IllegalStateException();
}
mixingClass += keyOption.title;
}
if (doubleSizedParallel(cxt))
hash = "((" + hash + ") << 1)";
return hash;
mixingClass += "KeyMixing";
return mixingClass + ".mix(" + hash + ")";
}

static String isFree(MethodContext cxt, String key) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,9 @@ static String firstKey(MethodContext cxt, String table, String keys, String key,
modulo = capacityAssigned ? " % capacity" :
(" % (capacity = " + (parallelKV(cxt) ? table : keys) + ".length)");
}
String hashAssignment = isLHash(cxt) ? keyHash(cxt, key, distinctNullKey) :
positiveKeyHash(cxt, key, distinctNullKey);
if (isDHash(cxt)) {
String hashAssignment = keyHash(cxt, key, distinctNullKey);
if (isDHash(cxt))
hashAssignment = "(hash = " + hashAssignment + ")";
} else {
hashAssignment = "(" + hashAssignment + ")";
}
indexAssignment = "index = " + hashAssignment + modulo;
} else {
indexAssignment = "index = 0";
Expand All @@ -83,40 +79,6 @@ static String firstKey(MethodContext cxt, String table, String keys, String key,
}
}

private static String positiveKeyHash(MethodContext cxt, String key, boolean distinctNullKey) {
String hash;
if (distinctNullKey && cxt.isNullKey()) {
return "0";
} if (cxt.isObjectOrNullKey()) {
hash = (distinctNullKey ? "keyHashCode" : "nullableKeyHashCode") +
"(" + key + ")";
hash = maskPositive(cxt, hash);
} else {
PrimitiveType keyOption = (PrimitiveType) cxt.keyOption();
switch (keyOption) {
case BYTE: hash = key + " & BYTE_MASK"; break;
case SHORT: hash = key + " & SHORT_MASK"; break;
case CHAR: hash = key; break;
case INT: case FLOAT: hash = maskPositive(cxt, key); break;
case LONG: case DOUBLE:
hash = maskPositive(cxt, format("((int) (%s ^ (%s >>> 32)))", key, key));
break;
default:
throw new IllegalStateException();
}
}
if (doubleSizedParallel(cxt))
hash = "((" + hash + ") << 1)";
return hash;
}

private static String maskPositive(MethodContext cxt, String hash) {
String mask = "Integer.MAX_VALUE";
if (doubleSizedParallel(cxt))
mask = "(" + mask + " >> 1)";
return hash + " & " + mask;
}

static int innerLoopBodies(MethodContext cxt) {
if (isDHash(cxt) || isLHash(cxt)) return 1;
assertHash(cxt, isQHash(cxt));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* with DHash|QHash|LHash hash */
/* with DHash hash */
/*
* Copyright 2014 the original author or authors.
*
Expand All @@ -19,4 +19,40 @@


interface DHash extends Hash {

/* with Separate|Parallel kv */

/* with byte|char|short|int|float key */
static class SeparateKVByteKeyMixing {
static int mix(/* bits */byte key) {
return key/* if !(char key) */ & Integer.MAX_VALUE/* endif */;
}
}
/* endwith */

/* with double|long key */
static class SeparateKVDoubleKeyMixing {
static int mix(long key) {
// not to loose information about 31-32 and 63-64-th bits
long h = key ^ (key >> 40) ^ (key >> 24);
/* if Separate kv */
return ((int) h) & Integer.MAX_VALUE;
/* elif Parallel kv */
return (((int) h) << 2) >>> 1;
/* endif */
}
}
/* endwith */

static class SeparateKVObjKeyMixing {
static int mix(int hash) {
/* if Separate kv */
return hash & Integer.MAX_VALUE;
/* elif Parallel kv */
return (hash << 2) >>> 1;
/* endif */
}
}

/* endwith */
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* with LHash hash */
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.openhft.collect.impl.hash;

public interface LHash extends Hash {

/** = round(2 ^ 32 * (sqrt(5) - 1)), Java form of unsigned 2654435769 */
static final int INT_PHI_MAGIC = -1640531527;
/** ~= round(2 ^ 64 * (sqrt(5) - 1)), Java form of 11400714819323198485 */
static final long LONG_PHI_MAGIC = -7046029254386353131L;

static final int BYTE_MIX_SHIFT = 6;
static final int CHAR_MIX_SHIFT = 10, SHORT_MIX_SHIFT = CHAR_MIX_SHIFT;
static final int INT_MIX_SHIFT = 16, FLOAT_MIX_SHIFT = INT_MIX_SHIFT;

/* with Separate|Parallel kv */

/* with byte|char|short|int|float key */
static class SeparateKVByteKeyMixing {
static int mix(/* bits */byte key) {
int h = key * INT_PHI_MAGIC;
return h ^ (h >> BYTE_MIX_SHIFT);
}
}
/* endwith */

/* with double|long key */
static class SeparateKVDoubleKeyMixing {
static int mix(long key) {
long h = key * LONG_PHI_MAGIC;
h ^= h >> 32;
return (int) (h ^ (h >> INT_MIX_SHIFT));
}
}
/* endwith */

static class SeparateKVObjKeyMixing {
static int mix(int hash) {
return hash ^ (hash >> INT_MIX_SHIFT);
}
}

/* endwith */
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* with QHash hash */
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.openhft.collect.impl.hash;

import static net.openhft.collect.impl.hash.LHash.*;


public interface QHash extends Hash {
/* with Separate|Parallel kv */

/* with byte|char|short|int|float key */
static class SeparateKVByteKeyMixing {
static int mix(/* bits */byte key) {
return (key * INT_PHI_MAGIC) & Integer.MAX_VALUE;
}
}
/* endwith */

/* with double|long key */
static class SeparateKVDoubleKeyMixing {
static int mix(long key) {
long h = key * LONG_PHI_MAGIC;
/* if Separate kv */
h ^= h >> 32;
return ((int) h) & Integer.MAX_VALUE;
/* elif Parallel kv */
// not to loose information about 63-64-th bits
h ^= (h >> 40) ^ (h >> 24);
return ((((int) h) << 2) >>> 1);
/* endif */
}
}
/* endwith */

static class SeparateKVObjKeyMixing {
static int mix(int hash) {
/* if Separate kv */
return hash & Integer.MAX_VALUE;
/* elif Parallel kv */
return (hash << 2) >>> 1;
/* endif */
}
}

/* endwith */
}

0 comments on commit 1725d4f

Please sign in to comment.