Skip to content

Commit 4e4a944

Browse files
authored
Merge pull request #438 from jmalkin/bloom
Bloom filter
2 parents 5562578 + 37f6531 commit 4e4a944

16 files changed

+2995
-8
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ add_subdirectory(quantiles)
119119
add_subdirectory(count)
120120
add_subdirectory(density)
121121
add_subdirectory(tdigest)
122+
add_subdirectory(filters)
122123

123124
if (WITH_PYTHON)
124125
add_subdirectory(python)

LICENSE

+35-7
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,9 @@ APPENDIX A: How to apply the Apache License to your work.
207207

208208
APPENDIX B: Additional licenses relevant to this product.
209209

210-
This product includes a number of source files with code that has been
211-
adapted from 3rd party sources including sources that may be subject
212-
to different copyright notices and license terms. Your use of
210+
This product includes a number of source files with code that has been
211+
adapted from 3rd party sources including sources that may be subject
212+
to different copyright notices and license terms. Your use of
213213
the source code for these subcomponents is subject to the terms and
214214
conditions of the following licenses.
215215

@@ -221,7 +221,7 @@ APPENDIX B: Additional licenses relevant to this product.
221221
https://github.com/catchorg/Catch2/blob/v2.x/LICENSE.txt
222222

223223
Boost Software License - Version 1.0 - August 17th, 2003
224-
224+
225225
Permission is hereby granted, free of charge, to any person or organization
226226
obtaining a copy of the software and accompanying documentation covered by
227227
this license (the "Software") to use, reproduce, display, distribute,
@@ -248,23 +248,51 @@ APPENDIX B: Additional licenses relevant to this product.
248248
Found in the Catch2 unit test code that is downloaded from github.com as part
249249
of CMake configuration if configured to build tests.
250250

251+
=============================================================
252+
MIT License
253+
=============================================================
254+
255+
Original source:
256+
https://github.com/stbrumme/xxhash/blob/master/LICENSE
257+
258+
Permission is hereby granted, free of charge, to any person obtaining a copy
259+
of this software and associated documentation files (the "Software"),
260+
to deal in the Software without restriction, including without limitation
261+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
262+
and/or sell copies of the Software, and to permit persons to whom the Software
263+
is furnished to do so, subject to the following conditions:
264+
265+
The above copyright notice and this permission notice shall be included
266+
in all copies or substantial portions of the Software.
267+
268+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
269+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
270+
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
271+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
272+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
273+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
274+
275+
Code Location:
276+
common/include/xxhash64.h
277+
Original source code:
278+
Copyright (c) 2018 Stephan Brumme
279+
https://github.com/stbrumme/xxhash/blob/master/xxhash64.h
251280

252281
=============================================================
253282
Public Domain
254283
=============================================================
255284
Original source code:
256285
https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
257286
Placed in the Public Domain by Austin Appleby
258-
287+
259288
Code Locations:
260289
common/include/MurmurHash3.h
261290
that is adapted from the above.
262291
-------------------------------------------------------------
263292
Original source code:
264293
* https://graphics.stanford.edu/~seander/bithacks.html
265294
* Placed in the Public Domain by Sean Eron Anderson
266-
295+
267296
Code Locations:
268297
* common/include/ceiling_power_of_2.hpp
269298
that is adapted from the above.
270-

