1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.google.common.hash;
16
17 import static com.google.common.base.Preconditions.checkArgument;
18
19 import com.google.common.math.LongMath;
20 import com.google.common.primitives.Ints;
21 import com.google.common.primitives.Longs;
22
23 import java.math.RoundingMode;
24 import java.util.Arrays;
25
26
27
28
29
30
31
32
33
34
35
36
37
38 enum BloomFilterStrategies implements BloomFilter.Strategy {
39
40
41
42
43
44 MURMUR128_MITZ_32() {
45 @Override public <T> boolean put(T object, Funnel<? super T> funnel,
46 int numHashFunctions, BitArray bits) {
47 long bitSize = bits.bitSize();
48 long hash64 = Hashing.murmur3_128().hashObject(object, funnel).asLong();
49 int hash1 = (int) hash64;
50 int hash2 = (int) (hash64 >>> 32);
51
52 boolean bitsChanged = false;
53 for (int i = 1; i <= numHashFunctions; i++) {
54 int combinedHash = hash1 + (i * hash2);
55
56 if (combinedHash < 0) {
57 combinedHash = ~combinedHash;
58 }
59 bitsChanged |= bits.set(combinedHash % bitSize);
60 }
61 return bitsChanged;
62 }
63
64 @Override public <T> boolean mightContain(T object, Funnel<? super T> funnel,
65 int numHashFunctions, BitArray bits) {
66 long bitSize = bits.bitSize();
67 long hash64 = Hashing.murmur3_128().hashObject(object, funnel).asLong();
68 int hash1 = (int) hash64;
69 int hash2 = (int) (hash64 >>> 32);
70
71 for (int i = 1; i <= numHashFunctions; i++) {
72 int combinedHash = hash1 + (i * hash2);
73
74 if (combinedHash < 0) {
75 combinedHash = ~combinedHash;
76 }
77 if (!bits.get(combinedHash % bitSize)) {
78 return false;
79 }
80 }
81 return true;
82 }
83 },
84
85
86
87
88
89
90 MURMUR128_MITZ_64() {
91 @Override
92 public <T> boolean put(T object, Funnel<? super T> funnel,
93 int numHashFunctions, BitArray bits) {
94 long bitSize = bits.bitSize();
95 byte[] bytes = Hashing.murmur3_128().hashObject(object, funnel).getBytesInternal();
96 long hash1 = lowerEight(bytes);
97 long hash2 = upperEight(bytes);
98
99 boolean bitsChanged = false;
100 long combinedHash = hash1;
101 for (int i = 0; i < numHashFunctions; i++) {
102
103 bitsChanged |= bits.set((combinedHash & Long.MAX_VALUE) % bitSize);
104 combinedHash += hash2;
105 }
106 return bitsChanged;
107 }
108
109 @Override
110 public <T> boolean mightContain(T object, Funnel<? super T> funnel,
111 int numHashFunctions, BitArray bits) {
112 long bitSize = bits.bitSize();
113 byte[] bytes = Hashing.murmur3_128().hashObject(object, funnel).getBytesInternal();
114 long hash1 = lowerEight(bytes);
115 long hash2 = upperEight(bytes);
116
117 long combinedHash = hash1;
118 for (int i = 0; i < numHashFunctions; i++) {
119
120 if (!bits.get((combinedHash & Long.MAX_VALUE) % bitSize)) {
121 return false;
122 }
123 combinedHash += hash2;
124 }
125 return true;
126 }
127
128 private long lowerEight(byte[] bytes) {
129 return Longs.fromBytes(
130 bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]);
131 }
132
133 private long upperEight(byte[] bytes) {
134 return Longs.fromBytes(
135 bytes[15], bytes[14], bytes[13], bytes[12], bytes[11], bytes[10], bytes[9], bytes[8]);
136 }
137 };
138
139
140 static final class BitArray {
141 final long[] data;
142 long bitCount;
143
144 BitArray(long bits) {
145 this(new long[Ints.checkedCast(LongMath.divide(bits, 64, RoundingMode.CEILING))]);
146 }
147
148
149 BitArray(long[] data) {
150 checkArgument(data.length > 0, "data length is zero!");
151 this.data = data;
152 long bitCount = 0;
153 for (long value : data) {
154 bitCount += Long.bitCount(value);
155 }
156 this.bitCount = bitCount;
157 }
158
159
160 boolean set(long index) {
161 if (!get(index)) {
162 data[(int) (index >>> 6)] |= (1L << index);
163 bitCount++;
164 return true;
165 }
166 return false;
167 }
168
169 boolean get(long index) {
170 return (data[(int) (index >>> 6)] & (1L << index)) != 0;
171 }
172
173
174 long bitSize() {
175 return (long) data.length * Long.SIZE;
176 }
177
178
179 long bitCount() {
180 return bitCount;
181 }
182
183 BitArray copy() {
184 return new BitArray(data.clone());
185 }
186
187
188 void putAll(BitArray array) {
189 checkArgument(data.length == array.data.length,
190 "BitArrays must be of equal length (%s != %s)", data.length, array.data.length);
191 bitCount = 0;
192 for (int i = 0; i < data.length; i++) {
193 data[i] |= array.data[i];
194 bitCount += Long.bitCount(data[i]);
195 }
196 }
197
198 @Override public boolean equals(Object o) {
199 if (o instanceof BitArray) {
200 BitArray bitArray = (BitArray) o;
201 return Arrays.equals(data, bitArray.data);
202 }
203 return false;
204 }
205
206 @Override public int hashCode() {
207 return Arrays.hashCode(data);
208 }
209 }
210 }