Export of internal Abseil changes

--
6cfac39ea1266f01f195de5eb4c9a6fc9ea9b20a by Matt Kulukundis <kfm@google.com>:

Fix a typo

PiperOrigin-RevId: 366174890

--
6ee8c58647aef171d394e59fa06f9bf8cd0306ec by Derek Mauro <dmauro@google.com>:

Adds `ABSL_ATTRIBUTE_LIFETIME_BOUND` and applies it to the
`const std::string&` constructor of `absl::string_view`.

Compilers that support this attribute will emit a warning
if the parameter does not have sufficient lifetime.

PiperOrigin-RevId: 366027738

--
b944427d96e4b436b8fa0fe396c2a1118dbbbd13 by Abseil Team <absl-team@google.com>:

Calls to `ResetToEmpty()` from `ClearSlow` use ~3% of the time in assignment. However, `ClearSlow()` is only used in contexts where `data_` is immediately reassigned.

Rename `ClearSlow()` into `UnrefTree()` and remove `data_` resetting.

PiperOrigin-RevId: 365977213

--
7428b3147a5672c8bb55649efa3a1cfe19b52a8b by Abseil Team <absl-team@google.com>:

Fix CordRepRing diabolical growth

The 'Mutable' function in CordRepRing was over-eager in doubling capacity, which lead to 'ludicrous' growth in the diabolical test case as added to cord_test. This CL fixes the doubling for growing shared reps, and tempers CordRepRing growth for non shared capacity to 1.5 instead of 2, which is more inline with a conservative growth we also have in tree cord.

After this change, CordRepRing no longer swamps the heap into the shadow realm, and is in effect reducing the memory used compared to the tree implementation. With a diabolical 5000 bytes growth pattern:

Tree cord: 1523520 bytes
Ring cord:  274232 bytes

PiperOrigin-RevId: 365915857

--
f24d4aee48b03c5a7980664df903f947cbb198e8 by Andy Getzendanner <durandal@google.com>:

Import of CCTZ from GitHub.

PiperOrigin-RevId: 365873932
GitOrigin-RevId: 6cfac39ea1266f01f195de5eb4c9a6fc9ea9b20a
Change-Id: I9737aa215ac732c9785a1d0032c77aba62330f12
pull/939/head
Abseil Team 4 years ago committed by Andy Getz
parent d9a31a2d44
commit 2faed9dd2a
  1. 22
      absl/base/attributes.h
  2. 2
      absl/hash/internal/wyhash.h
  3. 5
      absl/strings/cord.cc
  4. 6
      absl/strings/cord.h
  5. 20
      absl/strings/cord_test.cc
  6. 5
      absl/strings/internal/cord_rep_ring.cc
  7. 5
      absl/strings/string_view.h
  8. 2
      absl/time/internal/cctz/src/time_zone_fixed.cc
  9. 12
      absl/time/internal/cctz/src/time_zone_lookup_test.cc

@ -706,4 +706,26 @@
#define ABSL_ATTRIBUTE_PURE_FUNCTION
#endif
// ABSL_ATTRIBUTE_LIFETIME_BOUND indicates that a resource owned by a function
// parameter or implicit object parameter is retained by the return value of the
// annotated function (or, for a parameter of a constructor, in the value of the
// constructed object). This attribute causes warnings to be produced if a
// temporary object does not live long enough.
//
// When applied to a reference parameter, the referenced object is assumed to be
// retained by the return value of the function. When applied to a non-reference
// parameter (for example, a pointer or a class type), all temporaries
// referenced by the parameter are assumed to be retained by the return value of
// the function.
//
// See also the upstream documentation:
// https://clang.llvm.org/docs/AttributeReference.html#lifetimebound
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::lifetimebound)
#define ABSL_ATTRIBUTE_LIFETIME_BOUND [[clang::lifetimebound]]
#elif ABSL_HAVE_ATTRIBUTE(lifetimebound)
#define ABSL_ATTRIBUTE_LIFETIME_BOUND __attribute__((lifetimebound))
#else
#define ABSL_ATTRIBUTE_LIFETIME_BOUND
#endif
#endif // ABSL_BASE_ATTRIBUTES_H_

