llvm.org GIT mirror llvm / 6069e66
[ADT] Replace std::isprint by llvm::isPrint. The standard library functions ::isprint/std::isprint have platform- and locale-dependent behavior which makes LLVM's output less predictable. In particular, regression tests my fail depending on the implementation of these functions. Implement llvm::isPrint in StringExtras.h with a standard behavior and replace all uses of ::isprint/std::isprint by a call it llvm::isPrint. The function is inlined and does not look up language settings so it should perform better than the standard library's version. Such a replacement has already been done for isdigit, isalpha, isxdigit in r314883. gtest does the same in gtest-printers.cc using the following justification: // Returns true if c is a printable ASCII character. We test the // value of c directly instead of calling isprint(), which is buggy on // Windows Mobile. inline bool IsPrintableAscii(wchar_t c) { return 0x20 <= c && c <= 0x7E; } Similar issues have also been encountered by Julia: https://github.com/JuliaLang/julia/issues/7416 I noticed the problem myself when on Windows isprint('\t') started to evaluate to true (see https://stackoverflow.com/questions/51435249) and thus caused several unit tests to fail. The result of isprint doesn't seem to be well-defined even for ASCII characters. Therefore I suggest to replace isprint by a platform-independent version. Differential Revision: https://reviews.llvm.org/D49680 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@338034 91177308-0d34-0410-b5e6-96231b3b80d8 Michael Kruse 1 year, 10 months ago
11 changed file(s) with 40 addition(s) and 13 deletion(s). Raw diff Collapse all Expand all
9696 if (LLVM_UNLIKELY(!isASCII(C)))
9797 return false;
9898 return true;
99 }
100
101 /// Checks whether character \p C is printable.
102 ///
103 /// Locale-independent version of the C standard library isprint whose results
104 /// may differ on different platforms.
105 inline bool isPrint(char C) {
106 unsigned char UC = static_cast(C);
107 return (0x20 <= UC) && (UC <= 0x7E);
99108 }
100109
101110 /// Returns the corresponding lowercase character if \p x is uppercase.
219219 raw_ostream &write_uuid(const uuid_t UUID);
220220
221221 /// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't
222 /// satisfy std::isprint into an escape sequence.
222 /// satisfy llvm::isPrint into an escape sequence.
223223 raw_ostream &write_escaped(StringRef Str, bool UseHexEscapes = false);
224224
225225 raw_ostream &write(unsigned char C);
814814 continue;
815815 }
816816
817 if (isprint((unsigned char)C)) {
817 if (isPrint((unsigned char)C)) {
818818 OS << (char)C;
819819 continue;
820820 }
128128 StringRef buffer = Buffer.getBufferStart();
129129 return count == 0 ||
130130 std::all_of(buffer.begin(), buffer.begin() + count,
131 [](char c) { return ::isprint(c) || ::isspace(c); });
131 [](char c) { return isPrint(c) || ::isspace(c); });
132132 }
133133
134134 // Read the profile variant flag from the header: ":FE" means this is a FE
6060 void llvm::printEscapedString(StringRef Name, raw_ostream &Out) {
6161 for (unsigned i = 0, e = Name.size(); i != e; ++i) {
6262 unsigned char C = Name[i];
63 if (isprint(C) && C != '\\' && C != '"')
63 if (isPrint(C) && C != '\\' && C != '"')
6464 Out << C;
6565 else
6666 Out << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
159159 *this << '\\' << '"';
160160 break;
161161 default:
162 if (std::isprint(c)) {
162 if (isPrint(c)) {
163163 *this << c;
164164 break;
165165 }
435435
436436 // Print the ASCII char values for each byte on this line
437437 for (uint8_t Byte : Line) {
438 if (isprint(Byte))
438 if (isPrint(Byte))
439439 *this << static_cast(Byte);
440440 else
441441 *this << '.';
10121012 {
10131013 static char pbuf[10];
10141014
1015 if (isprint(ch) || ch == ' ')
1015 if (isPrint(ch) || ch == ' ')
10161016 (void)snprintf(pbuf, sizeof pbuf, "%c", ch);
10171017 else
10181018 (void)snprintf(pbuf, sizeof pbuf, "\\%o", ch);
698698 std::string Str;
699699 bool ArrayIsPrintable = true;
700700 for (unsigned j = i - 1, je = Record.size(); j != je; ++j) {
701 if (!isprint(static_cast(Record[j]))) {
701 if (!isPrint(static_cast(Record[j]))) {
702702 ArrayIsPrintable = false;
703703 break;
704704 }
718718 } else {
719719 bool BlobIsPrintable = true;
720720 for (unsigned i = 0, e = Blob.size(); i != e; ++i)
721 if (!isprint(static_cast(Blob[i]))) {
721 if (!isPrint(static_cast(Blob[i]))) {
722722 BlobIsPrintable = false;
723723 break;
724724 }
16501650 }
16511651 Byte = Bytes.slice(Index)[0];
16521652 outs() << format(" %02x", Byte);
1653 AsciiData[NumBytes] = isprint(Byte) ? Byte : '.';
1653 AsciiData[NumBytes] = isPrint(Byte) ? Byte : '.';
16541654
16551655 uint8_t IndentOffset = 0;
16561656 NumBytes++;
18981898 // Print ascii.
18991899 outs() << " ";
19001900 for (std::size_t i = 0; i < 16 && addr + i < end; ++i) {
1901 if (std::isprint(static_cast(Contents[addr + i]) & 0xFF))
1901 if (isPrint(static_cast(Contents[addr + i]) & 0xFF))
19021902 outs() << Contents[addr + i];
19031903 else
19041904 outs() << ".";
2828
2929 static void printAsPrintable(raw_ostream &W, const uint8_t *Start, size_t Len) {
3030 for (size_t i = 0; i < Len; i++)
31 W << (isprint(Start[i]) ? static_cast(Start[i]) : '.');
31 W << (isPrint(Start[i]) ? static_cast(Start[i]) : '.');
3232 }
3333
3434 static Expected
137137
138138 TmpSecPtr = SecPtr;
139139 for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i)
140 W.startLine() << (isprint(TmpSecPtr[i]) ? static_cast(TmpSecPtr[i])
140 W.startLine() << (isPrint(TmpSecPtr[i]) ? static_cast(TmpSecPtr[i])
141141 : '.');
142142
143143 W.startLine() << '\n';
1111 #include "gtest/gtest.h"
1212
1313 using namespace llvm;
14
15 TEST(StringExtrasTest, isPrint) {
16 EXPECT_FALSE(isPrint('\0'));
17 EXPECT_FALSE(isPrint('\t'));
18 EXPECT_TRUE(isPrint('0'));
19 EXPECT_TRUE(isPrint('a'));
20 EXPECT_TRUE(isPrint('A'));
21 EXPECT_TRUE(isPrint(' '));
22 EXPECT_TRUE(isPrint('~'));
23 EXPECT_TRUE(isPrint('?'));
24 }
1425
1526 TEST(StringExtrasTest, Join) {
1627 std::vector Items;
92103 EXPECT_EQ("abcdefg01234.,&!~`'}\"", OS.str());
93104 }
94105
106 TEST(StringExtrasTest, printEscapedString) {
107 std::string str;
108 raw_string_ostream OS(str);
109 printEscapedString("ABCdef123&<>\\\"'\t", OS);
110 EXPECT_EQ("ABCdef123&<>\\5C\\22'\\09", OS.str());
111 }
112
95113 TEST(StringExtrasTest, printHTMLEscaped) {
96114 std::string str;
97115 raw_string_ostream OS(str);