#pragma once #include #include #include #include #include #include #include namespace beast { class xxhasher { public: using result_type = std::size_t; private: static_assert(sizeof(std::size_t) == 8, "requires 64-bit std::size_t"); // Have an internal buffer to avoid the streaming API // A 64-byte buffer should to be big enough for us static constexpr std::size_t INTERNAL_BUFFER_SIZE = 64; alignas(64) std::array buffer_; std::span readBuffer_; std::span writeBuffer_; std::optional seed_; XXH3_state_t* state_ = nullptr; void resetBuffers() { writeBuffer_ = std::span{buffer_}; readBuffer_ = {}; } void updateHash(void const* data, std::size_t len) { if (writeBuffer_.size() < len) { flushToState(data, len); } else { std::memcpy(writeBuffer_.data(), data, len); writeBuffer_ = writeBuffer_.subspan(len); readBuffer_ = std::span{std::begin(buffer_), buffer_.size() - writeBuffer_.size()}; } } static XXH3_state_t* allocState() { auto ret = XXH3_createState(); if (ret == nullptr) throw std::bad_alloc(); // LCOV_EXCL_LINE return ret; } void flushToState(void const* data, std::size_t len) { if (!state_) { state_ = allocState(); if (seed_.has_value()) { XXH3_64bits_reset_withSeed(state_, *seed_); } else { XXH3_64bits_reset(state_); } } XXH3_64bits_update(state_, readBuffer_.data(), readBuffer_.size()); resetBuffers(); if (data && len) { XXH3_64bits_update(state_, data, len); } } result_type retrieveHash() { if (state_) { flushToState(nullptr, 0); return XXH3_64bits_digest(state_); } else { if (seed_.has_value()) { return XXH3_64bits_withSeed(readBuffer_.data(), readBuffer_.size(), *seed_); } else { return XXH3_64bits(readBuffer_.data(), readBuffer_.size()); } } } public: static constexpr auto const endian = boost::endian::order::native; xxhasher(xxhasher const&) = delete; xxhasher& operator=(xxhasher const&) = delete; xxhasher() { resetBuffers(); } ~xxhasher() noexcept { if (state_) { XXH3_freeState(state_); } } template ::value>* = nullptr> explicit xxhasher(Seed seed) : seed_(seed) { resetBuffers(); } template ::value>* = nullptr> xxhasher(Seed seed, Seed) : seed_(seed) { resetBuffers(); } void operator()(void const* key, std::size_t len) noexcept { updateHash(key, len); } explicit operator result_type() noexcept { return retrieveHash(); } }; } // namespace beast