26JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4514 4996)
30 return (juce_wchar) towupper ((wint_t) character);
35 return (juce_wchar) towlower ((wint_t) character);
41 return iswupper ((wint_t) character) != 0;
43 return toLowerCase (character) != character;
50 return iswlower ((wint_t) character) != 0;
52 return toUpperCase (character) != character;
56JUCE_END_IGNORE_WARNINGS_MSVC
61 return character ==
' ' || (character <= 13 && character >= 9);
66 return iswspace ((wint_t) character) != 0;
71 return (character >=
'0' && character <=
'9');
76 return iswdigit ((wint_t) character) != 0;
81 return (character >=
'a' && character <=
'z')
82 || (character >=
'A' && character <=
'Z');
87 return iswalpha ((wint_t) character) != 0;
92 return (character >=
'a' && character <=
'z')
93 || (character >=
'A' && character <=
'Z')
94 || (character >=
'0' && character <=
'9');
99 return iswalnum ((wint_t) character) != 0;
104 return (character >=
' ' && character <=
'~');
109 return iswprint ((wint_t) character) != 0;
114 auto d = (
unsigned int) (digit -
'0');
116 if (d < (
unsigned int) 10)
119 d += (
unsigned int) (
'0' -
'a');
121 if (d < (
unsigned int) 6)
124 d += (
unsigned int) (
'a' -
'A');
126 if (d < (
unsigned int) 6)
132double CharacterFunctions::mulexp10 (
const double value,
int exponent)
noexcept
137 if (exactlyEqual (value, 0.0))
140 const bool negative = (exponent < 0);
143 exponent = -exponent;
145 double result = 1.0, power = 10.0;
147 for (
int bit = 1; exponent != 0; bit <<= 1)
149 if ((exponent & bit) != 0)
161 return negative ? (value / result) : (value * result);
166 if (c < 0x80 || c >= 0xa0)
167 return (juce_wchar) c;
169 static const uint16 lookup[] = { 0x20AC, 0x0007, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
170 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0007, 0x017D, 0x0007,
171 0x0007, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
172 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0007, 0x017E, 0x0178 };
174 return (juce_wchar) lookup[c - 0x80];
183#define STR(value) QUOTE(value)
184#define ASYM_CHARPTR_DOUBLE_PAIR(str, value) std::pair<const char*, double> (STR(str), value)
185#define CHARPTR_DOUBLE_PAIR(value) ASYM_CHARPTR_DOUBLE_PAIR(value, value)
186#define CHARPTR_DOUBLE_PAIR_COMBOS(value) \
187 CHARPTR_DOUBLE_PAIR(value), \
188 CHARPTR_DOUBLE_PAIR(-value), \
189 ASYM_CHARPTR_DOUBLE_PAIR(+value, value), \
190 ASYM_CHARPTR_DOUBLE_PAIR(000000 ## value, value), \
191 ASYM_CHARPTR_DOUBLE_PAIR(+000 ## value, value), \
192 ASYM_CHARPTR_DOUBLE_PAIR(-0 ## value, -value)
194namespace characterFunctionsTests
197template <
typename CharPo
interType>
198MemoryBlock memoryBlockFromCharPtr (
const typename CharPointerType::CharType* charPtr)
200 using CharType =
typename CharPointerType::CharType;
203 CharPointerType source (charPtr);
205 result.
setSize (CharPointerType::getBytesRequiredFor (source) +
sizeof (CharType));
206 CharPointerType dest { (CharType*) result.
getData() };
207 dest.writeAll (source);
211template <
typename FromCharPo
interType,
typename ToCharPo
interType>
212MemoryBlock convert (
const MemoryBlock& source,
bool removeNullTerminator =
false)
214 using ToCharType =
typename ToCharPointerType ::CharType;
215 using FromCharType =
typename FromCharPointerType::CharType;
217 FromCharPointerType sourcePtr { (FromCharType*) source.getData() };
219 std::vector<juce_wchar> sourceChars;
220 size_t requiredSize = 0;
223 while ((c = sourcePtr.getAndAdvance()) !=
'\0')
225 requiredSize += ToCharPointerType::getBytesRequiredFor (c);
226 sourceChars.push_back (c);
229 if (! removeNullTerminator)
230 requiredSize +=
sizeof (ToCharType);
235 ToCharPointerType dest { (ToCharType*) result.getData() };
237 for (
auto wc : sourceChars)
240 if (! removeNullTerminator)
246struct SeparatorStrings
248 std::vector<MemoryBlock> terminals, nulls;
251template <
typename CharPo
interType>
252SeparatorStrings getSeparators()
259SeparatorStrings getSeparators<CharPointer_ASCII>()
261 SeparatorStrings result;
263 const CharPointer_ASCII::CharType* terminalCharPtrs[] = {
264 "",
"-",
"+",
"e",
"e+",
"E-",
"f",
" ",
",",
";",
"<",
"'",
"\"",
"_",
"k",
265 " +",
" -",
" -e",
"-In ",
" +n",
"n",
" r"
268 for (
auto ptr : terminalCharPtrs)
269 result.terminals.push_back (memoryBlockFromCharPtr<CharPointer_ASCII> (ptr));
271 const CharPointer_ASCII::CharType* nullCharPtrs[] = {
"." };
273 result.nulls = result.terminals;
275 for (
auto ptr : nullCharPtrs)
276 result.nulls.push_back (memoryBlockFromCharPtr<CharPointer_ASCII> (ptr));
282SeparatorStrings getSeparators<CharPointer_UTF8>()
284 auto result = getSeparators<CharPointer_ASCII>();
286 const CharPointer_UTF8::CharType* terminalCharPtrs[] = {
290 "\xf0\x9f\x8f\x81\xF0\x9F\x9A\x97"
293 for (
auto ptr : terminalCharPtrs)
295 auto block = memoryBlockFromCharPtr<CharPointer_UTF8> (ptr);
297 for (
auto vec : { &result.terminals, &result.nulls })
298 vec->push_back (block);
304template <
typename CharPo
interType,
typename StorageType>
305SeparatorStrings prefixWithAsciiSeparators (
const std::vector<std::vector<StorageType>>& terminalCharPtrs)
307 auto asciiSeparators = getSeparators<CharPointer_ASCII>();
309 SeparatorStrings result;
311 for (
const auto& block : asciiSeparators.terminals)
312 result.terminals.push_back (convert<CharPointer_ASCII, CharPointerType> (block));
314 for (
const auto& block : asciiSeparators.nulls)
315 result.nulls.push_back (convert<CharPointer_ASCII, CharPointerType> (block));
317 for (
auto& t : terminalCharPtrs)
319 const auto block = memoryBlockFromCharPtr<CharPointerType> ((
typename CharPointerType::CharType*) t.data());
321 for (
auto vec : { &result.terminals, &result.nulls })
322 vec->push_back (block);
329SeparatorStrings getSeparators<CharPointer_UTF16>()
331 const std::vector<std::vector<char16_t>> terminalCharPtrs {
335 { 0xd801, 0xdc37, 0x0 },
336 { 0x0065, 0xd83d, 0xde03, 0x0 },
337 { 0xd83c, 0xdfc1, 0xd83d, 0xde97, 0x0 }
340 return prefixWithAsciiSeparators<CharPointer_UTF16> (terminalCharPtrs);
344SeparatorStrings getSeparators<CharPointer_UTF32>()
346 const std::vector<std::vector<char32_t>> terminalCharPtrs = {
350 { 0x00000065, 0x0001f603, 0x0 },
351 { 0x0001f3c1, 0x0001f697, 0x0 }
354 return prefixWithAsciiSeparators<CharPointer_UTF32> (terminalCharPtrs);
357template <
typename TestFunction>
358void withAllPrefixesAndSuffixes (
const std::vector<MemoryBlock>& prefixes,
359 const std::vector<MemoryBlock>& suffixes,
360 const std::vector<MemoryBlock>& testValues,
363 for (
const auto& prefix : prefixes)
365 for (
const auto& testValue : testValues)
367 MemoryBlock testBlock = prefix;
368 testBlock.append (testValue.getData(), testValue.getSize());
370 for (
const auto& suffix : suffixes)
372 MemoryBlock data = testBlock;
373 data.append (suffix.getData(), suffix.getSize());
381template <
typename CharPo
interType>
382class CharacterFunctionsTests final :
public UnitTest
385 using CharType =
typename CharPointerType::CharType;
387 CharacterFunctionsTests()
388 : UnitTest (
"CharacterFunctions", UnitTestCategories::text)
391 void runTest()
override
393 beginTest (
"readDoubleValue");
395 const std::pair<const char*, double> trials[] =
398 CHARPTR_DOUBLE_PAIR_COMBOS (0),
399 CHARPTR_DOUBLE_PAIR_COMBOS (3),
400 CHARPTR_DOUBLE_PAIR_COMBOS (4931),
401 CHARPTR_DOUBLE_PAIR_COMBOS (5000),
402 CHARPTR_DOUBLE_PAIR_COMBOS (9862097),
405 CHARPTR_DOUBLE_PAIR_COMBOS (0.),
406 CHARPTR_DOUBLE_PAIR_COMBOS (9.),
407 CHARPTR_DOUBLE_PAIR_COMBOS (7.000),
408 CHARPTR_DOUBLE_PAIR_COMBOS (0.2),
409 CHARPTR_DOUBLE_PAIR_COMBOS (.298630),
410 CHARPTR_DOUBLE_PAIR_COMBOS (1.118),
411 CHARPTR_DOUBLE_PAIR_COMBOS (0.9000),
412 CHARPTR_DOUBLE_PAIR_COMBOS (0.0000001),
413 CHARPTR_DOUBLE_PAIR_COMBOS (500.0000001),
414 CHARPTR_DOUBLE_PAIR_COMBOS (9862098.2398604),
417 CHARPTR_DOUBLE_PAIR_COMBOS (0e0),
418 CHARPTR_DOUBLE_PAIR_COMBOS (0.e0),
419 CHARPTR_DOUBLE_PAIR_COMBOS (0.00000e0),
420 CHARPTR_DOUBLE_PAIR_COMBOS (.0e7),
421 CHARPTR_DOUBLE_PAIR_COMBOS (0e-5),
422 CHARPTR_DOUBLE_PAIR_COMBOS (2E0),
423 CHARPTR_DOUBLE_PAIR_COMBOS (4.E0),
424 CHARPTR_DOUBLE_PAIR_COMBOS (1.2000000E0),
425 CHARPTR_DOUBLE_PAIR_COMBOS (1.2000000E6),
426 CHARPTR_DOUBLE_PAIR_COMBOS (.398e3),
427 CHARPTR_DOUBLE_PAIR_COMBOS (10e10),
428 CHARPTR_DOUBLE_PAIR_COMBOS (1.4962e+2),
429 CHARPTR_DOUBLE_PAIR_COMBOS (3198693.0973e4),
430 CHARPTR_DOUBLE_PAIR_COMBOS (10973097.2087E-4),
431 CHARPTR_DOUBLE_PAIR_COMBOS (1.3986e00006),
432 CHARPTR_DOUBLE_PAIR_COMBOS (2087.3087e+00006),
433 CHARPTR_DOUBLE_PAIR_COMBOS (6.0872e-00006),
435 CHARPTR_DOUBLE_PAIR_COMBOS (1.7976931348623157e+308),
436 CHARPTR_DOUBLE_PAIR_COMBOS (2.2250738585072014e-308),
440 CHARPTR_DOUBLE_PAIR_COMBOS (17654321098765432.9),
441 CHARPTR_DOUBLE_PAIR_COMBOS (183456789012345678.9),
442 CHARPTR_DOUBLE_PAIR_COMBOS (1934567890123456789.9),
443 CHARPTR_DOUBLE_PAIR_COMBOS (20345678901234567891.9),
444 CHARPTR_DOUBLE_PAIR_COMBOS (10000000000000000303786028427003666890752.000000),
445 CHARPTR_DOUBLE_PAIR_COMBOS (10000000000000000303786028427003666890752e3),
446 CHARPTR_DOUBLE_PAIR_COMBOS (10000000000000000303786028427003666890752e100),
447 CHARPTR_DOUBLE_PAIR_COMBOS (10000000000000000303786028427003666890752.000000e-5),
448 CHARPTR_DOUBLE_PAIR_COMBOS (10000000000000000303786028427003666890752.000005e-40),
450 CHARPTR_DOUBLE_PAIR_COMBOS (1.23456789012345678901234567890),
451 CHARPTR_DOUBLE_PAIR_COMBOS (1.23456789012345678901234567890e-111),
454 auto asciiToMemoryBlock = [] (
const char* asciiPtr,
bool removeNullTerminator)
456 auto block = memoryBlockFromCharPtr<CharPointer_ASCII> (asciiPtr);
457 return convert<CharPointer_ASCII, CharPointerType> (block, removeNullTerminator);
460 const auto separators = getSeparators<CharPointerType>();
462 for (
const auto& trial : trials)
464 for (
const auto& terminal : separators.terminals)
466 MemoryBlock data { asciiToMemoryBlock (trial.first,
true) };
467 data.append (terminal.getData(), terminal.getSize());
469 CharPointerType charPtr { (CharType*) data.getData() };
470 expectEquals (CharacterFunctions::readDoubleValue (charPtr), trial.second);
471 expect (*charPtr == *(CharPointerType ((CharType*) terminal.getData())));
475 auto asciiToMemoryBlocks = [&] (
const std::vector<const char*>& asciiPtrs,
bool removeNullTerminator)
477 std::vector<MemoryBlock> result;
479 for (
auto* ptr : asciiPtrs)
480 result.push_back (asciiToMemoryBlock (ptr, removeNullTerminator));
485 std::vector<const char*> prefixCharPtrs = {
"" ,
"+",
"-" };
486 const auto prefixes = asciiToMemoryBlocks (prefixCharPtrs,
true);
489 std::vector<const char*> nanCharPtrs = {
"NaN",
"nan",
"NAN",
"naN" };
490 auto nans = asciiToMemoryBlocks (nanCharPtrs,
true);
492 withAllPrefixesAndSuffixes (prefixes, separators.terminals, nans, [
this] (
const MemoryBlock& data,
493 const MemoryBlock& suffix)
495 CharPointerType charPtr { (CharType*) data.getData() };
496 expect (std::isnan (CharacterFunctions::readDoubleValue (charPtr)));
497 expect (*charPtr == *(CharPointerType ((CharType*) suffix.getData())));
502 std::vector<const char*> infCharPtrs = {
"Inf",
"inf",
"INF",
"InF",
"1.0E1024",
"1.23456789012345678901234567890e123456789" };
503 auto infs = asciiToMemoryBlocks (infCharPtrs,
true);
505 withAllPrefixesAndSuffixes (prefixes, separators.terminals, infs, [
this] (
const MemoryBlock& data,
506 const MemoryBlock& suffix)
508 CharPointerType charPtr { (CharType*) data.getData() };
509 auto expected = charPtr[0] ==
'-' ? -std::numeric_limits<double>::infinity()
510 : std::numeric_limits<double>::infinity();
511 expectEquals (CharacterFunctions::readDoubleValue (charPtr), expected);
512 expect (*charPtr == *(CharPointerType ((CharType*) suffix.getData())));
517 std::vector<const char*> zeroCharPtrs = {
"1.0E-400",
"1.23456789012345678901234567890e-123456789" };
518 auto zeros = asciiToMemoryBlocks (zeroCharPtrs,
true);
520 withAllPrefixesAndSuffixes (prefixes, separators.terminals, zeros, [
this] (
const MemoryBlock& data,
521 const MemoryBlock& suffix)
523 CharPointerType charPtr { (CharType*) data.getData() };
524 auto expected = charPtr[0] ==
'-' ? -0.0 : 0.0;
525 expectEquals (CharacterFunctions::readDoubleValue (charPtr), expected);
526 expect (*charPtr == *(CharPointerType ((CharType*) suffix.getData())));
531 for (
const auto& n : separators.nulls)
533 MemoryBlock data { n.getData(), n.getSize() };
534 CharPointerType charPtr { (CharType*) data.getData() };
536 expect (charPtr == CharPointerType { (CharType*) data.getData() }.findEndOfWhitespace());
542static CharacterFunctionsTests<CharPointer_ASCII> characterFunctionsTestsAscii;
543static CharacterFunctionsTests<CharPointer_UTF8> characterFunctionsTestsUtf8;
544static CharacterFunctionsTests<CharPointer_UTF16> characterFunctionsTestsUtf16;
545static CharacterFunctionsTests<CharPointer_UTF32> characterFunctionsTestsUtf32;
static juce_wchar toLowerCase(juce_wchar character) noexcept
static bool isDigit(char character) noexcept
static bool isLowerCase(juce_wchar character) noexcept
static bool isLetter(char character) noexcept
static bool isWhitespace(char character) noexcept
static double readDoubleValue(CharPointerType &text) noexcept
static int getHexDigitValue(juce_wchar digit) noexcept
static bool isLetterOrDigit(char character) noexcept
static bool isUpperCase(juce_wchar character) noexcept
static bool isPrintable(char character) noexcept
static juce_wchar getUnicodeCharFromWindows1252Codepage(uint8 windows1252Char) noexcept
void * getData() noexcept
void setSize(size_t newSize, bool initialiseNewSpaceToZero=false)