diff options
author | swarmer <swarmer@yandex-team.com> | 2024-10-16 03:27:14 +0300 |
---|---|---|
committer | swarmer <swarmer@yandex-team.com> | 2024-10-16 03:41:38 +0300 |
commit | 35c54372ef41e968a90908579c2fec61650af39e (patch) | |
tree | a5b5b61136ea8ac8e028ee6b933e5cbb29d7573e | |
parent | d9797921c7989ee196f79f8c738da5af4894007e (diff) | |
download | ydb-35c54372ef41e968a90908579c2fec61650af39e.tar.gz |
StringSplitter: recreate State after copy
commit_hash:75f3a4a20b797f07c51c63b96f0f1e1374707f33
-rw-r--r-- | util/string/split.h | 32 | ||||
-rw-r--r-- | util/string/split_ut.cpp | 26 |
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; |