#ifndef HIGHWAYHASH_HIGHWAYHASH_H_
#define HIGHWAYHASH_HIGHWAYHASH_H_
#include "highwayhash/arch_specific.h"
#include "highwayhash/compiler_specific.h"
#include "highwayhash/hh_types.h"
#if HH_ARCH_X64
#include "highwayhash/iaca.h"
#endif
#if HH_TARGET == HH_TARGET_AVX2
#include "highwayhash/hh_avx2.h"
#elif HH_TARGET == HH_TARGET_SSE41
#include "highwayhash/hh_sse41.h"
#elif HH_TARGET == HH_TARGET_VSX
#include "highwayhash/hh_vsx.h"
#elif HH_TARGET == HH_TARGET_Portable
#include "highwayhash/hh_portable.h"
#else
#error "Unknown target, add its hh_*.h include here."
#endif
#ifndef HH_DISABLE_TARGET_SPECIFIC
namespace highwayhash {
template <TargetBits Target> struct HHStateForTarget {};
template <> struct HHStateForTarget<HH_TARGET> {
using type = HH_TARGET_NAME::HH_ADD_TARGET_SUFFIX(HHState);
};
template <TargetBits Target>
using HHStateT = typename HHStateForTarget<Target>::type;
template <class State, typename Result>
HH_INLINE void HighwayHashT(State *HH_RESTRICT state,
const char *HH_RESTRICT bytes, const size_t size,
Result *HH_RESTRICT hash) {
const size_t remainder = size & (sizeof(HHPacket) - 1);
const size_t truncated = size & ~(sizeof(HHPacket) - 1);
for (size_t offset = 0; offset < truncated; offset += sizeof(HHPacket)) {
state->Update(*reinterpret_cast<const HHPacket *>(bytes + offset));
}
if (remainder != 0) {
state->UpdateRemainder(bytes + truncated, remainder);
}
state->Finalize(hash);
}
template <TargetBits Target> class HighwayHashCatT {
public:
HH_INLINE HighwayHashCatT(const HHKey &key) : state_(key) {
HHStateT<Target>::ZeroInitialize(buffer_);
}
HH_INLINE void Reset(const HHKey &key) {
state_.Reset(key);
buffer_usage_ = 0;
}
HH_INLINE void Append(const char *HH_RESTRICT bytes, size_t num_bytes) {
const size_t capacity = sizeof(HHPacket) - buffer_usage_;
if (HH_UNLIKELY(num_bytes < capacity)) {
HHStateT<Target>::AppendPartial(bytes, num_bytes, buffer_, buffer_usage_);
buffer_usage_ += num_bytes;
return;
}
HHStateT<Target> state_copy = state_;
const size_t buffer_usage = buffer_usage_;
if (HH_LIKELY(buffer_usage != 0)) {
state_copy.AppendAndUpdate(bytes, capacity, buffer_, buffer_usage);
bytes += capacity;
num_bytes -= capacity;
}
while (num_bytes >= sizeof(HHPacket)) {
state_copy.Update(*reinterpret_cast<const HHPacket *>(bytes));
bytes += sizeof(HHPacket);
num_bytes -= sizeof(HHPacket);
}
buffer_usage_ = num_bytes;
state_ = state_copy;
if (HH_LIKELY(num_bytes != 0)) {
HHStateT<Target>::CopyPartial(bytes, num_bytes, buffer_);
}
}
template <typename Result> HH_INLINE void Finalize(Result *HH_RESTRICT hash) {
HHStateT<Target> state_copy = state_;
const size_t buffer_usage = buffer_usage_;
if (HH_LIKELY(buffer_usage != 0)) {
state_copy.UpdateRemainder(buffer_, buffer_usage);
}
state_copy.Finalize(hash);
}
private:
HHPacket HH_ALIGNAS(buffer_, 64);
HHStateT<Target> HH_ALIGNAS(state_, 32);
size_t buffer_usage_ = 0;
};
} #endif #endif