diff --git a/include/boost/parser/detail/text/algorithm.hpp b/include/boost/parser/detail/text/algorithm.hpp index d1b58e8f..9f22affb 100644 --- a/include/boost/parser/detail/text/algorithm.hpp +++ b/include/boost/parser/detail/text/algorithm.hpp @@ -325,6 +325,8 @@ namespace boost::parser::detail { namespace text { if (detail::next(first2) == last2) { auto const it = parser::detail::text::find(first1, last1, *first2); + if (it == last1) + return {it, it}; return {it, detail::next(it)}; } diff --git a/include/boost/parser/parser.hpp b/include/boost/parser/parser.hpp index f4951b8c..da3b18d7 100644 --- a/include/boost/parser/parser.hpp +++ b/include/boost/parser/parser.hpp @@ -1479,7 +1479,8 @@ namespace boost { namespace parser { char32_t operator*() const { return folded_[idx_]; } no_case_iter & operator++() { - if (last_idx_ <= ++idx_) { + ++idx_; + if (last_idx_ <= idx_) { ++it_; fold(); } @@ -1508,6 +1509,7 @@ namespace boost { namespace parser { idx_ = 0; if (it_ == last_) { folded_[0] = 0; + last_idx_ = 1; return; } auto const folded_last = diff --git a/test/no_case.cpp b/test/no_case.cpp index 94fbc9d6..3ba51842 100644 --- a/test/no_case.cpp +++ b/test/no_case.cpp @@ -125,9 +125,10 @@ TEST(no_case, match_any_within_string) EXPECT_TRUE(*result == U's'); } { + // Non-Unicode parsing fails to match, since 'ß' is not treated as a + // single character. auto const result = parse("s", _trasse_p); - EXPECT_TRUE(result); - EXPECT_EQ(*result, 's'); + EXPECT_FALSE(result); } { auto const result = parse(U"S", _trasse_p); @@ -136,8 +137,7 @@ TEST(no_case, match_any_within_string) } { auto const result = parse("S", _trasse_p); - EXPECT_TRUE(result); - EXPECT_EQ(*result, 'S'); + EXPECT_FALSE(result); } { auto const result = parse(U"t", _trasse_p); @@ -159,6 +159,10 @@ TEST(no_case, match_any_within_string) EXPECT_TRUE(result); EXPECT_EQ(*result, 'T'); } + { + auto const result = parse("X", _trasse_p); + EXPECT_FALSE(result); + } } constexpr auto capital_sharp_s = u8"ẞ"; // U+1E9E @@ -304,6 +308,51 @@ TEST(no_case, detail_no_case_iter) EXPECT_EQ(folded, "sss"); EXPECT_TRUE(first.base() == detail::text::null_sentinel); } + { + auto const street = U"Straße"; + std::string folded; + auto const first_const = + detail::no_case_iter(street, detail::text::null_sentinel); + auto first = first_const; + while (first != detail::text::null_sentinel) { + folded.push_back(*first); + ++first; + } + EXPECT_EQ(folded, "strasse"); + EXPECT_TRUE(first.base() == detail::text::null_sentinel); + + first = first_const; + std::u32string_view const sv = U"strasse"; + auto mismatches = detail::text::mismatch( + first, detail::text::null_sentinel, sv.begin(), sv.end()); + EXPECT_TRUE(mismatches.first == detail::text::null_sentinel); + EXPECT_TRUE(mismatches.second == sv.end()); + + { + first = first_const; + auto search_result = detail::text::search( + first, detail::text::null_sentinel, sv.begin(), sv.end()); + EXPECT_TRUE(search_result.begin() == first); + EXPECT_TRUE(search_result.end() == detail::text::null_sentinel); + } + + { + first = first_const; + auto search_result = detail::text::search( + sv.begin(), sv.end(), first, detail::text::null_sentinel); + EXPECT_TRUE(search_result.begin() == sv.begin()); + EXPECT_TRUE(search_result.end() == sv.end()); + } + + { + detail::case_fold_array_t folded_char; + auto folded_last = detail::case_fold('X', folded_char.begin()); + auto search_result = detail::text::search( + sv.begin(), sv.end(), folded_char.begin(), folded_last); + EXPECT_TRUE(search_result.begin() == sv.end()); + EXPECT_TRUE(search_result.end() == sv.end()); + } + } } TEST(no_case, detail_no_case_mismatch)