mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 20:14:23 +08:00
Export of internal Abseil changes
-- a9ea60e9c0ccd744b6f12fd021dbedfe826dfe84 by Matt Kulukundis <kfm@google.com>: Add an internal hook to allow keeping flags in sync with global state. Rollforward, except continue including hashtablez_flags.h in absl_flags.h so users don't break. PiperOrigin-RevId: 412198044 -- 183e5c440b68c797ce4a82102f94f41c97a14674 by Martijn Vels <mvels@google.com>: Internal cleanups and changes PiperOrigin-RevId: 412083793 -- 3740faf7c5a2e1723e3c7e4d1b3f3db7cbec6e61 by Abseil Team <absl-team@google.com>: Mark Cord::Clear() with the ABSL_ATTRIBUTE_REINITIALIZES attribute. This prevents false positives in the clang-tidy check bugprone-use-after-move; it allows Clear() to be called on a moved-from Cord without any warnings, and the Cord will thereafter be regarded as initialized again. PiperOrigin-RevId: 412082757 -- a730d3f4ba06b55ae50386920a0544592069ac01 by Abseil Team <absl-team@google.com>: StrJoin: Support iterators that do not have an `operator->` Allows using `StrJoin` with iterators that do not have an `operator->`. The `operator->` requirement for input iterators was dropped in C++20. PiperOrigin-RevId: 412066130 -- 6773c0ced2caa6a7855898298faecc584f3997ec by Andy Soffer <asoffer@google.com>: Rollback of internal hook for keeping flags in sync with global state. PiperOrigin-RevId: 411895027 -- 4e7016a2fb88ce97853ef85ad5b4f76998eacca1 by Matt Kulukundis <kfm@google.com>: Add an internal hook to allow keeping flags in sync with global state. PiperOrigin-RevId: 411867376 -- 2a7d4056e467b6b5d8a7aa9398d6cb5454c10fc5 by Martijn Vels <mvels@google.com>: Internal change PiperOrigin-RevId: 411806932 GitOrigin-RevId: a9ea60e9c0ccd744b6f12fd021dbedfe826dfe84 Change-Id: Ib35bb7b40774979ed2ad205bbb1744b1085eae78
This commit is contained in:
@@ -38,12 +38,18 @@ ABSL_CONST_INIT std::atomic<bool> g_hashtablez_enabled{
|
||||
false
|
||||
};
|
||||
ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_sample_parameter{1 << 10};
|
||||
std::atomic<HashtablezConfigListener> g_hashtablez_config_listener{nullptr};
|
||||
|
||||
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
|
||||
ABSL_PER_THREAD_TLS_KEYWORD absl::profiling_internal::ExponentialBiased
|
||||
g_exponential_biased_generator;
|
||||
#endif
|
||||
|
||||
void TriggerHashtablezConfigListener() {
|
||||
auto* listener = g_hashtablez_config_listener.load(std::memory_order_acquire);
|
||||
if (listener != nullptr) listener();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
|
||||
@@ -163,11 +169,33 @@ void RecordInsertSlow(HashtablezInfo* info, size_t hash,
|
||||
info->size.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void SetHashtablezConfigListener(HashtablezConfigListener l) {
|
||||
g_hashtablez_config_listener.store(l, std::memory_order_release);
|
||||
}
|
||||
|
||||
bool IsHashtablezEnabled() {
|
||||
return g_hashtablez_enabled.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void SetHashtablezEnabled(bool enabled) {
|
||||
SetHashtablezEnabledInternal(enabled);
|
||||
TriggerHashtablezConfigListener();
|
||||
}
|
||||
|
||||
void SetHashtablezEnabledInternal(bool enabled) {
|
||||
g_hashtablez_enabled.store(enabled, std::memory_order_release);
|
||||
}
|
||||
|
||||
int32_t GetHashtablezSampleParameter() {
|
||||
return g_hashtablez_sample_parameter.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void SetHashtablezSampleParameter(int32_t rate) {
|
||||
SetHashtablezSampleParameterInternal(rate);
|
||||
TriggerHashtablezConfigListener();
|
||||
}
|
||||
|
||||
void SetHashtablezSampleParameterInternal(int32_t rate) {
|
||||
if (rate > 0) {
|
||||
g_hashtablez_sample_parameter.store(rate, std::memory_order_release);
|
||||
} else {
|
||||
@@ -176,7 +204,16 @@ void SetHashtablezSampleParameter(int32_t rate) {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GetHashtablezMaxSamples() {
|
||||
return GlobalHashtablezSampler().GetMaxSamples();
|
||||
}
|
||||
|
||||
void SetHashtablezMaxSamples(int32_t max) {
|
||||
SetHashtablezMaxSamplesInternal(max);
|
||||
TriggerHashtablezConfigListener();
|
||||
}
|
||||
|
||||
void SetHashtablezMaxSamplesInternal(int32_t max) {
|
||||
if (max > 0) {
|
||||
GlobalHashtablezSampler().SetMaxSamples(max);
|
||||
} else {
|
||||
|
||||
@@ -258,14 +258,23 @@ using HashtablezSampler =
|
||||
// Returns a global Sampler.
|
||||
HashtablezSampler& GlobalHashtablezSampler();
|
||||
|
||||
using HashtablezConfigListener = void (*)();
|
||||
void SetHashtablezConfigListener(HashtablezConfigListener l);
|
||||
|
||||
// Enables or disables sampling for Swiss tables.
|
||||
bool IsHashtablezEnabled();
|
||||
void SetHashtablezEnabled(bool enabled);
|
||||
void SetHashtablezEnabledInternal(bool enabled);
|
||||
|
||||
// Sets the rate at which Swiss tables will be sampled.
|
||||
int32_t GetHashtablezSampleParameter();
|
||||
void SetHashtablezSampleParameter(int32_t rate);
|
||||
void SetHashtablezSampleParameterInternal(int32_t rate);
|
||||
|
||||
// Sets a soft max for the number of samples that will be kept.
|
||||
int32_t GetHashtablezMaxSamples();
|
||||
void SetHashtablezMaxSamples(int32_t max);
|
||||
void SetHashtablezMaxSamplesInternal(int32_t max);
|
||||
|
||||
// Configuration override.
|
||||
// This allows process-wide sampling without depending on order of
|
||||
|
||||
@@ -75,6 +75,7 @@ class SampleRecorder {
|
||||
// samples that have been dropped.
|
||||
int64_t Iterate(const std::function<void(const T& stack)>& f);
|
||||
|
||||
int32_t GetMaxSamples() const;
|
||||
void SetMaxSamples(int32_t max);
|
||||
|
||||
private:
|
||||
@@ -223,6 +224,11 @@ void SampleRecorder<T>::SetMaxSamples(int32_t max) {
|
||||
max_samples_.store(max, std::memory_order_release);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int32_t SampleRecorder<T>::GetMaxSamples() const {
|
||||
return max_samples_.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
} // namespace profiling_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -436,6 +436,7 @@ cc_library(
|
||||
"//absl/container:inlined_vector",
|
||||
"//absl/functional:function_ref",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/numeric:bits",
|
||||
"//absl/types:optional",
|
||||
"//absl/types:span",
|
||||
],
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/endian.h"
|
||||
#include "absl/base/internal/per_thread_tls.h"
|
||||
@@ -215,7 +216,7 @@ class Cord {
|
||||
//
|
||||
// Releases the Cord data. Any nodes that share data with other Cords, if
|
||||
// applicable, will have their reference counts reduced by 1.
|
||||
void Clear();
|
||||
ABSL_ATTRIBUTE_REINITIALIZES void Clear();
|
||||
|
||||
// Cord::Append()
|
||||
//
|
||||
|
||||
@@ -49,6 +49,11 @@ static constexpr auto MAX_FLAT_TAG = absl::cord_internal::MAX_FLAT_TAG;
|
||||
|
||||
typedef std::mt19937_64 RandomEngine;
|
||||
|
||||
using absl::cord_internal::CordRep;
|
||||
using absl::cord_internal::CordRepFlat;
|
||||
using absl::cord_internal::kFlatOverhead;
|
||||
using absl::cord_internal::kMaxFlatLength;
|
||||
|
||||
static std::string RandomLowercaseString(RandomEngine* rng);
|
||||
static std::string RandomLowercaseString(RandomEngine* rng, size_t length);
|
||||
|
||||
@@ -266,10 +271,6 @@ INSTANTIATE_TEST_SUITE_P(WithParam, CordTest, testing::Values(0, 1, 2, 3),
|
||||
|
||||
|
||||
TEST(CordRepFlat, AllFlatCapacities) {
|
||||
using absl::cord_internal::CordRep;
|
||||
using absl::cord_internal::CordRepFlat;
|
||||
using absl::cord_internal::kFlatOverhead;
|
||||
|
||||
// Explicitly and redundantly assert built-in min/max limits
|
||||
static_assert(absl::cord_internal::kFlatOverhead < 32, "");
|
||||
static_assert(absl::cord_internal::kMinFlatSize == 32, "");
|
||||
@@ -310,9 +311,6 @@ TEST(CordRepFlat, AllFlatCapacities) {
|
||||
}
|
||||
|
||||
TEST(CordRepFlat, MaxFlatSize) {
|
||||
using absl::cord_internal::CordRep;
|
||||
using absl::cord_internal::CordRepFlat;
|
||||
using absl::cord_internal::kMaxFlatLength;
|
||||
CordRepFlat* flat = CordRepFlat::New(kMaxFlatLength);
|
||||
EXPECT_EQ(flat->Capacity(), kMaxFlatLength);
|
||||
CordRep::Unref(flat);
|
||||
@@ -323,15 +321,23 @@ TEST(CordRepFlat, MaxFlatSize) {
|
||||
}
|
||||
|
||||
TEST(CordRepFlat, MaxLargeFlatSize) {
|
||||
using absl::cord_internal::CordRep;
|
||||
using absl::cord_internal::CordRepFlat;
|
||||
using absl::cord_internal::kFlatOverhead;
|
||||
const size_t size = 256 * 1024 - kFlatOverhead;
|
||||
CordRepFlat* flat = CordRepFlat::New(CordRepFlat::Large(), size);
|
||||
EXPECT_GE(flat->Capacity(), size);
|
||||
CordRep::Unref(flat);
|
||||
}
|
||||
|
||||
TEST(CordRepFlat, AllFlatSizes) {
|
||||
const size_t kMaxSize = 256 * 1024;
|
||||
for (size_t size = 32; size <= kMaxSize; size *=2) {
|
||||
const size_t length = size - kFlatOverhead - 1;
|
||||
CordRepFlat* flat = CordRepFlat::New(CordRepFlat::Large(), length);
|
||||
EXPECT_GE(flat->Capacity(), length);
|
||||
memset(flat->Data(), 0xCD, flat->Capacity());
|
||||
CordRep::Unref(flat);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(CordTest, AllFlatSizes) {
|
||||
using absl::strings_internal::CordTestAccess;
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/strings/internal/cord_internal.h"
|
||||
|
||||
namespace absl {
|
||||
@@ -105,8 +107,8 @@ struct CordRepFlat : public CordRep {
|
||||
struct Large {};
|
||||
|
||||
// Creates a new flat node.
|
||||
template <size_t max_flat_size>
|
||||
static CordRepFlat* NewImpl(size_t len) {
|
||||
template <size_t max_flat_size, typename... Args>
|
||||
static CordRepFlat* NewImpl(size_t len, Args... args ABSL_ATTRIBUTE_UNUSED) {
|
||||
if (len <= kMinFlatLength) {
|
||||
len = kMinFlatLength;
|
||||
} else if (len > max_flat_size - kFlatOverhead) {
|
||||
|
||||
@@ -229,10 +229,11 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
|
||||
std::string result;
|
||||
if (start != end) {
|
||||
// Sums size
|
||||
size_t result_size = start->size();
|
||||
auto&& start_value = *start;
|
||||
size_t result_size = start_value.size();
|
||||
for (Iterator it = start; ++it != end;) {
|
||||
result_size += s.size();
|
||||
result_size += it->size();
|
||||
result_size += (*it).size();
|
||||
}
|
||||
|
||||
if (result_size > 0) {
|
||||
@@ -240,13 +241,15 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
|
||||
|
||||
// Joins strings
|
||||
char* result_buf = &*result.begin();
|
||||
memcpy(result_buf, start->data(), start->size());
|
||||
result_buf += start->size();
|
||||
|
||||
memcpy(result_buf, start_value.data(), start_value.size());
|
||||
result_buf += start_value.size();
|
||||
for (Iterator it = start; ++it != end;) {
|
||||
memcpy(result_buf, s.data(), s.size());
|
||||
result_buf += s.size();
|
||||
memcpy(result_buf, it->data(), it->size());
|
||||
result_buf += it->size();
|
||||
auto&& value = *it;
|
||||
memcpy(result_buf, value.data(), value.size());
|
||||
result_buf += value.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
@@ -33,6 +34,7 @@
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -471,4 +473,136 @@ TEST(StrJoin, Tuple) {
|
||||
"-", absl::DereferenceFormatter(TestFormatter())));
|
||||
}
|
||||
|
||||
// A minimal value type for `StrJoin` inputs.
|
||||
// Used to ensure we do not excessively require more a specific type, such as a
|
||||
// `string_view`.
|
||||
//
|
||||
// Anything that can be `data()` and `size()` is OK.
|
||||
class TestValue {
|
||||
public:
|
||||
TestValue(const char* data, size_t size) : data_(data), size_(size) {}
|
||||
const char* data() const { return data_; }
|
||||
size_t size() const { return size_; }
|
||||
|
||||
private:
|
||||
const char* data_;
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
// A minimal C++20 forward iterator, used to test that we do not impose
|
||||
// excessive requirements on StrJoin inputs.
|
||||
//
|
||||
// The 2 main differences between pre-C++20 LegacyForwardIterator and the
|
||||
// C++20 ForwardIterator are:
|
||||
// 1. `operator->` is not required in C++20.
|
||||
// 2. `operator*` result does not need to be an lvalue (a reference).
|
||||
//
|
||||
// The `operator->` requirement was removed on page 17 in:
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1037r0.pdf
|
||||
//
|
||||
// See the `[iterator.requirements]` section of the C++ standard.
|
||||
//
|
||||
// The value type is a template parameter so that we can test the behaviour
|
||||
// of `StrJoin` specializations, e.g. the NoFormatter specialization for
|
||||
// `string_view`.
|
||||
template <typename ValueT>
|
||||
class TestIterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = ValueT;
|
||||
using pointer = void;
|
||||
using reference = const value_type&;
|
||||
using difference_type = int;
|
||||
|
||||
// `data` must outlive the result.
|
||||
static TestIterator begin(const std::vector<absl::string_view>& data) {
|
||||
return TestIterator(&data, 0);
|
||||
}
|
||||
|
||||
static TestIterator end(const std::vector<absl::string_view>& data) {
|
||||
return TestIterator(nullptr, data.size());
|
||||
}
|
||||
|
||||
bool operator==(const TestIterator& other) const {
|
||||
return pos_ == other.pos_;
|
||||
}
|
||||
bool operator!=(const TestIterator& other) const {
|
||||
return pos_ != other.pos_;
|
||||
}
|
||||
|
||||
// This deliberately returns a `prvalue`.
|
||||
// The requirement to return a reference was removed in C++20.
|
||||
value_type operator*() const {
|
||||
return ValueT((*data_)[pos_].data(), (*data_)[pos_].size());
|
||||
}
|
||||
|
||||
// `operator->()` is deliberately omitted.
|
||||
// The requirement to provide it was removed in C++20.
|
||||
|
||||
TestIterator& operator++() {
|
||||
++pos_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TestIterator operator++(int) {
|
||||
TestIterator result = *this;
|
||||
++(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
TestIterator& operator--() {
|
||||
--pos_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TestIterator operator--(int) {
|
||||
TestIterator result = *this;
|
||||
--(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
TestIterator(const std::vector<absl::string_view>* data, size_t pos)
|
||||
: data_(data), pos_(pos) {}
|
||||
|
||||
const std::vector<absl::string_view>* data_;
|
||||
size_t pos_;
|
||||
};
|
||||
|
||||
template <typename ValueT>
|
||||
class TestIteratorRange {
|
||||
public:
|
||||
// `data` must be non-null and must outlive the result.
|
||||
explicit TestIteratorRange(const std::vector<absl::string_view>& data)
|
||||
: begin_(TestIterator<ValueT>::begin(data)),
|
||||
end_(TestIterator<ValueT>::end(data)) {}
|
||||
|
||||
const TestIterator<ValueT>& begin() const { return begin_; }
|
||||
const TestIterator<ValueT>& end() const { return end_; }
|
||||
|
||||
private:
|
||||
TestIterator<ValueT> begin_;
|
||||
TestIterator<ValueT> end_;
|
||||
};
|
||||
|
||||
TEST(StrJoin, TestIteratorRequirementsNoFormatter) {
|
||||
const std::vector<absl::string_view> a = {"a", "b", "c"};
|
||||
|
||||
// When the value type is string-like (`std::string` or `string_view`),
|
||||
// the NoFormatter template specialization is used internally.
|
||||
EXPECT_EQ("a-b-c",
|
||||
absl::StrJoin(TestIteratorRange<absl::string_view>(a), "-"));
|
||||
}
|
||||
|
||||
TEST(StrJoin, TestIteratorRequirementsCustomFormatter) {
|
||||
const std::vector<absl::string_view> a = {"a", "b", "c"};
|
||||
EXPECT_EQ("a-b-c",
|
||||
absl::StrJoin(TestIteratorRange<TestValue>(a), "-",
|
||||
[](std::string* out, const TestValue& value) {
|
||||
absl::StrAppend(
|
||||
out,
|
||||
absl::string_view(value.data(), value.size()));
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user