diff --git a/include/icubaby/icubaby.hpp b/include/icubaby/icubaby.hpp index c0b40265..521ee5e8 100644 --- a/include/icubaby/icubaby.hpp +++ b/include/icubaby/icubaby.hpp @@ -1045,7 +1045,9 @@ class transcode_view::iterator { constexpr std::ranges::iterator_t const& base () const& noexcept { return current_; } constexpr std::ranges::iterator_t base () && { return std::move (current_); } - constexpr value_type const& operator* () const { return state_.front (); } + constexpr value_type const& operator* () const { + return state_.empty () ? replacement : state_.front (); + } constexpr std::ranges::iterator_t operator->() const { return state_.front (); } constexpr iterator& operator++ () { @@ -1085,6 +1087,7 @@ class transcode_view::iterator { private: std::ranges::iterator_t current_{}; transcode_view const* parent_ = nullptr; + static value_type const replacement = icubaby::replacement_char; class state { public: @@ -1117,6 +1120,11 @@ class transcode_view::iterator { mutable state state_{}; }; +template + requires std::ranges::view +transcode_view::iterator::value_type const +transcode_view::iterator::replacement; + template requires std::ranges::view constexpr std::ranges::iterator_t transcode_view::iterator::state::fill ( diff --git a/unittests/test_u8_32.cpp b/unittests/test_u8_32.cpp index 74b1485f..2d44aeda 100644 --- a/unittests/test_u8_32.cpp +++ b/unittests/test_u8_32.cpp @@ -277,8 +277,23 @@ TEST (Utf8To32, RangesCopy) { }; // clang-format on std::vector out32; - std::ranges::copy (in | icubaby::ranges::transcode, std::back_inserter (out32)); + auto const r = in | icubaby::ranges::transcode; + std::ranges::copy (r, std::back_inserter (out32)); EXPECT_THAT (out32, testing::ElementsAre (char32_t{0x3053}, char32_t{0x3093}, char32_t{0x306B}, char32_t{0x3061}, char32_t{0x306F}, char32_t{0x4E16}, char32_t{0x754C}, char32_t{0x000A})); + EXPECT_TRUE (r.well_formed()); } +TEST (Utf8To32, RangesBadInput) { + // clang-format off + std::vector const in{ + char8_t{0xF3}, char8_t{0x81}, + }; + // clang-format on + std::vector out32; + auto const r = in | icubaby::ranges::transcode; + std::ranges::copy (r, std::back_inserter (out32)); + EXPECT_THAT (out32, testing::ElementsAre (char32_t{icubaby::replacement_char})); + EXPECT_FALSE (r.well_formed()); +} + #endif // __cpp_lib_ranges