Skip to content

Commit ecac814

Browse files
authored
chore: upadate datasketches lib from 5.0.2 to 5.2.0 (#746)
1 parent 3e4ebd5 commit ecac814

File tree

7 files changed

+248
-14
lines changed

7 files changed

+248
-14
lines changed

3rd/datasketches/common/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@ target_sources(common
4343
${CMAKE_CURRENT_SOURCE_DIR}/include/quantiles_sorted_view_impl.hpp
4444
${CMAKE_CURRENT_SOURCE_DIR}/include/optional.hpp
4545
${CMAKE_CURRENT_SOURCE_DIR}/include/version.hpp.in
46+
${CMAKE_CURRENT_SOURCE_DIR}/include/xxhash64.h
4647
)

3rd/datasketches/common/include/MurmurHash3.h

+5-6
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ typedef struct {
7171
// Block read - if your platform needs to do endian-swapping or can only
7272
// handle aligned reads, do the conversion here
7373

74-
MURMUR3_FORCE_INLINE uint64_t getblock64 ( const uint64_t * p, size_t i )
74+
MURMUR3_FORCE_INLINE uint64_t getblock64 ( const uint8_t * p, size_t i )
7575
{
7676
uint64_t res;
77-
memcpy(&res, p + i, sizeof(res));
77+
memcpy(&res, p + i * sizeof(uint64_t), sizeof(res));
7878
return res;
7979
}
8080

@@ -104,13 +104,12 @@ MURMUR3_FORCE_INLINE void MurmurHash3_x64_128(const void* key, size_t lenBytes,
104104

105105
// Number of full 128-bit blocks of 16 bytes.
106106
// Possible exclusion of a remainder of up to 15 bytes.
107-
const size_t nblocks = lenBytes >> 4; // bytes / 16
107+
const size_t nblocks = lenBytes >> 4; // bytes / 16
108108

109109
// Process the 128-bit blocks (the body) into the hash
110-
const uint64_t* blocks = (const uint64_t*)(data);
111110
for (size_t i = 0; i < nblocks; ++i) { // 16 bytes per block
112-
uint64_t k1 = getblock64(blocks, i * 2 + 0);
113-
uint64_t k2 = getblock64(blocks, i * 2 + 1);
111+
uint64_t k1 = getblock64(data, i * 2 + 0);
112+
uint64_t k2 = getblock64(data, i * 2 + 1);
114113

115114
k1 *= c1; k1 = MURMUR3_ROTL64(k1,31); k1 *= c2; out.h1 ^= k1;
116115
out.h1 = MURMUR3_ROTL64(out.h1,27);

3rd/datasketches/common/include/common_defs.hpp

+18
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>
@@ -91,6 +92,23 @@ static inline void write(std::ostream& os, const T* ptr, size_t size_bytes) {
9192
os.write(reinterpret_cast<const char*>(ptr), size_bytes);
9293
}
9394

95+
template<typename T>
96+
T byteswap(T value) {
97+
char* ptr = static_cast<char*>(static_cast<void*>(&value));
98+
const int len = sizeof(T);
99+
for (size_t i = 0; i < len / 2; ++i) {
100+
std::swap(ptr[i], ptr[len - i - 1]);
101+
}
102+
return value;
103+
}
104+
105+
template<typename T>
106+
static inline T read_big_endian(std::istream& is) {
107+
T value;
108+
is.read(reinterpret_cast<char*>(&value), sizeof(T));
109+
return byteswap(value);
110+
}
111+
94112
// wrapper for iterators to implement operator-> returning temporary value
95113
template<typename T>
96114
class return_value_holder {

3rd/datasketches/common/include/quantiles_sorted_view_impl.hpp

+5-7
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,17 @@ auto quantiles_sorted_view<T, C, A>::get_quantile(double rank, bool inclusive) c
8686
template<typename T, typename C, typename A>
8787
auto quantiles_sorted_view<T, C, A>::get_CDF(const T* split_points, uint32_t size, bool inclusive) const -> vector_double {
8888
if (entries_.empty()) throw std::runtime_error("operation is undefined for an empty sketch");
89-
vector_double buckets(entries_.get_allocator());
90-
if (entries_.size() == 0) return buckets;
9189
check_split_points(split_points, size);
92-
buckets.reserve(size + 1);
93-
for (uint32_t i = 0; i < size; ++i) buckets.push_back(get_rank(split_points[i], inclusive));
94-
buckets.push_back(1);
95-
return buckets;
90+
vector_double ranks(entries_.get_allocator());
91+
ranks.reserve(size + 1);
92+
for (uint32_t i = 0; i < size; ++i) ranks.push_back(get_rank(split_points[i], inclusive));
93+
ranks.push_back(1);
94+
return ranks;
9695
}
9796

9897
template<typename T, typename C, typename A>
9998
auto quantiles_sorted_view<T, C, A>::get_PMF(const T* split_points, uint32_t size, bool inclusive) const -> vector_double {
10099
auto buckets = get_CDF(split_points, size, inclusive);
101-
if (buckets.size() == 0) return buckets;
102100
for (uint32_t i = size; i > 0; --i) {
103101
buckets[i] -= buckets[i - 1];
104102
}
+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+
};

3rd/datasketches/cpc/include/cpc_compressor.hpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ template<typename A> class cpc_compressor;
4444
template<typename A>
4545
inline cpc_compressor<A>& get_compressor();
4646

47+
// function called atexit to clean up compression tables
48+
template<typename A>
49+
void destroy_compressor();
50+
4751
template<typename A>
4852
class cpc_compressor {
4953
public:
@@ -109,8 +113,10 @@ class cpc_compressor {
109113
};
110114

111115
cpc_compressor();
112-
template<typename T> friend cpc_compressor<T>& get_compressor();
116+
friend cpc_compressor& get_compressor<A>();
117+
113118
~cpc_compressor();
119+
friend void destroy_compressor<A>();
114120

115121
void make_decoding_tables(); // call this at startup
116122
void free_decoding_tables(); // call this at the end

3rd/datasketches/cpc/include/cpc_compressor_impl.hpp

+10
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
#ifndef CPC_COMPRESSOR_IMPL_HPP_
2323
#define CPC_COMPRESSOR_IMPL_HPP_
2424

25+
#include <cstdlib>
2526
#include <memory>
2627
#include <stdexcept>
2728

29+
#include "common_defs.hpp"
2830
#include "compression_data.hpp"
2931
#include "cpc_util.hpp"
3032
#include "cpc_common.hpp"
@@ -36,9 +38,17 @@ namespace datasketches {
3638
template<typename A>
3739
cpc_compressor<A>& get_compressor() {
3840
static cpc_compressor<A>* instance = new cpc_compressor<A>(); // use new for global initialization
41+
static int reg_result = std::atexit(destroy_compressor<A>); // just to clean up a little more nicely; don't worry if it fails
42+
unused(reg_result);
3943
return *instance;
4044
}
4145

46+
// register to call compressor destructor at exit
47+
template<typename A>
48+
void destroy_compressor() {
49+
delete std::addressof(get_compressor<A>());
50+
}
51+
4252
template<typename A>
4353
cpc_compressor<A>::cpc_compressor() {
4454
make_decoding_tables();

0 commit comments

Comments
 (0)