From 3e1983c5c07eb8a43ad030e770cbae023a470a04 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 24 Nov 2021 22:01:08 -0800 Subject: Export of internal Abseil changes -- a9ea60e9c0ccd744b6f12fd021dbedfe826dfe84 by Matt Kulukundis : 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 : Internal cleanups and changes PiperOrigin-RevId: 412083793 -- 3740faf7c5a2e1723e3c7e4d1b3f3db7cbec6e61 by Abseil Team : 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 : 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 : Rollback of internal hook for keeping flags in sync with global state. PiperOrigin-RevId: 411895027 -- 4e7016a2fb88ce97853ef85ad5b4f76998eacca1 by Matt Kulukundis : Add an internal hook to allow keeping flags in sync with global state. PiperOrigin-RevId: 411867376 -- 2a7d4056e467b6b5d8a7aa9398d6cb5454c10fc5 by Martijn Vels : Internal change PiperOrigin-RevId: 411806932 GitOrigin-RevId: a9ea60e9c0ccd744b6f12fd021dbedfe826dfe84 Change-Id: Ib35bb7b40774979ed2ad205bbb1744b1085eae78 --- absl/strings/str_join_test.cc | 134 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) (limited to 'absl/strings/str_join_test.cc') 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 #include #include +#include #include #include #include @@ -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 +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& data) { + return TestIterator(&data, 0); + } + + static TestIterator end(const std::vector& 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* data, size_t pos) + : data_(data), pos_(pos) {} + + const std::vector* data_; + size_t pos_; +}; + +template +class TestIteratorRange { + public: + // `data` must be non-null and must outlive the result. + explicit TestIteratorRange(const std::vector& data) + : begin_(TestIterator::begin(data)), + end_(TestIterator::end(data)) {} + + const TestIterator& begin() const { return begin_; } + const TestIterator& end() const { return end_; } + + private: + TestIterator begin_; + TestIterator end_; +}; + +TEST(StrJoin, TestIteratorRequirementsNoFormatter) { + const std::vector 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(a), "-")); +} + +TEST(StrJoin, TestIteratorRequirementsCustomFormatter) { + const std::vector a = {"a", "b", "c"}; + EXPECT_EQ("a-b-c", + absl::StrJoin(TestIteratorRange(a), "-", + [](std::string* out, const TestValue& value) { + absl::StrAppend( + out, + absl::string_view(value.data(), value.size())); + })); +} + } // namespace -- cgit v1.2.3