summaryrefslogtreecommitdiff
path: root/absl/strings
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2021-11-24 22:01:08 -0800
committerGravatar Andy Getz <durandal@google.com>2021-11-30 11:44:51 -0500
commit3e1983c5c07eb8a43ad030e770cbae023a470a04 (patch)
tree073a0920d0041551d0a6ecce37f90be1e4f45983 /absl/strings
parentec0d76f1d012cc1a4b3b08dfafcfc5237f5ba2c9 (diff)
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
Diffstat (limited to 'absl/strings')
-rw-r--r--absl/strings/BUILD.bazel1
-rw-r--r--absl/strings/cord.h3
-rw-r--r--absl/strings/cord_test.cc26
-rw-r--r--absl/strings/internal/cord_rep_flat.h6
-rw-r--r--absl/strings/internal/str_join_internal.h15
-rw-r--r--absl/strings/str_join_test.cc134
6 files changed, 166 insertions, 19 deletions
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 4e37151e..5d433cce 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -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",
],
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index 662e889a..27d3475f 100644
--- a/absl/strings/cord.h
+++ b/absl/strings/cord.h
@@ -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()
//
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc
index 8a311799..ea865cca 100644
--- a/absl/strings/cord_test.cc
+++ b/absl/strings/cord_test.cc
@@ -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;
diff --git a/absl/strings/internal/cord_rep_flat.h b/absl/strings/internal/cord_rep_flat.h
index a15c9acd..ae8b3a2a 100644
--- a/absl/strings/internal/cord_rep_flat.h
+++ b/absl/strings/internal/cord_rep_flat.h
@@ -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) {
diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h
index 31dbf672..d97d5033 100644
--- a/absl/strings/internal/str_join_internal.h
+++ b/absl/strings/internal/str_join_internal.h
@@ -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();
}
}
}
diff --git a/absl/strings/str_join_test.cc b/absl/strings/str_join_test.cc
index 2be6256e..c986e863 100644
--- a/absl/strings/str_join_test.cc
+++ b/absl/strings/str_join_test.cc
@@ -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