@ -36,7 +36,7 @@ namespace hash_internal {
// integers are hashed into the result.
//
// To allow all hashable types (including string_view and Span) to depend on
// this algoritm, we keep the API low-level, with as few dependencies as
// this algorithm, we keep the API low-level, with as few dependencies as
// possible.
uint64_t Wyhash(const void* data, size_t len, uint64_t seed,
const uint64_t salt[5]);

@ -491,7 +491,7 @@ static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) {
}
void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) {
ClearSlow();
UnrefTree();
data_ = src.data_;
if (is_tree()) {
@ -501,11 +501,10 @@ void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) {
}
}
void Cord::InlineRep::ClearSlow() {
void Cord::InlineRep::UnrefTree() {
if (is_tree()) {
CordRep::Unref(tree());
}
ResetToEmpty();
}
// --------------------------------------------------------------------

@ -776,8 +776,8 @@ class Cord {
friend class Cord;
void AssignSlow(const InlineRep& src);
// Unrefs the tree, stops profiling, and zeroes the contents
void ClearSlow();
// Unrefs the tree and stops profiling.
void UnrefTree();
void ResetToEmpty() { data_ = {}; }
@ -966,7 +966,7 @@ inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) {
inline Cord::InlineRep& Cord::InlineRep::operator=(
Cord::InlineRep&& src) noexcept {
if (is_tree()) {
ClearSlow();
UnrefTree();
}
data_ = src.data_;
src.ResetToEmpty();

@ -1316,6 +1316,26 @@ TEST(Cord, Concat_Append) {
EXPECT_EQ(s2.size(), size + 1);
}
TEST(Cord, DiabolicalGrowth) {
// This test exercises a diabolical Append(<one char>) on a cord, making the
// cord shared before each Append call resulting in a terribly fragmented
// resulting cord.
// TODO(b/183983616): Apply some minimum compaction when copying a shared
// source cord into a mutable copy for updates in CordRepRing.
RandomEngine rng(testing::GTEST_FLAG(random_seed));
const std::string expected = RandomLowercaseString(&rng, 5000);
absl::Cord cord;
for (char c : expected) {
absl::Cord shared(cord);
cord.Append(absl::string_view(&c, 1));
}
std::string value;
absl::CopyCordToString(cord, &value);
EXPECT_EQ(value, expected);
ABSL_RAW_LOG(INFO, "Diabolical size allocated = %zu",
cord.EstimatedMemoryUsage());
}
TEST(MakeFragmentedCord, MakeFragmentedCordFromInitializerList) {
absl::Cord fragmented =
absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"});

@ -400,10 +400,11 @@ CordRepRing* CordRepRing::Mutable(CordRepRing* rep, size_t extra) {
// Get current number of entries, and check for max capacity.
size_t entries = rep->entries();
size_t min_extra = (std::max)(extra, rep->capacity() * 2 - entries);
if (!rep->refcount.IsOne()) {
return Copy(rep, rep->head(), rep->tail(), min_extra);
return Copy(rep, rep->head(), rep->tail(), extra);
} else if (entries + extra > rep->capacity()) {
const size_t min_grow = rep->capacity() + rep->capacity() / 2;
const size_t min_extra = (std::max)(extra, min_grow - entries);
CordRepRing* newrep = CordRepRing::New(entries, min_extra);
newrep->Fill<false>(rep, rep->head(), rep->tail());
CordRepRing::Delete(rep);

@ -36,6 +36,7 @@
#include <limits>
#include <string>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
@ -180,8 +181,8 @@ class string_view {
template <typename Allocator>
string_view( // NOLINT(runtime/explicit)
const std::basic_string<char, std::char_traits<char>, Allocator>&
str) noexcept
const std::basic_string<char, std::char_traits<char>, Allocator>& str
ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
// This is implemented in terms of `string_view(p, n)` so `str.size()`
// doesn't need to be reevaluated after `ptr_` is set.
: string_view(str.data(), str.size()) {}

@ -53,7 +53,7 @@ int Parse02d(const char* p) {
} // namespace
bool FixedOffsetFromName(const std::string& name, seconds* offset) {
if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
if (name == "UTC" || name == "UTC0") {
*offset = seconds::zero();
return true;
}

@ -717,6 +717,18 @@ TEST(TimeZones, LoadZonesConcurrently) {
}
#endif
TEST(TimeZone, UTC) {
const time_zone utc = utc_time_zone();
time_zone loaded_utc;
EXPECT_TRUE(load_time_zone("UTC", &loaded_utc));
EXPECT_EQ(loaded_utc, utc);
time_zone loaded_utc0;
EXPECT_TRUE(load_time_zone("UTC0", &loaded_utc0));
EXPECT_EQ(loaded_utc0, utc);
}
TEST(TimeZone, NamedTimeZones) {
const time_zone utc = utc_time_zone();
EXPECT_EQ("UTC", utc.name());

Loading…
Cancel
Save