Export of internal Abseil changes
-- 074a799119ac881b8b8ce59ef7a3166d1aa025ac by Tom Manshreck <shreck@google.com>: nit: Add return info for StrCat PiperOrigin-RevId: 278647298 -- d58a2a39ab6f50266cc695506ba2e86bdb45d795 by Mark Barolak <mbar@google.com>: Stop suppressing no-nested-anon-types warnings because there aren't actually any warnings to suppress. PiperOrigin-RevId: 278440548 -- 445051bd280b9a6f608a8c80b3d7cafcc1377a03 by Abseil Team <absl-team@google.com>: ResetThreadIdentity does not need to clear identity->waiter_state. ResetThreadIdentity is only called by NewThreadIdentity. NewThreadIdentity is only called by CreateThreadIdentity. CreateThreadIdentity calls PerThreadSem::Init, which initializes identity->waiter_state, immediately after calling NewThreadIdentity. Therefore ResetThreadIdentity does not need to clear identity->waiter_state. PiperOrigin-RevId: 278429844 -- c2079b664d92be40d5e365abcca4e9b3505a75a6 by Abseil Team <absl-team@google.com>: Delete the f->header.magic check in LowLevelAlloc::Free(). The f->header.magic check in LowLevelAlloc::Free() is redundant, because AddToFreeList() will immediately perform the same check. Also fix a typo in the comment that documents the lock requirements for Next(). The comment should say "L >= arena->mu", which is equivalent to EXCLUSIVE_LOCKS_REQUIRED(arena->mu). NOTE: LowLevelAlloc::Free() performs the f->header.magic check without holding the arena lock. This may have caused the TSAN data race warning reported in bug 143697235. PiperOrigin-RevId: 278414140 -- 5534f35ce677165700117d868f51607ed1f0d73b by Greg Falcon <gfalcon@google.com>: Add an internal (unsupported) PiecewiseCombiner class to allow hashing buffers piecewise. PiperOrigin-RevId: 278388902 GitOrigin-RevId: 074a799119ac881b8b8ce59ef7a3166d1aa025ac Change-Id: I61734850cbbb01c7585e8c736a5bb56e416512a8
This commit is contained in:
parent
20de2db748
commit
e96ae2203b
11 changed files with 278 additions and 15 deletions
|
|
@ -17,6 +17,36 @@
|
|||
namespace absl {
|
||||
namespace hash_internal {
|
||||
|
||||
uint64_t CityHashState::CombineLargeContiguousImpl32(uint64_t state,
|
||||
const unsigned char* first,
|
||||
size_t len) {
|
||||
while (len >= PiecewiseChunkSize()) {
|
||||
state =
|
||||
Mix(state, absl::hash_internal::CityHash32(reinterpret_cast<const char*>(first),
|
||||
PiecewiseChunkSize()));
|
||||
len -= PiecewiseChunkSize();
|
||||
first += PiecewiseChunkSize();
|
||||
}
|
||||
// Handle the remainder.
|
||||
return CombineContiguousImpl(state, first, len,
|
||||
std::integral_constant<int, 4>{});
|
||||
}
|
||||
|
||||
uint64_t CityHashState::CombineLargeContiguousImpl64(uint64_t state,
|
||||
const unsigned char* first,
|
||||
size_t len) {
|
||||
while (len >= PiecewiseChunkSize()) {
|
||||
state =
|
||||
Mix(state, absl::hash_internal::CityHash64(reinterpret_cast<const char*>(first),
|
||||
PiecewiseChunkSize()));
|
||||
len -= PiecewiseChunkSize();
|
||||
first += PiecewiseChunkSize();
|
||||
}
|
||||
// Handle the remainder.
|
||||
return CombineContiguousImpl(state, first, len,
|
||||
std::integral_constant<int, 8>{});
|
||||
}
|
||||
|
||||
ABSL_CONST_INIT const void* const CityHashState::kSeed = &kSeed;
|
||||
|
||||
} // namespace hash_internal
|
||||
|
|
|
|||
|
|
@ -52,6 +52,12 @@
|
|||
namespace absl {
|
||||
namespace hash_internal {
|
||||
|
||||
class PiecewiseCombiner;
|
||||
|
||||
// Internal detail: Large buffers are hashed in smaller chunks. This function
|
||||
// returns the size of these chunks.
|
||||
constexpr int PiecewiseChunkSize() { return 1024; }
|
||||
|
||||
// HashStateBase
|
||||
//
|
||||
// A hash state object represents an intermediate state in the computation
|
||||
|
|
@ -68,7 +74,7 @@ namespace hash_internal {
|
|||
//
|
||||
// `static H combine_contiguous(H state, const unsigned char*, size_t)`.
|
||||
//
|
||||
// `HashStateBase` will provide a complete implementations for a hash state
|
||||
// `HashStateBase` will provide a complete implementation for a hash state
|
||||
// object in terms of this method.
|
||||
//
|
||||
// Example:
|
||||
|
|
@ -117,6 +123,9 @@ class HashStateBase {
|
|||
// for-loop instead.
|
||||
template <typename T>
|
||||
static H combine_contiguous(H state, const T* data, size_t size);
|
||||
|
||||
private:
|
||||
friend class PiecewiseCombiner;
|
||||
};
|
||||
|
||||
// is_uniquely_represented
|
||||
|
|
@ -187,6 +196,61 @@ H hash_bytes(H hash_state, const T& value) {
|
|||
return H::combine_contiguous(std::move(hash_state), start, sizeof(value));
|
||||
}
|
||||
|
||||
// PiecewiseCombiner
|
||||
//
|
||||
// PiecewiseCombiner is an internal-only helper class for hashing a piecewise
|
||||
// buffer of `char` or `unsigned char` as though it were contiguous. This class
|
||||
// provides two methods:
|
||||
//
|
||||
// H add_buffer(state, data, size)
|
||||
// H finalize(state)
|
||||
//
|
||||
// `add_buffer` can be called zero or more times, followed by a single call to
|
||||
// `finalize`. This will produce the same hash expansion as concatenating each
|
||||
// buffer piece into a single contiguous buffer, and passing this to
|
||||
// `H::combine_contiguous`.
|
||||
//
|
||||
// Example usage:
|
||||
// PiecewiseCombiner combiner;
|
||||
// for (const auto& piece : pieces) {
|
||||
// state = combiner.add_buffer(std::move(state), piece.data, piece.size);
|
||||
// }
|
||||
// return combiner.finalize(std::move(state));
|
||||
class PiecewiseCombiner {
|
||||
public:
|
||||
PiecewiseCombiner() : position_(0) {}
|
||||
PiecewiseCombiner(const PiecewiseCombiner&) = delete;
|
||||
PiecewiseCombiner& operator=(const PiecewiseCombiner&) = delete;
|
||||
|
||||
// PiecewiseCombiner::add_buffer()
|
||||
//
|
||||
// Appends the given range of bytes to the sequence to be hashed, which may
|
||||
// modify the provided hash state.
|
||||
template <typename H>
|
||||
H add_buffer(H state, const unsigned char* data, size_t size);
|
||||
template <typename H>
|
||||
H add_buffer(H state, const char* data, size_t size) {
|
||||
return add_buffer(std::move(state),
|
||||
reinterpret_cast<const unsigned char*>(data), size);
|
||||
}
|
||||
|
||||
// PiecewiseCombiner::finalize()
|
||||
//
|
||||
// Finishes combining the hash sequence, which may may modify the provided
|
||||
// hash state.
|
||||
//
|
||||
// Once finalize() is called, add_buffer() may no longer be called. The
|
||||
// resulting hash state will be the same as if the pieces passed to
|
||||
// add_buffer() were concatenated into a single flat buffer, and then provided
|
||||
// to H::combine_contiguous().
|
||||
template <typename H>
|
||||
H finalize(H state);
|
||||
|
||||
private:
|
||||
unsigned char buf_[PiecewiseChunkSize()];
|
||||
size_t position_;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// AbslHashValue for Basic Types
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
@ -709,6 +773,16 @@ class CityHashState : public HashStateBase<CityHashState> {
|
|||
std::integral_constant<int, 8>
|
||||
/* sizeof_size_t*/);
|
||||
|
||||
// Slow dispatch path for calls to CombineContiguousImpl with a size argument
|
||||
// larger than PiecewiseChunkSize(). Has the same effect as calling
|
||||
// CombineContiguousImpl() repeatedly with the chunk stride size.
|
||||
static uint64_t CombineLargeContiguousImpl32(uint64_t state,
|
||||
const unsigned char* first,
|
||||
size_t len);
|
||||
static uint64_t CombineLargeContiguousImpl64(uint64_t state,
|
||||
const unsigned char* first,
|
||||
size_t len);
|
||||
|
||||
// Reads 9 to 16 bytes from p.
|
||||
// The first 8 bytes are in .first, the rest (zero padded) bytes are in
|
||||
// .second.
|
||||
|
|
@ -776,6 +850,9 @@ inline uint64_t CityHashState::CombineContiguousImpl(
|
|||
// multiplicative hash.
|
||||
uint64_t v;
|
||||
if (len > 8) {
|
||||
if (ABSL_PREDICT_FALSE(len > PiecewiseChunkSize())) {
|
||||
return CombineLargeContiguousImpl32(state, first, len);
|
||||
}
|
||||
v = absl::hash_internal::CityHash32(reinterpret_cast<const char*>(first), len);
|
||||
} else if (len >= 4) {
|
||||
v = Read4To8(first, len);
|
||||
|
|
@ -796,6 +873,9 @@ inline uint64_t CityHashState::CombineContiguousImpl(
|
|||
// multiplicative hash.
|
||||
uint64_t v;
|
||||
if (len > 16) {
|
||||
if (ABSL_PREDICT_FALSE(len > PiecewiseChunkSize())) {
|
||||
return CombineLargeContiguousImpl64(state, first, len);
|
||||
}
|
||||
v = absl::hash_internal::CityHash64(reinterpret_cast<const char*>(first), len);
|
||||
} else if (len > 8) {
|
||||
auto p = Read9To16(first, len);
|
||||
|
|
@ -812,7 +892,6 @@ inline uint64_t CityHashState::CombineContiguousImpl(
|
|||
return Mix(state, v);
|
||||
}
|
||||
|
||||
|
||||
struct AggregateBarrier {};
|
||||
|
||||
// HashImpl
|
||||
|
|
@ -849,6 +928,44 @@ template <typename T>
|
|||
H HashStateBase<H>::combine_contiguous(H state, const T* data, size_t size) {
|
||||
return hash_internal::hash_range_or_bytes(std::move(state), data, size);
|
||||
}
|
||||
|
||||
// HashStateBase::PiecewiseCombiner::add_buffer()
|
||||
template <typename H>
|
||||
H PiecewiseCombiner::add_buffer(H state, const unsigned char* data,
|
||||
size_t size) {
|
||||
if (position_ + size < PiecewiseChunkSize()) {
|
||||
// This partial chunk does not fill our existing buffer
|
||||
memcpy(buf_ + position_, data, size);
|
||||
position_ += size;
|
||||
return std::move(state);
|
||||
}
|
||||
|
||||
// Complete the buffer and hash it
|
||||
const size_t bytes_needed = PiecewiseChunkSize() - position_;
|
||||
memcpy(buf_ + position_, data, bytes_needed);
|
||||
state = H::combine_contiguous(std::move(state), buf_, PiecewiseChunkSize());
|
||||
data += bytes_needed;
|
||||
size -= bytes_needed;
|
||||
|
||||
// Hash whatever chunks we can without copying
|
||||
while (size >= PiecewiseChunkSize()) {
|
||||
state = H::combine_contiguous(std::move(state), data, PiecewiseChunkSize());
|
||||
data += PiecewiseChunkSize();
|
||||
size -= PiecewiseChunkSize();
|
||||
}
|
||||
// Fill the buffer with the remainder
|
||||
memcpy(buf_, data, size);
|
||||
position_ = size;
|
||||
return std::move(state);
|
||||
}
|
||||
|
||||
// HashStateBase::PiecewiseCombiner::finalize()
|
||||
template <typename H>
|
||||
H PiecewiseCombiner::finalize(H state) {
|
||||
// Hash the remainder left in the buffer, which may be empty
|
||||
return H::combine_contiguous(std::move(state), buf_, position_);
|
||||
}
|
||||
|
||||
} // namespace hash_internal
|
||||
} // namespace absl
|
||||
|
||||
|
|
|
|||
|
|
@ -146,6 +146,19 @@ class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> {
|
|||
static SpyHashStateImpl combine_contiguous(SpyHashStateImpl hash_state,
|
||||
const unsigned char* begin,
|
||||
size_t size) {
|
||||
const size_t large_chunk_stride = PiecewiseChunkSize();
|
||||
if (size > large_chunk_stride) {
|
||||
// Combining a large contiguous buffer must have the same effect as
|
||||
// doing it piecewise by the stride length, followed by the (possibly
|
||||
// empty) remainder.
|
||||
while (size >= large_chunk_stride) {
|
||||
hash_state = SpyHashStateImpl::combine_contiguous(
|
||||
std::move(hash_state), begin, large_chunk_stride);
|
||||
begin += large_chunk_stride;
|
||||
size -= large_chunk_stride;
|
||||
}
|
||||
}
|
||||
|
||||
hash_state.hash_representation_.emplace_back(
|
||||
reinterpret_cast<const char*>(begin), size);
|
||||
return hash_state;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue