aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorswarmer <swarmer@yandex-team.com>2024-10-16 03:27:14 +0300
committerswarmer <swarmer@yandex-team.com>2024-10-16 03:41:38 +0300
commit35c54372ef41e968a90908579c2fec61650af39e (patch)
treea5b5b61136ea8ac8e028ee6b933e5cbb29d7573e
parentd9797921c7989ee196f79f8c738da5af4894007e (diff)
downloadydb-35c54372ef41e968a90908579c2fec61650af39e.tar.gz
StringSplitter: recreate State after copy
commit_hash:75f3a4a20b797f07c51c63b96f0f1e1374707f33
-rw-r--r--util/string/split.h32
-rw-r--r--util/string/split_ut.cpp26
2 files changed, 58 insertions, 0 deletions
diff --git a/util/string/split.h b/util/string/split.h
index aa53da0475..2000498591 100644
--- a/util/string/split.h
+++ b/util/string/split.h
@@ -660,6 +660,15 @@ namespace NStringSplitPrivate {
using TIterator = TIteratorOf<String>;
friend class TStringSplitter<String>;
+ template <typename S = String, std::enable_if_t<THasData<S>::value, int> = 0>
+ TIterState(const String& string) noexcept
+ : TStringBufType()
+ , DelimiterEnd_(string.data())
+ , OriginEnd_(string.data() + string.size())
+ {
+ }
+
+ template <typename S = String, std::enable_if_t<!THasData<S>::value, int> = 0>
TIterState(const String& string) noexcept
: TStringBufType()
, DelimiterEnd_(std::begin(string))
@@ -700,6 +709,11 @@ namespace NStringSplitPrivate {
return TokenDelim() == DelimiterEnd_;
}
+ void MarkExhausted() noexcept {
+ UpdateParentBuf(OriginEnd_, OriginEnd_);
+ DelimiterEnd_ = OriginEnd_;
+ }
+
private:
TIterator DelimiterEnd_;
const TIterator OriginEnd_;
@@ -845,6 +859,24 @@ namespace NStringSplitPrivate {
{
}
+ TSplitRangeBase(const TSplitRangeBase& other)
+ : String_(other.String_)
+ , State_(String_)
+ , Delimiter_(other.Delimiter_)
+ {
+ }
+
+ TSplitRangeBase(TSplitRangeBase&& other)
+ : String_(std::move(other.String_))
+ , State_(String_)
+ , Delimiter_(std::move(other.Delimiter_))
+ {
+ other.State_.MarkExhausted();
+ }
+
+ TSplitRangeBase& operator=(const TSplitRangeBase& other) = delete;
+ TSplitRangeBase& operator=(TSplitRangeBase&& other) = delete;
+
inline TIteratorState* Next() {
if (State_.DelimiterIsEmpty()) {
return nullptr;
diff --git a/util/string/split_ut.cpp b/util/string/split_ut.cpp
index d1dac92d2d..7c62056b90 100644
--- a/util/string/split_ut.cpp
+++ b/util/string/split_ut.cpp
@@ -443,6 +443,13 @@ Y_UNIT_TEST_SUITE(StringSplitter) {
sum += FromString<int>(it.Token());
}
UNIT_ASSERT_VALUES_EQUAL(sum, 6);
+
+ TString ssum;
+ for (const auto& it : StringSplitter(" 1 2 3 " + std::string(100, ' ')).Split(' ').SkipEmpty()) {
+ ssum += FromString<TString>(it.Token());
+ ssum += ';';
+ }
+ UNIT_ASSERT_VALUES_EQUAL(ssum, "1;2;3;");
}
Y_UNIT_TEST(TestTake) {
@@ -746,6 +753,25 @@ Y_UNIT_TEST_SUITE(StringSplitter) {
UNIT_ASSERT_VALUES_EQUAL(expected1, actual3);
}
+ Y_UNIT_TEST(TesIterationAfterMove) {
+ const TString src = TString::Join(
+ "aaa",
+ TString(250, 'c'),
+ "bbb",
+ "aaa",
+ TString(250, 'c'),
+ "bbb");
+ auto s1 = StringSplitter(std::string(src)).SplitByString("c").SkipEmpty();
+ {
+ auto s2 = std::move(s1);
+ const TVector<TString> expected2 = {"aaa", "bbbaaa", "bbb"};
+ const auto result2 = s2.ToList<TString>();
+ UNIT_ASSERT_VALUES_EQUAL(result2, expected2);
+ }
+ const auto result1 = s1.ToList<TString>();
+ Y_UNUSED(result1); // valid but unspecified value
+ }
+
Y_UNIT_TEST(TestConstCString) {
const char* b = "a;b";
const char* e = b + 3;