diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 4a13e3b..2b8a528 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -1132,7 +1132,13 @@ template constexpr uint64_t int_luts::min_safe_u64[]; template fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { - return int_luts<>::chdigit[static_cast(c)]; + using UnsignedUC = typename std::make_unsigned::type; + auto uc = static_cast(c); + // For types larger than one byte, we need to force an index with sentinel + // value (using index zero because that is easiest) if any byte other than + // the low byte is non-zero. + auto mask = static_cast(-((uc & ~0xFFull) == 0)); + return int_luts<>::chdigit[static_cast(uc & mask)]; } fastfloat_really_inline constexpr size_t max_digits_u64(int base) { diff --git a/tests/fast_int.cpp b/tests/fast_int.cpp index 9b107c8..49044d3 100644 --- a/tests/fast_int.cpp +++ b/tests/fast_int.cpp @@ -831,6 +831,275 @@ int main() { return EXIT_FAILURE; } } + // dont parse UTF-16 code units of emojis as int if low byte is ascii digit + { + const std::u16string emojis[] = { + u"ℹ", u"ℹ️", u"☸", u"☸️", u"☹", u"☹️", u"✳", u"✳️", + u"✴", u"✴️", u"⤴", u"⤴️", u"⤵", u"⤵️", u"〰", u"〰️", + }; + bool failed = false; + auto array_size = sizeof(emojis) / sizeof(emojis[0]); + for (size_t i = 0; i < array_size; i++) { + auto e = emojis[i]; + int foo; + auto answer = fast_float::from_chars(e.data(), e.data() + e.size(), foo); + if (answer.ec == std::errc()) { + failed = true; + std::cerr << "Incorrectly parsed emoji #" << i << " as integer " << foo + << "." << std::endl; + } + } + + if (failed) { + return EXIT_FAILURE; + } + } + // dont parse UTF-32 code points of emojis as int if low byte is ascii digit + { + const std::u32string emojis[] = { + U"ℹ", + U"ℹ️", + U"☸", + U"☸️", + U"☹", + U"☹️", + U"✳", + U"✳️", + U"✴", + U"✴️", + U"⤴", + U"⤴️", + U"⤵", + U"⤵️", + U"〰", + U"〰️", + U"🈲", + U"🈳", + U"🈴", + U"🈵", + U"🈶", + U"🈷", + U"🈷️", + U"🈸", + U"🈹", + U"🌰", + U"🌱", + U"🌲", + U"🌳", + U"🌴", + U"🌵", + U"🌶", + U"🌶️", + U"🌷", + U"🌸", + U"🌹", + U"🐰", + U"🐱", + U"🐲", + U"🐳", + U"🐴", + U"🐵", + U"🐶", + U"🐷", + U"🐸", + U"🐹", + U"🔰", + U"🔱", + U"🔲", + U"🔳", + U"🔴", + U"🔵", + U"🔶", + U"🔷", + U"🔸", + U"🔹", + U"😰", + U"😱", + U"😲", + U"😳", + U"😴", + U"😵", + U"😵‍💫", + U"😶", + U"😶‍🌫", + U"😶‍🌫️", + U"😷", + U"😸", + U"😹", + U"🤰", + U"🤰🏻", + U"🤰🏼", + U"🤰🏽", + U"🤰🏾", + U"🤰🏿", + U"🤱", + U"🤱🏻", + U"🤱🏼", + U"🤱🏽", + U"🤱🏾", + U"🤱🏿", + U"🤲", + U"🤲🏻", + U"🤲🏼", + U"🤲🏽", + U"🤲🏾", + U"🤲🏿", + U"🤳", + U"🤳🏻", + U"🤳🏼", + U"🤳🏽", + U"🤳🏾", + U"🤳🏿", + U"🤴", + U"🤴🏻", + U"🤴🏼", + U"🤴🏽", + U"🤴🏾", + U"🤴🏿", + U"🤵", + U"🤵‍♀", + U"🤵‍♀️", + U"🤵‍♂", + U"🤵‍♂️", + U"🤵🏻", + U"🤵🏻‍♀", + U"🤵🏻‍♀️", + U"🤵🏻‍♂", + U"🤵🏻‍♂️", + U"🤵🏼", + U"🤵🏼‍♀", + U"🤵🏼‍♀️", + U"🤵🏼‍♂", + U"🤵🏼‍♂️", + U"🤵🏽", + U"🤵🏽‍♀", + U"🤵🏽‍♀️", + U"🤵🏽‍♂", + U"🤵🏽‍♂️", + U"🤵🏾", + U"🤵🏾‍♀", + U"🤵🏾‍♀️", + U"🤵🏾‍♂", + U"🤵🏾‍♂️", + U"🤵🏿", + U"🤵🏿‍♀", + U"🤵🏿‍♀️", + U"🤵🏿‍♂", + U"🤵🏿‍♂️", + U"🤶", + U"🤶🏻", + U"🤶🏼", + U"🤶🏽", + U"🤶🏾", + U"🤶🏿", + U"🤷", + U"🤷‍♀", + U"🤷‍♀️", + U"🤷‍♂", + U"🤷‍♂️", + U"🤷🏻", + U"🤷🏻‍♀", + U"🤷🏻‍♀️", + U"🤷🏻‍♂", + U"🤷🏻‍♂️", + U"🤷🏼", + U"🤷🏼‍♀", + U"🤷🏼‍♀️", + U"🤷🏼‍♂", + U"🤷🏼‍♂️", + U"🤷🏽", + U"🤷🏽‍♀", + U"🤷🏽‍♀️", + U"🤷🏽‍♂", + U"🤷🏽‍♂️", + U"🤷🏾", + U"🤷🏾‍♀", + U"🤷🏾‍♀️", + U"🤷🏾‍♂", + U"🤷🏾‍♂️", + U"🤷🏿", + U"🤷🏿‍♀", + U"🤷🏿‍♀️", + U"🤷🏿‍♂", + U"🤷🏿‍♂️", + U"🤸", + U"🤸‍♀", + U"🤸‍♀️", + U"🤸‍♂", + U"🤸‍♂️", + U"🤸🏻", + U"🤸🏻‍♀", + U"🤸🏻‍♀️", + U"🤸🏻‍♂", + U"🤸🏻‍♂️", + U"🤸🏼", + U"🤸🏼‍♀", + U"🤸🏼‍♀️", + U"🤸🏼‍♂", + U"🤸🏼‍♂️", + U"🤸🏽", + U"🤸🏽‍♀", + U"🤸🏽‍♀️", + U"🤸🏽‍♂", + U"🤸🏽‍♂️", + U"🤸🏾", + U"🤸🏾‍♀", + U"🤸🏾‍♀️", + U"🤸🏾‍♂", + U"🤸🏾‍♂️", + U"🤸🏿", + U"🤸🏿‍♀", + U"🤸🏿‍♀️", + U"🤸🏿‍♂", + U"🤸🏿‍♂️", + U"🤹", + U"🤹‍♀", + U"🤹‍♀️", + U"🤹‍♂", + U"🤹‍♂️", + U"🤹🏻", + U"🤹🏻‍♀", + U"🤹🏻‍♀️", + U"🤹🏻‍♂", + U"🤹🏻‍♂️", + U"🤹🏼", + U"🤹🏼‍♀", + U"🤹🏼‍♀️", + U"🤹🏼‍♂", + U"🤹🏼‍♂️", + U"🤹🏽", + U"🤹🏽‍♀", + U"🤹🏽‍♀️", + U"🤹🏽‍♂", + U"🤹🏽‍♂️", + U"🤹🏾", + U"🤹🏾‍♀", + U"🤹🏾‍♀️", + U"🤹🏾‍♂", + U"🤹🏾‍♂️", + U"🤹🏿", + U"🤹🏿‍♀", + U"🤹🏿‍♀️", + U"🤹🏿‍♂", + U"🤹🏿‍♂️", + }; + bool failed = false; + auto array_size = sizeof(emojis) / sizeof(emojis[0]); + for (size_t i = 0; i < array_size; i++) { + auto e = emojis[i]; + int foo; + auto answer = fast_float::from_chars(e.data(), e.data() + e.size(), foo); + if (answer.ec == std::errc()) { + failed = true; + std::cerr << "Incorrectly parsed emoji #" << i << " as integer " << foo + << "." << std::endl; + } + } + + if (failed) { + return EXIT_FAILURE; + } + } return EXIT_SUCCESS; } @@ -842,4 +1111,4 @@ int main() { std::cerr << "The test requires C++17." << std::endl; return EXIT_SUCCESS; } -#endif \ No newline at end of file +#endif