From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1851) id D517C3851C06; Thu, 25 Jun 2020 10:08:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D517C3851C06 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1593079713; bh=Tg6Uu3aMbT0JNtUHdCMKBZVBzkCF+/4CHPptEeB2Bkc=; h=From:To:Subject:Date:From; b=fpQg+sR+T31ZsKGOShtLzN/XajdzWUB04cIEt8HwFYrN0/ucalGY2UvJExhq1fKCR N5fpe1MuuanwE+DZZLV/g8KYenKrTJNiUnWl3KEZD6Lvne4X3ECkYqik1Amq3FEl2/ MnQ6YsJ4KP69LCFNx/6rdqRqSpt4ud4j1hSc1CiQ= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Martin Liska To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc(refs/users/marxin/heads/slp-function-v5)] libstdc++: Fix std::from_chars to ignore leading zeros in base 2 X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/users/marxin/heads/slp-function-v5 X-Git-Oldrev: 25920dd18ad12ea501309b1487366e22f35db631 X-Git-Newrev: eb0ff770e29715deb8b2e6f5da736e0c1e8f8d07 Message-Id: <20200625100833.D517C3851C06@sourceware.org> Date: Thu, 25 Jun 2020 10:08:33 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 25 Jun 2020 10:08:33 -0000 https://gcc.gnu.org/g:eb0ff770e29715deb8b2e6f5da736e0c1e8f8d07 commit eb0ff770e29715deb8b2e6f5da736e0c1e8f8d07 Author: Jonathan Wakely Date: Wed Jun 24 11:45:01 2020 +0100 libstdc++: Fix std::from_chars to ignore leading zeros in base 2 The parser for binary numbers returned an error if the entire string contains more digits than the result type. Leading zeros should be ignored. libstdc++-v3/ChangeLog: * include/std/charconv (__from_chars_binary): Ignore leading zeros. * testsuite/20_util/from_chars/1.cc: Check "0x1" for all bases, not just 10 and 16. * testsuite/20_util/from_chars/3.cc: New test. Diff: --- libstdc++-v3/include/std/charconv | 8 ++- libstdc++-v3/testsuite/20_util/from_chars/1.cc | 19 +++++-- libstdc++-v3/testsuite/20_util/from_chars/3.cc | 79 ++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv index 8fbf64058ee..b725e5d2afd 100644 --- a/libstdc++-v3/include/std/charconv +++ b/libstdc++-v3/include/std/charconv @@ -417,7 +417,11 @@ namespace __detail static_assert(is_unsigned<_Tp>::value, "implementation bug"); const ptrdiff_t __len = __last - __first; - int __i = 0; + ptrdiff_t __i = 0; + while (__i < __len && __first[__i] == '0') + ++__i; + const ptrdiff_t __leading_zeroes = __i; + while (__i < __len) { const unsigned char __c = (unsigned)__first[__i] - '0'; @@ -428,7 +432,7 @@ namespace __detail __i++; } __first += __i; - return __i <= __detail::__int_limits<_Tp>::digits; + return (__i - __leading_zeroes) <= __detail::__int_limits<_Tp>::digits; } /// std::from_chars implementation for integers in bases 3 to 10. diff --git a/libstdc++-v3/testsuite/20_util/from_chars/1.cc b/libstdc++-v3/testsuite/20_util/from_chars/1.cc index 916025bc7c6..ad5d50e67b3 100644 --- a/libstdc++-v3/testsuite/20_util/from_chars/1.cc +++ b/libstdc++-v3/testsuite/20_util/from_chars/1.cc @@ -31,7 +31,8 @@ check_from_chars(I expected, std::string s, int base = 0, char term = '\0') std::from_chars_result r = base == 0 ? std::from_chars(begin, end, val) : std::from_chars(begin, end, val, base); - return r.ec == std::errc{} && (r.ptr == end || *r.ptr == term) && val == expected; + return r.ec == std::errc{} && (r.ptr == end || *r.ptr == term) + && val == expected; } #include @@ -52,10 +53,18 @@ void test02() { // "0x" parsed as "0" not as hex prefix: - VERIFY( check_from_chars(0, "0x1", 10, 'x') ); - VERIFY( check_from_chars(0, "0X1", 10, 'X') ); - VERIFY( check_from_chars(0, "0x1", 16, 'x') ); - VERIFY( check_from_chars(0, "0X1", 16, 'X') ); + for (int base = 2; base < 34; ++base) + { + VERIFY( check_from_chars(0, "0x1", base, 'x') ); + VERIFY( check_from_chars(0, "0X1", base, 'X') ); + } + + VERIFY( check_from_chars(1123, "0x1", 34) ); + VERIFY( check_from_chars(1123, "0X1", 34) ); + VERIFY( check_from_chars(1156, "0x1", 35) ); + VERIFY( check_from_chars(1156, "0X1", 35) ); + VERIFY( check_from_chars(1189, "0x1", 36) ); + VERIFY( check_from_chars(1189, "0X1", 36) ); VERIFY( check_from_chars(1155, "xx", 34) ); VERIFY( check_from_chars(1155, "XX", 34) ); diff --git a/libstdc++-v3/testsuite/20_util/from_chars/3.cc b/libstdc++-v3/testsuite/20_util/from_chars/3.cc new file mode 100644 index 00000000000..9d4a77f5c31 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/from_chars/3.cc @@ -0,0 +1,79 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-do run { target c++14 } } + +#include +#include +#include + +#ifdef DEBUG +#include +#endif + +long long +read(const char* first, const char* last, int base) +{ + long long val = 0; + long long place = 1; + while (last > first) + { + val += (*--last - '0') * place; + place *= base; + } + return val; +} + +void +test01() +{ + std::from_chars_result res; + long long val; + for (auto s : { "10001", "10010", "10011", "10101", "10110", "10111", + "11001", "11010", "11011", "11101", "11110", "11111" }) + { + std::string ss[2] = { s, std::string(64, '0') + s }; + for (const auto& str : ss) + { + const char* first = str.data(); + for (int base = 2; base < 37; ++base) + { + const char* last = str.data() + str.length(); + for (size_t n = 0; n < ss[0].length(); ++n) + { +#ifdef DEBUG + printf("Parsing \"%.*s\" in base %d\n", int(last - first), first, + base); +#endif + res = std::from_chars(first, last, val, base); + VERIFY( res.ptr == last ); + VERIFY( res.ec == std::errc{} ); + VERIFY( val == read(first, last, base) ); + // Test again with shorter string to check from_chars doesn't read + // the digits past the last pointer. + --last; + } + } + } + } +} + +int +main() +{ + test01(); +}