#pragma once

/** SipHash - быстрая криптографическая хэш функция для коротких строк.
  * Взято отсюда: https://www.131002.net/siphash/
  *
  * Сделано два изменения:
  * - возвращает 128 бит, а не 64;
  * - сделано потоковой (можно вычислять по частям).
  *
  * На коротких строках (URL, поисковые фразы) более чем в 3 раза быстрее MD5 от OpenSSL.
  * (~ 700 МБ/сек., 15 млн. строк в секунду)
  *
  * Из репозитория ClickHouse
  */

#include <util/system/types.h>
#include <util/generic/string.h>

class TSipHash {
private:
    /// Состояние.
    ui64 v0;
    ui64 v1;
    ui64 v2;
    ui64 v3;

    /// Сколько байт обработано.
    ui64 cnt;

    /// Текущие 8 байт входных данных.
    union {
        ui64 current_word;
        ui8 current_bytes[8];
    };

    void Finalize();

public:
    /// Аргументы - seed.
    TSipHash(ui64 k0 = 0, ui64 k1 = 0);

    void Update(const char* data, ui64 size);

    /// Получить результат в некотором виде. Это можно сделать только один раз!
    void Get128(char* out);
    void Get128(ui64& lo, ui64& hi);
    ui64 Get64();
};

template <ui64 Key1 = 0, ui64 Key2 = 0>
inline void SipHash128(const char* data, const size_t size, char* out) {
    TSipHash hash(Key1, Key2);
    hash.Update(data, size);
    hash.Get128(out);
}

template <ui64 Key1 = 0, ui64 Key2 = 0>
inline ui64 SipHash64(const char* data, const size_t size) {
    TSipHash hash(Key1, Key2);
    hash.Update(data, size);
    return hash.Get64();
}

template <ui64 Key1 = 0, ui64 Key2 = 0>
inline ui64 SipHash64(const TString& s) {
    return SipHash64<Key1, Key2>(s.data(), s.size());
}