common/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ target_include_directories(common
3131

3232
install(TARGETS common EXPORT ${PROJECT_NAME})
3333

34-
install(FILES
34+
install(FILES
3535
${CMAKE_CURRENT_BINARY_DIR}/include/version.hpp
3636
include/binomial_bounds.hpp
3737
include/bounds_binomial_proportions.hpp
@@ -49,4 +49,5 @@ install(FILES
4949
include/quantiles_sorted_view_impl.hpp
5050
include/quantiles_sorted_view.hpp
5151
include/serde.hpp
52+
include/xxhash64.h
5253
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/DataSketches")

common/include/common_defs.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ namespace random_utils {
4242
static std::random_device rd; // possibly unsafe in MinGW with GCC < 9.2
4343
static thread_local std::mt19937_64 rand(rd());
4444
static thread_local std::uniform_real_distribution<> next_double(0.0, 1.0);
45+
static thread_local std::uniform_int_distribution<uint64_t> next_uint64(0, UINT64_MAX);
4546

4647
// thread-safe random bit
4748
static thread_local std::independent_bits_engine<std::mt19937, 1, uint32_t>

common/include/xxhash64.h

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// //////////////////////////////////////////////////////////
2+
// xxhash64.h
3+
// Copyright (c) 2016 Stephan Brumme. All rights reserved.
4+
// see http://create.stephan-brumme.com/disclaimer.html
5+
//
6+
7+
#pragma once
8+
#include <stdint.h> // for uint32_t and uint64_t
9+
10+
/// XXHash (64 bit), based on Yann Collet's descriptions, see http://cyan4973.github.io/xxHash/
11+
/** How to use:
12+
uint64_t myseed = 0;
13+
XXHash64 myhash(myseed);
14+
myhash.add(pointerToSomeBytes, numberOfBytes);
15+
myhash.add(pointerToSomeMoreBytes, numberOfMoreBytes); // call add() as often as you like to ...
16+
// and compute hash:
17+
uint64_t result = myhash.hash();
18+
19+
// or all of the above in one single line:
20+
uint64_t result2 = XXHash64::hash(mypointer, numBytes, myseed);
21+
22+
Note: my code is NOT endian-aware !
23+
**/
24+
class XXHash64
25+
{
26+
public:
27+
/// create new XXHash (64 bit)
28+
/** @param seed your seed value, even zero is a valid seed **/
29+
explicit XXHash64(uint64_t seed)
30+
{
31+
state[0] = seed + Prime1 + Prime2;
32+
state[1] = seed + Prime2;
33+
state[2] = seed;
34+
state[3] = seed - Prime1;
35+
bufferSize = 0;
36+
totalLength = 0;
37+
}
38+
39+
/// add a chunk of bytes
40+
/** @param input pointer to a continuous block of data
41+
@param length number of bytes
42+
@return false if parameters are invalid / zero **/
43+
bool add(const void* input, uint64_t length)
44+
{
45+
// no data ?
46+
if (!input || length == 0)
47+
return false;
48+
49+
totalLength += length;
50+
// byte-wise access
51+
const unsigned char* data = (const unsigned char*)input;
52+
53+
// unprocessed old data plus new data still fit in temporary buffer ?
54+
if (bufferSize + length < MaxBufferSize)
55+
{
56+
// just add new data
57+
while (length-- > 0)
58+
buffer[bufferSize++] = *data++;
59+
return true;
60+
}
61+
62+
// point beyond last byte
63+
const unsigned char* stop = data + length;
64+
const unsigned char* stopBlock = stop - MaxBufferSize;
65+
66+
// some data left from previous update ?
67+
if (bufferSize > 0)
68+
{
69+
// make sure temporary buffer is full (16 bytes)
70+
while (bufferSize < MaxBufferSize)
71+
buffer[bufferSize++] = *data++;
72+
73+
// process these 32 bytes (4x8)
74+
process(buffer, state[0], state[1], state[2], state[3]);
75+
}
76+
77+
// copying state to local variables helps optimizer A LOT
78+
uint64_t s0 = state[0], s1 = state[1], s2 = state[2], s3 = state[3];
79+
// 32 bytes at once
80+
while (data <= stopBlock)
81+
{
82+
// local variables s0..s3 instead of state[0]..state[3] are much faster
83+
process(data, s0, s1, s2, s3);
84+
data += 32;
85+
}
86+
// copy back
87+
state[0] = s0; state[1] = s1; state[2] = s2; state[3] = s3;
88+
89+
// copy remainder to temporary buffer
90+
bufferSize = stop - data;
91+
for (uint64_t i = 0; i < bufferSize; i++)
92+
buffer[i] = data[i];
93+
94+
// done
95+
return true;
96+
}
97+
98+
/// get current hash
99+
/** @return 64 bit XXHash **/
100+
uint64_t hash() const
101+
{
102+
// fold 256 bit state into one single 64 bit value
103+
uint64_t result;
104+
if (totalLength >= MaxBufferSize)
105+
{
106+
result = rotateLeft(state[0], 1) +
107+
rotateLeft(state[1], 7) +
108+
rotateLeft(state[2], 12) +
109+
rotateLeft(state[3], 18);
110+
result = (result ^ processSingle(0, state[0])) * Prime1 + Prime4;
111+
result = (result ^ processSingle(0, state[1])) * Prime1 + Prime4;
112+
result = (result ^ processSingle(0, state[2])) * Prime1 + Prime4;
113+
result = (result ^ processSingle(0, state[3])) * Prime1 + Prime4;
114+
}
115+
else
116+
{
117+
// internal state wasn't set in add(), therefore original seed is still stored in state2
118+
result = state[2] + Prime5;
119+
}
120+
121+
result += totalLength;
122+
123+
// process remaining bytes in temporary buffer
124+
const unsigned char* data = buffer;
125+
// point beyond last byte
126+
const unsigned char* stop = data + bufferSize;
127+
128+
// at least 8 bytes left ? => eat 8 bytes per step
129+
for (; data + 8 <= stop; data += 8)
130+
result = rotateLeft(result ^ processSingle(0, *(uint64_t*)data), 27) * Prime1 + Prime4;
131+
132+
// 4 bytes left ? => eat those
133+
if (data + 4 <= stop)
134+
{
135+
result = rotateLeft(result ^ (*(uint32_t*)data) * Prime1, 23) * Prime2 + Prime3;
136+
data += 4;
137+
}
138+
139+
// take care of remaining 0..3 bytes, eat 1 byte per step
140+
while (data != stop)
141+
result = rotateLeft(result ^ (*data++) * Prime5, 11) * Prime1;
142+
143+
// mix bits
144+
result ^= result >> 33;
145+
result *= Prime2;
146+
result ^= result >> 29;
147+
result *= Prime3;
148+
result ^= result >> 32;
149+
return result;
150+
}
151+
152+
153+
/// combine constructor, add() and hash() in one static function (C style)
154+
/** @param input pointer to a continuous block of data
155+
@param length number of bytes
156+
@param seed your seed value, e.g. zero is a valid seed
157+
@return 64 bit XXHash **/
158+
static uint64_t hash(const void* input, uint64_t length, uint64_t seed)
159+
{
160+
XXHash64 hasher(seed);
161+
hasher.add(input, length);
162+
return hasher.hash();
163+
}
164+
165+
private:
166+
/// magic constants :-)
167+
static const uint64_t Prime1 = 11400714785074694791ULL;
168+
static const uint64_t Prime2 = 14029467366897019727ULL;
169+
static const uint64_t Prime3 = 1609587929392839161ULL;
170+
static const uint64_t Prime4 = 9650029242287828579ULL;
171+
static const uint64_t Prime5 = 2870177450012600261ULL;
172+
173+
/// temporarily store up to 31 bytes between multiple add() calls
174+
static const uint64_t MaxBufferSize = 31+1;
175+
176+
uint64_t state[4];
177+
unsigned char buffer[MaxBufferSize];
178+
uint64_t bufferSize;
179+
uint64_t totalLength;
180+
181+
/// rotate bits, should compile to a single CPU instruction (ROL)
182+
static inline uint64_t rotateLeft(uint64_t x, unsigned char bits)
183+
{
184+
return (x << bits) | (x >> (64 - bits));
185+
}
186+
187+
/// process a single 64 bit value
188+
static inline uint64_t processSingle(uint64_t previous, uint64_t input)
189+
{
190+
return rotateLeft(previous + input * Prime2, 31) * Prime1;
191+
}
192+
193+
/// process a block of 4x4 bytes, this is the main part of the XXHash32 algorithm
194+
static inline void process(const void* data, uint64_t& state0, uint64_t& state1, uint64_t& state2, uint64_t& state3)
195+
{
196+
const uint64_t* block = (const uint64_t*) data;
197+
state0 = processSingle(state0, block[0]);
198+
state1 = processSingle(state1, block[1]);
199+
state2 = processSingle(state2, block[2]);
200+
state3 = processSingle(state3, block[3]);
201+
}
202+
};

filters/CMakeLists.txt

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
add_library(filters INTERFACE)
19+
20+
add_library(${PROJECT_NAME}::FILTERS ALIAS filters)
21+
22+
if (BUILD_TESTS)
23+
add_subdirectory(test)
24+
endif()
25+
26+
target_include_directories(filters
27+
INTERFACE
28+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
29+
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>
30+
)
31+
32+
target_link_libraries(filters INTERFACE common)
33+
34+
install(TARGETS filters
35+
EXPORT ${PROJECT_NAME}
36+
)
37+
38+
install(FILES
39+
include/bloom_filter.hpp
40+
include/bloom_filter_impl.hpp
41+
include/bloom_filter_builder_impl.hpp
42+
include/bit_array_ops.hpp
43+
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/DataSketches")

0 commit comments

Comments
 (0)