Coverage Report

Created: 2026-01-17 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/highwayhash/highwayhash/state_helpers.h
Line
Count
Source
1
// Copyright 2017 Google Inc. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#ifndef HIGHWAYHASH_STATE_H_
16
#define HIGHWAYHASH_STATE_H_
17
18
// Helper functions to split inputs into packets and call State::Update on each.
19
20
#include <stdint.h>
21
#include <cstddef>
22
#include <cstring>
23
#include <memory>
24
25
#include "highwayhash/compiler_specific.h"
26
#include "highwayhash/endianess.h"
27
28
namespace highwayhash {
29
30
// uint64_t is unsigned long on Linux; we need 'unsigned long long'
31
// for interoperability with TensorFlow.
32
typedef unsigned long long HH_U64;  // NOLINT
33
34
// Copies the remaining bytes to a zero-padded buffer, sets the upper byte to
35
// size % 256 (always possible because this should only be called if the
36
// total size is not a multiple of the packet size) and updates hash state.
37
//
38
// The padding scheme is essentially from SipHash, but permuted for the
39
// convenience of AVX-2 masked loads. This function must use the same layout so
40
// that the vector and scalar HighwayTreeHash have the same result.
41
//
42
// "remaining_size" is the number of accessible/remaining bytes
43
// (size % kPacketSize).
44
//
45
// Primary template; the specialization for AVX-2 is faster. Intended as an
46
// implementation detail, do not call directly.
47
template <class State>
48
HH_INLINE void PaddedUpdate(const HH_U64 size, const char* remaining_bytes,
49
                            const HH_U64 remaining_size, State* state) {
50
  HH_ALIGNAS(32) char final_packet[State::kPacketSize] = {0};
51
52
  // This layout matches the AVX-2 specialization in highway_tree_hash.h.
53
  uint32_t packet4 = static_cast<uint32_t>(size) << 24;
54
55
  const size_t remainder_mod4 = remaining_size & 3;
56
  if (remainder_mod4 != 0) {
57
    const char* final_bytes = remaining_bytes + remaining_size - remainder_mod4;
58
    packet4 += static_cast<uint32_t>(final_bytes[0]);
59
    const int idx1 = remainder_mod4 >> 1;
60
    const int idx2 = remainder_mod4 - 1;
61
    packet4 += static_cast<uint32_t>(final_bytes[idx1]) << 8;
62
    packet4 += static_cast<uint32_t>(final_bytes[idx2]) << 16;
63
  }
64
  packet4 = host_from_le32(packet4);
65
66
  memcpy(final_packet, remaining_bytes, remaining_size - remainder_mod4);
67
  memcpy(final_packet + State::kPacketSize - 4, &packet4, sizeof(packet4));
68
69
  state->Update(final_packet);
70
}
71
72
// Updates hash state for every whole packet, and once more for the final
73
// padded packet.
74
template <class State>
75
49
HH_INLINE void UpdateState(const char* bytes, const HH_U64 size, State* state) {
76
  // Feed entire packets.
77
49
  const int kPacketSize = State::kPacketSize;
78
49
  static_assert((kPacketSize & (kPacketSize - 1)) == 0, "Size must be 2^i.");
79
49
  const size_t remainder = size & (kPacketSize - 1);
80
49
  const size_t truncated_size = size - remainder;
81
1.04M
  for (size_t i = 0; i < truncated_size; i += kPacketSize) {
82
1.04M
    state->Update(bytes + i);
83
1.04M
  }
84
85
49
  PaddedUpdate(size, bytes + truncated_size, remainder, state);
86
49
}
void highwayhash::UpdateState<highwayhash::SipHashStateT<2, 4> >(char const*, unsigned long long, highwayhash::SipHashStateT<2, 4>*)
Line
Count
Source
75
49
HH_INLINE void UpdateState(const char* bytes, const HH_U64 size, State* state) {
76
  // Feed entire packets.
77
49
  const int kPacketSize = State::kPacketSize;
78
49
  static_assert((kPacketSize & (kPacketSize - 1)) == 0, "Size must be 2^i.");
79
49
  const size_t remainder = size & (kPacketSize - 1);
80
49
  const size_t truncated_size = size - remainder;
81
1.04M
  for (size_t i = 0; i < truncated_size; i += kPacketSize) {
82
1.04M
    state->Update(bytes + i);
83
1.04M
  }
84
85
49
  PaddedUpdate(size, bytes + truncated_size, remainder, state);
86
49
}
Unexecuted instantiation: void highwayhash::UpdateState<highwayhash::SipHashStateT<1, 3> >(char const*, unsigned long long, highwayhash::SipHashStateT<1, 3>*)
87
88
// Convenience function for updating with the bytes of a string.
89
template <class String, class State>
90
HH_INLINE void UpdateState(const String& s, State* state) {
91
  const char* bytes = reinterpret_cast<const char*>(s.data());
92
  const size_t size = s.length() * sizeof(typename String::value_type);
93
  UpdateState(bytes, size, state);
94
}
95
96
// Computes a hash of a byte array using the given hash State class.
97
//
98
// Example: const SipHashState::Key key = { 1, 2 }; char data[4];
99
// ComputeHash<SipHashState>(key, data, sizeof(data));
100
//
101
// This function avoids duplicating Update/Finalize in every call site.
102
// Callers wanting to combine multiple hashes should repeatedly UpdateState()
103
// and only call State::Finalize once.
104
template <class State>
105
HH_U64 ComputeHash(const typename State::Key& key, const char* bytes,
106
49
                   const HH_U64 size) {
107
49
  State state(key);
108
49
  UpdateState(bytes, size, &state);
109
49
  return state.Finalize();
110
49
}
unsigned long long highwayhash::ComputeHash<highwayhash::SipHashStateT<2, 4> >(highwayhash::SipHashStateT<2, 4>::Key const&, char const*, unsigned long long)
Line
Count
Source
106
49
                   const HH_U64 size) {
107
49
  State state(key);
108
49
  UpdateState(bytes, size, &state);
109
49
  return state.Finalize();
110
49
}
Unexecuted instantiation: unsigned long long highwayhash::ComputeHash<highwayhash::SipHashStateT<1, 3> >(highwayhash::SipHashStateT<1, 3>::Key const&, char const*, unsigned long long)
111
112
// Computes a hash of a string's bytes using the given hash State class.
113
//
114
// Example: const SipHashState::Key key = { 1, 2 };
115
// StringHasher<SipHashState>()(key, std::u16string(u"abc"));
116
//
117
// A struct with nested function template enables deduction of the String type.
118
template <class State>
119
struct StringHasher {
120
  template <class String>
121
  HH_U64 operator()(const typename State::Key& key, const String& s) {
122
    State state(key);
123
    UpdateState(s, &state);
124
    return state.Finalize();
125
  }
126
};
127
128
}  // namespace highwayhash
129
130
#endif  // HIGHWAYHASH_STATE_H_