mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-26 17:41:59 +00:00
d36f52502e
It's still hackish and dirty, but server and client compies. Server starts, but throwes meaningless exception on any query. Client seems to be working fine. Linux compilation might (but shouldn't) be broken (not tested).
184 lines
4.0 KiB
C++
184 lines
4.0 KiB
C++
#pragma once
|
||
|
||
/** SipHash - быстрая криптографическая хэш функция для коротких строк.
|
||
* Взято отсюда: https://www.131002.net/siphash/
|
||
*
|
||
* Сделано два изменения:
|
||
* - возвращает 128 бит, а не 64;
|
||
* - сделано потоковой (можно вычислять по частям).
|
||
*
|
||
* На коротких строках (URL, поисковые фразы) более чем в 3 раза быстрее MD5 от OpenSSL.
|
||
* (~ 700 МБ/сек., 15 млн. строк в секунду)
|
||
*/
|
||
|
||
#include <cstdint>
|
||
#include <cstddef>
|
||
#include <DB/Core/Types.h>
|
||
|
||
#define ROTL(x,b) static_cast<u64>( ((x) << (b)) | ( (x) >> (64 - (b))) )
|
||
|
||
#define SIPROUND \
|
||
do \
|
||
{ \
|
||
v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \
|
||
v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \
|
||
v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \
|
||
v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \
|
||
} while(0)
|
||
|
||
|
||
class SipHash
|
||
{
|
||
private:
|
||
using u64 = DB::UInt64;
|
||
using u8 = DB::UInt8;
|
||
|
||
/// Состояние.
|
||
u64 v0;
|
||
u64 v1;
|
||
u64 v2;
|
||
u64 v3;
|
||
|
||
/// Сколько байт обработано.
|
||
u64 cnt;
|
||
|
||
/// Текущие 8 байт входных данных.
|
||
union
|
||
{
|
||
u64 current_word;
|
||
u8 current_bytes[8];
|
||
};
|
||
|
||
void finalize()
|
||
{
|
||
/// В последний свободный байт пишем остаток от деления длины на 256.
|
||
current_bytes[7] = cnt;
|
||
|
||
v3 ^= current_word;
|
||
SIPROUND;
|
||
SIPROUND;
|
||
v0 ^= current_word;
|
||
|
||
v2 ^= 0xff;
|
||
SIPROUND;
|
||
SIPROUND;
|
||
SIPROUND;
|
||
SIPROUND;
|
||
}
|
||
|
||
public:
|
||
/// Аргументы - seed.
|
||
SipHash(u64 k0 = 0, u64 k1 = 0)
|
||
{
|
||
/// Инициализируем состояние некоторыми случайными байтами и seed-ом.
|
||
v0 = 0x736f6d6570736575ULL ^ k0;
|
||
v1 = 0x646f72616e646f6dULL ^ k1;
|
||
v2 = 0x6c7967656e657261ULL ^ k0;
|
||
v3 = 0x7465646279746573ULL ^ k1;
|
||
|
||
cnt = 0;
|
||
current_word = 0;
|
||
}
|
||
|
||
void update(const char * data, u64 size)
|
||
{
|
||
const char * end = data + size;
|
||
|
||
/// Дообработаем остаток от предыдущего апдейта, если есть.
|
||
if (cnt & 7)
|
||
{
|
||
while (cnt & 7 && data < end)
|
||
{
|
||
current_bytes[cnt & 7] = *data;
|
||
++data;
|
||
++cnt;
|
||
}
|
||
|
||
/// Если всё ещё не хватает байт до восьмибайтового слова.
|
||
if (cnt & 7)
|
||
return;
|
||
|
||
v3 ^= current_word;
|
||
SIPROUND;
|
||
SIPROUND;
|
||
v0 ^= current_word;
|
||
}
|
||
|
||
cnt += end - data;
|
||
|
||
while (data + 8 <= end)
|
||
{
|
||
current_word = *reinterpret_cast<const u64 *>(data);
|
||
|
||
v3 ^= current_word;
|
||
SIPROUND;
|
||
SIPROUND;
|
||
v0 ^= current_word;
|
||
|
||
data += 8;
|
||
}
|
||
|
||
/// Заполняем остаток, которого не хватает до восьмибайтового слова.
|
||
current_word = 0;
|
||
switch (end - data)
|
||
{
|
||
case 7: current_bytes[6] = data[6];
|
||
case 6: current_bytes[5] = data[5];
|
||
case 5: current_bytes[4] = data[4];
|
||
case 4: current_bytes[3] = data[3];
|
||
case 3: current_bytes[2] = data[2];
|
||
case 2: current_bytes[1] = data[1];
|
||
case 1: current_bytes[0] = data[0];
|
||
case 0: break;
|
||
}
|
||
}
|
||
|
||
/// Получить результат в некотором виде. Это можно сделать только один раз!
|
||
|
||
void get128(char * out)
|
||
{
|
||
finalize();
|
||
reinterpret_cast<u64 *>(out)[0] = v0 ^ v1;
|
||
reinterpret_cast<u64 *>(out)[1] = v2 ^ v3;
|
||
}
|
||
|
||
void get128(u64 & lo, u64 & hi)
|
||
{
|
||
finalize();
|
||
lo = v0 ^ v1;
|
||
hi = v2 ^ v3;
|
||
}
|
||
|
||
u64 get64()
|
||
{
|
||
finalize();
|
||
return v0 ^ v1 ^ v2 ^ v3;
|
||
}
|
||
};
|
||
|
||
|
||
#undef ROTL
|
||
#undef SIPROUND
|
||
|
||
|
||
inline void sipHash128(const char * data, const size_t size, char * out)
|
||
{
|
||
SipHash hash;
|
||
hash.update(data, size);
|
||
hash.get128(out);
|
||
}
|
||
|
||
inline DB::UInt64 sipHash64(const char * data, const size_t size)
|
||
{
|
||
SipHash hash;
|
||
hash.update(data, size);
|
||
return hash.get64();
|
||
}
|
||
|
||
#include <string>
|
||
|
||
inline DB::UInt64 sipHash64(const std::string & s)
|
||
{
|
||
return sipHash64(s.data(), s.size());
|
||
}
|