Last active
February 17, 2021 12:59
-
-
Save shavitush/4dab72f2922806864d0ec2a0c94269a8 to your computer and use it in GitHub Desktop.
Single header C++17 RAII wrapper for xxHash states and ultra fast file checksums
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <any> | |
#include <cstdint> | |
#include <fstream> | |
#include <filesystem> | |
#include <xxhash.h> | |
class file_not_found_exception : public std::runtime_error | |
{ | |
public: | |
file_not_found_exception(const char* message) : std::runtime_error(message) | |
{ } | |
}; | |
template <const int nBits = 32, typename ret_t = uint32_t> | |
class xxhash | |
{ | |
static_assert(nBits == 32 || nBits == 64, "xxHash only supports 32/64 bit"); | |
static_assert(sizeof(ret_t) * 8 >= nBits, "ret_t's must be equal to or higher than nBits"); | |
private: | |
std::any m_pState = nullptr; | |
public: | |
xxhash(uint32_t dwSeed = 0) | |
{ | |
if(nBits == 32) | |
{ | |
this->m_pState = XXH32_createState(); | |
XXH32_reset(std::any_cast<XXH32_state_t*>(this->m_pState), dwSeed); | |
} | |
else | |
{ | |
this->m_pState = XXH64_createState(); | |
XXH64_reset(std::any_cast<XXH64_state_t*>(this->m_pState), dwSeed); | |
} | |
} | |
~xxhash() | |
{ | |
if(nBits == 32) XXH32_freeState(std::any_cast<XXH32_state_t*>(this->m_pState)); | |
else XXH64_freeState(std::any_cast<XXH64_state_t*>(this->m_pState)); | |
} | |
// Feeds data in to the xxhash64 state | |
template <typename T> | |
auto feed(T* aBuffer, size_t dwSize) const -> void | |
{ | |
if(nBits == 32) XXH32_update(std::any_cast<XXH32_state_t*>(this->m_pState), reinterpret_cast<const void*>(aBuffer), dwSize); | |
else XXH64_update(std::any_cast<XXH64_state_t*>(this->m_pState), reinterpret_cast<const void*>(aBuffer), dwSize); | |
} | |
// Gets a digest from the state | |
auto get() const -> ret_t | |
{ | |
if(nBits == 32) return static_cast<ret_t>(XXH32_digest(std::any_cast<XXH32_state_t*>(this->m_pState))); | |
return static_cast<ret_t>(XXH64_digest(std::any_cast<XXH64_state_t*>(this->m_pState))); | |
} | |
// Gets a hash of the specified file from its path. | |
static auto hash_file(std::filesystem::path pFile, uint32_t dwSeed = 0) -> ret_t | |
{ | |
if(!std::filesystem::exists(pFile)) | |
{ | |
throw file_not_found_exception("Specified file could not be found"); | |
} | |
constexpr auto nBufferSize = 1024 * 1024; // 1 megabyte | |
auto aBuffer = std::make_unique<char[]>(nBufferSize); | |
std::ifstream pInput(pFile, std::ios::binary); | |
xxhash<nBits, ret_t> pHash(dwSeed); | |
while(pInput) | |
{ | |
pInput.read(&aBuffer[0], nBufferSize); | |
pHash.feed(&aBuffer[0], nBufferSize); | |
} | |
return pHash.get(); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment