Make absl::StrSplit iterators valid input iterators. `SplitIterator` stores a copy of its delimiter, so the `const` data members of `ByAnyChar`, `ByLength` and `MaxSplits` made their split iterators not-assignable, unlike those of `ByString` and `ByChar`. Dropping that `const` makes the iterators of all built-in delimiters valid input iterators, without changing behavior. The `SimpleDelimiter` example in the documentation drops its `const` member too, so custom delimiters based on it avoid the same problem. PiperOrigin-RevId: 998612982 Change-Id: I2926cecacc4cfa3569899bc4bac806ad8be585f4
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index 19692b3..5fe9b68 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel
@@ -1170,6 +1170,7 @@ deps = [ ":string_view", ":strings", + "//absl/algorithm:container", "//absl/base:core_headers", "//absl/base:dynamic_annotations", "//absl/container:btree",
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index 23a32c9..1461d94 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt
@@ -401,6 +401,7 @@ COPTS ${ABSL_TEST_COPTS} DEPS + absl::algorithm_container absl::btree absl::core_headers absl::dynamic_annotations
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h index e86b29a..dc32af1 100644 --- a/absl/strings/str_split.h +++ b/absl/strings/str_split.h
@@ -96,7 +96,7 @@ // function: // // struct SimpleDelimiter { -// const char c_; +// char c_; // explicit SimpleDelimiter(char c) : c_(c) {} // absl::string_view Find(absl::string_view text, size_t pos) { // auto found = text.find(c_, pos); @@ -206,7 +206,7 @@ absl::string_view Find(absl::string_view text, size_t pos) const; private: - const std::string delimiters_; + std::string delimiters_; }; // ByLength @@ -237,7 +237,7 @@ absl::string_view Find(absl::string_view text, size_t pos) const; private: - const ptrdiff_t length_; + ptrdiff_t length_; }; namespace strings_internal { @@ -291,7 +291,7 @@ private: Delimiter delimiter_; - const int limit_; + int limit_; int count_; };
diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc index 8155311..7487e00 100644 --- a/absl/strings/str_split_test.cc +++ b/absl/strings/str_split_test.cc
@@ -14,6 +14,7 @@ #include "absl/strings/str_split.h" +#include <algorithm> #include <array> #include <cstddef> #include <cstdint> @@ -32,6 +33,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/algorithm/container.h" #include "absl/base/macros.h" #include "absl/container/btree_map.h" #include "absl/container/btree_set.h" @@ -1036,6 +1038,36 @@ EXPECT_FALSE(IsFoundAt("abcd", four_char_delim, 0)); } +TEST(Split, ByAnyCharWorksWithRepeatedFind) { + auto splitter = absl::StrSplit("a,b;a", absl::ByAnyChar(",;")); + auto it = absl::c_find(splitter, "a"); + ASSERT_NE(it, splitter.end()); + // Search on from the next piece, which assigns the iterator. + it = std::find(std::next(it), splitter.end(), "a"); + ASSERT_NE(it, splitter.end()); + EXPECT_EQ(std::next(it), splitter.end()); +} + +TEST(Split, ByLengthWorksWithRepeatedFind) { + auto splitter = absl::StrSplit("aba", absl::ByLength(1)); + auto it = absl::c_find(splitter, "a"); + ASSERT_NE(it, splitter.end()); + // Search on from the next piece, which assigns the iterator. + it = std::find(std::next(it), splitter.end(), "a"); + ASSERT_NE(it, splitter.end()); + EXPECT_EQ(std::next(it), splitter.end()); +} + +TEST(Split, MaxSplitsWorksWithRepeatedFind) { + auto splitter = absl::StrSplit("a,a,b,c", absl::MaxSplits(',', 2)); + auto it = absl::c_find(splitter, "a"); + ASSERT_NE(it, splitter.end()); + // Search on from the next piece, which assigns the iterator. + it = std::find(std::next(it), splitter.end(), "a"); + ASSERT_NE(it, splitter.end()); + EXPECT_EQ(*std::next(it), "b,c"); +} + TEST(Split, WorksWithLargeStrings) { #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER)