summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2021-03-31 20:42:07 -0700
committerGravatar Andy Getz <durandal@google.com>2021-04-01 02:36:11 -0400
commit2faed9dd2a3722eda068ad88df3b4071f5c5588d (patch)
tree867bb51c6bb4c390b4b0aa972747a5d4447e0c9a
parentd9a31a2d440f33aa40d88b3b8a98f4c19ffaa182 (diff)
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
-rw-r--r--absl/base/attributes.h22
-rw-r--r--absl/hash/internal/wyhash.h2
-rw-r--r--absl/strings/cord.cc5
-rw-r--r--absl/strings/cord.h6
-rw-r--r--absl/strings/cord_test.cc20
-rw-r--r--absl/strings/internal/cord_rep_ring.cc5
-rw-r--r--absl/strings/string_view.h5
-rw-r--r--absl/time/internal/cctz/src/time_zone_fixed.cc2
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup_test.cc12
9 files changed, 67 insertions, 12 deletions
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index 325e2f8d..294e5d0c 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -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_
diff --git a/absl/hash/internal/wyhash.h b/absl/hash/internal/wyhash.h
index 4aff4e93..2b534b47 100644
--- a/absl/hash/internal/wyhash.h
+++ b/absl/hash/internal/wyhash.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]);
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index 1c03a618..1aea396f 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -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();
}
// --------------------------------------------------------------------
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index fa9cb913..cb2ffc5c 100644
--- a/absl/strings/cord.h
+++ b/absl/strings/cord.h
@@ -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();
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc
index fb673411..710a1b40 100644
--- a/absl/strings/cord_test.cc
+++ b/absl/strings/cord_test.cc
@@ -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"});
diff --git a/absl/strings/internal/cord_rep_ring.cc b/absl/strings/internal/cord_rep_ring.cc
index 4d31d1d9..cb95b19a 100644
--- a/absl/strings/internal/cord_rep_ring.cc
+++ b/absl/strings/internal/cord_rep_ring.cc
@@ -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);
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index b276bdba..1f14a758 100644
--- a/absl/strings/string_view.h
+++ b/absl/strings/string_view.h
@@ -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()) {}
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc
index 303c0244..f2b3294e 100644
--- a/absl/time/internal/cctz/src/time_zone_fixed.cc
+++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -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;
}
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index 9a1a8d6e..6948c3ea 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -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());