1 // Written in the D programming language. 2 3 /++ 4 Functions which operate on ASCII characters. 5 6 All of the functions in std.ascii accept Unicode characters but 7 effectively ignore them if they're not ASCII. All `isX` functions return 8 `false` for non-ASCII characters, and all `toX` functions do nothing 9 to non-ASCII characters. 10 11 For functions which operate on Unicode characters, see 12 $(MREF std, uni). 13 14 $(SCRIPT inhibitQuickIndex = 1;) 15 $(DIVC quickindex, 16 $(BOOKTABLE, 17 $(TR $(TH Category) $(TH Functions)) 18 $(TR $(TD Validation) $(TD 19 $(LREF isAlpha) 20 $(LREF isAlphaNum) 21 $(LREF isASCII) 22 $(LREF isControl) 23 $(LREF isDigit) 24 $(LREF isGraphical) 25 $(LREF isHexDigit) 26 $(LREF isLower) 27 $(LREF isOctalDigit) 28 $(LREF isPrintable) 29 $(LREF isPunctuation) 30 $(LREF isUpper) 31 $(LREF isWhite) 32 )) 33 $(TR $(TD Conversions) $(TD 34 $(LREF toLower) 35 $(LREF toUpper) 36 )) 37 $(TR $(TD Constants) $(TD 38 $(LREF digits) 39 $(LREF fullHexDigits) 40 $(LREF hexDigits) 41 $(LREF letters) 42 $(LREF lowercase) 43 $(LREF lowerHexDigits) 44 $(LREF newline) 45 $(LREF octalDigits) 46 $(LREF uppercase) 47 $(LREF whitespace) 48 )) 49 $(TR $(TD Enums) $(TD 50 $(LREF ControlChar) 51 $(LREF LetterCase) 52 )) 53 )) 54 References: 55 $(LINK2 http://www.digitalmars.com/d/ascii-table.html, ASCII Table), 56 $(HTTP en.wikipedia.org/wiki/Ascii, Wikipedia) 57 58 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 59 Authors: $(HTTP digitalmars.com, Walter Bright) and 60 $(HTTP jmdavisprog.com, Jonathan M Davis) 61 Source: $(PHOBOSSRC std/ascii.d) 62 +/ 63 module std.ascii; 64 65 immutable fullHexDigits = "0123456789ABCDEFabcdef"; /// 0 .. 9A .. Fa .. f 66 immutable hexDigits = fullHexDigits[0 .. 16]; /// 0 .. 9A .. F 67 immutable lowerHexDigits = "0123456789abcdef"; /// 0 .. 9a .. f 68 immutable digits = hexDigits[0 .. 10]; /// 0 .. 9 69 immutable octalDigits = digits[0 .. 8]; /// 0 .. 7 70 immutable letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; /// A .. Za .. z 71 immutable uppercase = letters[0 .. 26]; /// A .. Z 72 immutable lowercase = letters[26 .. 52]; /// a .. z 73 immutable whitespace = " \t\v\r\n\f"; /// ASCII _whitespace 74 75 /++ 76 Letter case specifier. 77 +/ 78 enum LetterCase : bool 79 { 80 upper, /// Upper case letters 81 lower /// Lower case letters 82 } 83 84 /// 85 @safe unittest 86 { 87 import std.conv : to; 88 89 assert(42.to!string(16, LetterCase.upper) == "2A"); 90 assert(42.to!string(16, LetterCase.lower) == "2a"); 91 } 92 93 /// 94 @safe unittest 95 { 96 import std.digest.hmac : hmac; 97 import std.digest : toHexString; 98 import std.digest.sha : SHA1; 99 import std.string : representation; 100 101 const sha1HMAC = "A very long phrase".representation 102 .hmac!SHA1("secret".representation) 103 .toHexString!(LetterCase.lower); 104 assert(sha1HMAC == "49f2073c7bf58577e8c9ae59fe8cfd37c9ab94e5"); 105 } 106 107 /++ 108 All control characters in the ASCII table ($(HTTPS www.asciitable.com, source)). 109 +/ 110 enum ControlChar : char 111 { 112 nul = '\x00', /// Null 113 soh = '\x01', /// Start of heading 114 stx = '\x02', /// Start of text 115 etx = '\x03', /// End of text 116 eot = '\x04', /// End of transmission 117 enq = '\x05', /// Enquiry 118 ack = '\x06', /// Acknowledge 119 bel = '\x07', /// Bell 120 bs = '\x08', /// Backspace 121 tab = '\x09', /// Horizontal tab 122 lf = '\x0A', /// NL line feed, new line 123 vt = '\x0B', /// Vertical tab 124 ff = '\x0C', /// NP form feed, new page 125 cr = '\x0D', /// Carriage return 126 so = '\x0E', /// Shift out 127 si = '\x0F', /// Shift in 128 dle = '\x10', /// Data link escape 129 dc1 = '\x11', /// Device control 1 130 dc2 = '\x12', /// Device control 2 131 dc3 = '\x13', /// Device control 3 132 dc4 = '\x14', /// Device control 4 133 nak = '\x15', /// Negative acknowledge 134 syn = '\x16', /// Synchronous idle 135 etb = '\x17', /// End of transmission block 136 can = '\x18', /// Cancel 137 em = '\x19', /// End of medium 138 sub = '\x1A', /// Substitute 139 esc = '\x1B', /// Escape 140 fs = '\x1C', /// File separator 141 gs = '\x1D', /// Group separator 142 rs = '\x1E', /// Record separator 143 us = '\x1F', /// Unit separator 144 del = '\x7F' /// Delete 145 } 146 147 /// 148 @safe pure nothrow @nogc unittest 149 { 150 import std.algorithm.comparison, std.algorithm.searching, std.range, std.traits; 151 152 // Because all ASCII characters fit in char, so do these 153 static assert(ControlChar.ack.sizeof == 1); 154 155 // All control characters except del are in row starting from 0 156 static assert(EnumMembers!ControlChar.only.until(ControlChar.del).equal(iota(32))); 157 158 static assert(ControlChar.nul == '\0'); 159 static assert(ControlChar.bel == '\a'); 160 static assert(ControlChar.bs == '\b'); 161 static assert(ControlChar.ff == '\f'); 162 static assert(ControlChar.lf == '\n'); 163 static assert(ControlChar.cr == '\r'); 164 static assert(ControlChar.tab == '\t'); 165 static assert(ControlChar.vt == '\v'); 166 } 167 168 /// 169 @safe pure nothrow unittest 170 { 171 import std.conv; 172 //Control character table can be used in place of hexcodes. 173 with (ControlChar) assert(text("Phobos", us, "Deimos", us, "Tango", rs) == "Phobos\x1FDeimos\x1FTango\x1E"); 174 } 175 176 /// Newline sequence for this system. 177 version (Windows) 178 immutable newline = "\r\n"; 179 else version (Posix) 180 immutable newline = "\n"; 181 else 182 static assert(0, "Unsupported OS"); 183 184 185 /++ 186 Params: c = The character to test. 187 Returns: Whether `c` is a letter or a number (0 .. 9, a .. z, A .. Z). 188 +/ 189 pragma(inline, true) 190 bool isAlphaNum(dchar c) @safe pure nothrow @nogc 191 { 192 const hc = c | 0x20; 193 return ('0' <= c && c <= '9') || ('a' <= hc && hc <= 'z'); 194 } 195 196 /// 197 @safe pure nothrow @nogc unittest 198 { 199 assert( isAlphaNum('A')); 200 assert( isAlphaNum('1')); 201 assert(!isAlphaNum('#')); 202 203 // N.B.: does not return true for non-ASCII Unicode alphanumerics: 204 assert(!isAlphaNum('á')); 205 } 206 207 @safe unittest 208 { 209 import std.range; 210 foreach (c; chain(digits, octalDigits, fullHexDigits, letters, lowercase, uppercase)) 211 assert(isAlphaNum(c)); 212 213 foreach (c; whitespace) 214 assert(!isAlphaNum(c)); 215 } 216 217 218 /++ 219 Params: c = The character to test. 220 Returns: Whether `c` is an ASCII letter (A .. Z, a .. z). 221 +/ 222 pragma(inline, true) 223 bool isAlpha(dchar c) @safe pure nothrow @nogc 224 { 225 // Optimizer can turn this into a bitmask operation on 64 bit code 226 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); 227 } 228 229 /// 230 @safe pure nothrow @nogc unittest 231 { 232 assert( isAlpha('A')); 233 assert(!isAlpha('1')); 234 assert(!isAlpha('#')); 235 236 // N.B.: does not return true for non-ASCII Unicode alphabetic characters: 237 assert(!isAlpha('á')); 238 } 239 240 @safe unittest 241 { 242 import std.range; 243 foreach (c; chain(letters, lowercase, uppercase)) 244 assert(isAlpha(c)); 245 246 foreach (c; chain(digits, octalDigits, whitespace)) 247 assert(!isAlpha(c)); 248 } 249 250 251 /++ 252 Params: c = The character to test. 253 Returns: Whether `c` is a lowercase ASCII letter (a .. z). 254 +/ 255 pragma(inline, true) 256 bool isLower(dchar c) @safe pure nothrow @nogc 257 { 258 return c >= 'a' && c <= 'z'; 259 } 260 261 /// 262 @safe pure nothrow @nogc unittest 263 { 264 assert( isLower('a')); 265 assert(!isLower('A')); 266 assert(!isLower('#')); 267 268 // N.B.: does not return true for non-ASCII Unicode lowercase letters 269 assert(!isLower('á')); 270 assert(!isLower('Á')); 271 } 272 273 @safe unittest 274 { 275 import std.range; 276 foreach (c; lowercase) 277 assert(isLower(c)); 278 279 foreach (c; chain(digits, uppercase, whitespace)) 280 assert(!isLower(c)); 281 } 282 283 284 /++ 285 Params: c = The character to test. 286 Returns: Whether `c` is an uppercase ASCII letter (A .. Z). 287 +/ 288 pragma(inline, true) 289 bool isUpper(dchar c) @safe pure nothrow @nogc 290 { 291 return c <= 'Z' && 'A' <= c; 292 } 293 294 /// 295 @safe pure nothrow @nogc unittest 296 { 297 assert( isUpper('A')); 298 assert(!isUpper('a')); 299 assert(!isUpper('#')); 300 301 // N.B.: does not return true for non-ASCII Unicode uppercase letters 302 assert(!isUpper('á')); 303 assert(!isUpper('Á')); 304 } 305 306 @safe unittest 307 { 308 import std.range; 309 foreach (c; uppercase) 310 assert(isUpper(c)); 311 312 foreach (c; chain(digits, lowercase, whitespace)) 313 assert(!isUpper(c)); 314 } 315 316 317 /++ 318 Params: c = The character to test. 319 Returns: Whether `c` is a digit (0 .. 9). 320 +/ 321 pragma(inline, true) 322 bool isDigit(dchar c) @safe pure nothrow @nogc 323 { 324 return '0' <= c && c <= '9'; 325 } 326 327 /// 328 @safe pure nothrow @nogc unittest 329 { 330 assert( isDigit('3')); 331 assert( isDigit('8')); 332 assert(!isDigit('B')); 333 assert(!isDigit('#')); 334 335 // N.B.: does not return true for non-ASCII Unicode numbers 336 assert(!isDigit('0')); // full-width digit zero (U+FF10) 337 assert(!isDigit('4')); // full-width digit four (U+FF14) 338 } 339 340 @safe unittest 341 { 342 import std.range; 343 foreach (c; digits) 344 assert(isDigit(c)); 345 346 foreach (c; chain(letters, whitespace)) 347 assert(!isDigit(c)); 348 } 349 350 351 /++ 352 Params: c = The character to test. 353 Returns: Whether `c` is a digit in base 8 (0 .. 7). 354 +/ 355 pragma(inline, true) 356 bool isOctalDigit(dchar c) @safe pure nothrow @nogc 357 { 358 return c >= '0' && c <= '7'; 359 } 360 361 /// 362 @safe pure nothrow @nogc unittest 363 { 364 assert( isOctalDigit('0')); 365 assert( isOctalDigit('7')); 366 assert(!isOctalDigit('8')); 367 assert(!isOctalDigit('A')); 368 assert(!isOctalDigit('#')); 369 } 370 371 @safe unittest 372 { 373 import std.range; 374 foreach (c; octalDigits) 375 assert(isOctalDigit(c)); 376 377 foreach (c; chain(letters, ['8', '9'], whitespace)) 378 assert(!isOctalDigit(c)); 379 } 380 381 382 /++ 383 Params: c = The character to test. 384 Returns: Whether `c` is a digit in base 16 (0 .. 9, A .. F, a .. f). 385 +/ 386 pragma(inline, true) 387 bool isHexDigit(dchar c) @safe pure nothrow @nogc 388 { 389 const hc = c | 0x20; 390 return ('0' <= c && c <= '9') || ('a' <= hc && hc <= 'f'); 391 } 392 393 /// 394 @safe pure nothrow @nogc unittest 395 { 396 assert( isHexDigit('0')); 397 assert( isHexDigit('A')); 398 assert( isHexDigit('f')); // lowercase hex digits are accepted 399 assert(!isHexDigit('g')); 400 assert(!isHexDigit('G')); 401 assert(!isHexDigit('#')); 402 } 403 404 @safe unittest 405 { 406 import std.range; 407 foreach (c; fullHexDigits) 408 assert(isHexDigit(c)); 409 410 foreach (c; chain(lowercase[6 .. $], uppercase[6 .. $], whitespace)) 411 assert(!isHexDigit(c)); 412 } 413 414 415 /++ 416 Params: c = The character to test. 417 Returns: Whether or not `c` is a whitespace character. That includes the 418 space, tab, vertical tab, form feed, carriage return, and linefeed 419 characters. 420 +/ 421 pragma(inline, true) 422 bool isWhite(dchar c) @safe pure nothrow @nogc 423 { 424 return c == ' ' || (c >= 0x09 && c <= 0x0D); 425 } 426 427 /// 428 @safe pure nothrow @nogc unittest 429 { 430 assert( isWhite(' ')); 431 assert( isWhite('\t')); 432 assert( isWhite('\n')); 433 assert(!isWhite('1')); 434 assert(!isWhite('a')); 435 assert(!isWhite('#')); 436 437 // N.B.: Does not return true for non-ASCII Unicode whitespace characters. 438 static import std.uni; 439 assert(std.uni.isWhite('\u00A0')); 440 assert(!isWhite('\u00A0')); // std.ascii.isWhite 441 } 442 443 @safe unittest 444 { 445 import std.range; 446 foreach (c; whitespace) 447 assert(isWhite(c)); 448 449 foreach (c; chain(digits, letters)) 450 assert(!isWhite(c)); 451 } 452 453 454 /++ 455 Params: c = The character to test. 456 Returns: Whether `c` is a control character. 457 +/ 458 pragma(inline, true) 459 bool isControl(dchar c) @safe pure nothrow @nogc 460 { 461 return c < 0x20 || c == 0x7F; 462 } 463 464 /// 465 @safe pure nothrow @nogc unittest 466 { 467 assert( isControl('\0')); 468 assert( isControl('\022')); 469 assert( isControl('\n')); // newline is both whitespace and control 470 assert(!isControl(' ')); 471 assert(!isControl('1')); 472 assert(!isControl('a')); 473 assert(!isControl('#')); 474 475 // N.B.: non-ASCII Unicode control characters are not recognized: 476 assert(!isControl('\u0080')); 477 assert(!isControl('\u2028')); 478 assert(!isControl('\u2029')); 479 } 480 481 @safe unittest 482 { 483 import std.range; 484 foreach (dchar c; 0 .. 32) 485 assert(isControl(c)); 486 assert(isControl(127)); 487 488 foreach (c; chain(digits, letters, [' '])) 489 assert(!isControl(c)); 490 } 491 492 493 /++ 494 Params: c = The character to test. 495 Returns: Whether or not `c` is a punctuation character. That includes 496 all ASCII characters which are not control characters, letters, digits, or 497 whitespace. 498 +/ 499 pragma(inline, true) 500 bool isPunctuation(dchar c) @safe pure nothrow @nogc 501 { 502 return c <= '~' && c >= '!' && !isAlphaNum(c); 503 } 504 505 /// 506 @safe pure nothrow @nogc unittest 507 { 508 assert( isPunctuation('.')); 509 assert( isPunctuation(',')); 510 assert( isPunctuation(':')); 511 assert( isPunctuation('!')); 512 assert( isPunctuation('#')); 513 assert( isPunctuation('~')); 514 assert( isPunctuation('+')); 515 assert( isPunctuation('_')); 516 517 assert(!isPunctuation('1')); 518 assert(!isPunctuation('a')); 519 assert(!isPunctuation(' ')); 520 assert(!isPunctuation('\n')); 521 assert(!isPunctuation('\0')); 522 523 // N.B.: Non-ASCII Unicode punctuation characters are not recognized. 524 assert(!isPunctuation('\u2012')); // (U+2012 = en-dash) 525 } 526 527 @safe unittest 528 { 529 foreach (dchar c; 0 .. 128) 530 { 531 if (isControl(c) || isAlphaNum(c) || c == ' ') 532 assert(!isPunctuation(c)); 533 else 534 assert(isPunctuation(c)); 535 } 536 } 537 538 539 /++ 540 Params: c = The character to test. 541 Returns: Whether or not `c` is a printable character other than the 542 space character. 543 +/ 544 pragma(inline, true) 545 bool isGraphical(dchar c) @safe pure nothrow @nogc 546 { 547 return '!' <= c && c <= '~'; 548 } 549 550 /// 551 @safe pure nothrow @nogc unittest 552 { 553 assert( isGraphical('1')); 554 assert( isGraphical('a')); 555 assert( isGraphical('#')); 556 assert(!isGraphical(' ')); // whitespace is not graphical 557 assert(!isGraphical('\n')); 558 assert(!isGraphical('\0')); 559 560 // N.B.: Unicode graphical characters are not regarded as such. 561 assert(!isGraphical('á')); 562 } 563 564 @safe unittest 565 { 566 foreach (dchar c; 0 .. 128) 567 { 568 if (isControl(c) || c == ' ') 569 assert(!isGraphical(c)); 570 else 571 assert(isGraphical(c)); 572 } 573 } 574 575 576 /++ 577 Params: c = The character to test. 578 Returns: Whether or not `c` is a printable character - including the 579 space character. 580 +/ 581 pragma(inline, true) 582 bool isPrintable(dchar c) @safe pure nothrow @nogc 583 { 584 return c >= ' ' && c <= '~'; 585 } 586 587 /// 588 @safe pure nothrow @nogc unittest 589 { 590 assert( isPrintable(' ')); // whitespace is printable 591 assert( isPrintable('1')); 592 assert( isPrintable('a')); 593 assert( isPrintable('#')); 594 assert(!isPrintable('\0')); // control characters are not printable 595 596 // N.B.: Printable non-ASCII Unicode characters are not recognized. 597 assert(!isPrintable('á')); 598 } 599 600 @safe unittest 601 { 602 foreach (dchar c; 0 .. 128) 603 { 604 if (isControl(c)) 605 assert(!isPrintable(c)); 606 else 607 assert(isPrintable(c)); 608 } 609 } 610 611 612 /++ 613 Params: c = The character to test. 614 Returns: Whether or not `c` is in the ASCII character set - i.e. in the 615 range 0 .. 0x7F. 616 +/ 617 pragma(inline, true) 618 bool isASCII(dchar c) @safe pure nothrow @nogc 619 { 620 return c <= 0x7F; 621 } 622 623 /// 624 @safe pure nothrow @nogc unittest 625 { 626 assert( isASCII('a')); 627 assert(!isASCII('á')); 628 } 629 630 @safe unittest 631 { 632 foreach (dchar c; 0 .. 128) 633 assert(isASCII(c)); 634 635 assert(!isASCII(128)); 636 } 637 638 639 /++ 640 Converts an ASCII letter to lowercase. 641 642 Params: c = A character of any type that implicitly converts to `dchar`. 643 In the case where it's a built-in type, or an enum of a built-in type, 644 `Unqual!(OriginalType!C)` is returned, whereas if it's a user-defined 645 type, `dchar` is returned. 646 647 Returns: The corresponding lowercase letter, if `c` is an uppercase 648 ASCII character, otherwise `c` itself. 649 +/ 650 auto toLower(C)(C c) 651 if (is(C : dchar)) 652 { 653 import std.traits : OriginalType; 654 655 static if (!__traits(isScalar, C)) 656 alias R = dchar; 657 else static if (is(immutable OriginalType!C == immutable OC, OC)) 658 alias R = OC; 659 660 return isUpper(c) ? cast(R)(cast(R) c + 'a' - 'A') : cast(R) c; 661 } 662 663 /// 664 @safe pure nothrow @nogc unittest 665 { 666 assert(toLower('a') == 'a'); 667 assert(toLower('A') == 'a'); 668 assert(toLower('#') == '#'); 669 670 // N.B.: Non-ASCII Unicode uppercase letters are not converted. 671 assert(toLower('Á') == 'Á'); 672 } 673 674 @safe pure nothrow unittest 675 { 676 677 import std.meta; 678 static foreach (C; AliasSeq!(char, wchar, dchar, immutable char, ubyte)) 679 { 680 foreach (i, c; uppercase) 681 assert(toLower(cast(C) c) == lowercase[i]); 682 683 foreach (C c; 0 .. 128) 684 { 685 if (c < 'A' || c > 'Z') 686 assert(toLower(c) == c); 687 else 688 assert(toLower(c) != c); 689 } 690 691 foreach (C c; 128 .. C.max) 692 assert(toLower(c) == c); 693 694 //CTFE 695 static assert(toLower(cast(C)'a') == 'a'); 696 static assert(toLower(cast(C)'A') == 'a'); 697 } 698 } 699 700 701 /++ 702 Converts an ASCII letter to uppercase. 703 704 Params: c = Any type which implicitly converts to `dchar`. In the case 705 where it's a built-in type, or an enum of a built-in type, 706 `Unqual!(OriginalType!C)` is returned, whereas if it's a user-defined 707 type, `dchar` is returned. 708 709 Returns: The corresponding uppercase letter, if `c` is a lowercase ASCII 710 character, otherwise `c` itself. 711 +/ 712 auto toUpper(C)(C c) 713 if (is(C : dchar)) 714 { 715 import std.traits : OriginalType; 716 717 static if (!__traits(isScalar, C)) 718 alias R = dchar; 719 else static if (is(immutable OriginalType!C == immutable OC, OC)) 720 alias R = OC; 721 722 return isLower(c) ? cast(R)(cast(R) c - ('a' - 'A')) : cast(R) c; 723 } 724 725 /// 726 @safe pure nothrow @nogc unittest 727 { 728 assert(toUpper('a') == 'A'); 729 assert(toUpper('A') == 'A'); 730 assert(toUpper('#') == '#'); 731 732 // N.B.: Non-ASCII Unicode lowercase letters are not converted. 733 assert(toUpper('á') == 'á'); 734 } 735 736 @safe pure nothrow unittest 737 { 738 import std.meta; 739 static foreach (C; AliasSeq!(char, wchar, dchar, immutable char, ubyte)) 740 { 741 foreach (i, c; lowercase) 742 assert(toUpper(cast(C) c) == uppercase[i]); 743 744 foreach (C c; 0 .. 128) 745 { 746 if (c < 'a' || c > 'z') 747 assert(toUpper(c) == c); 748 else 749 assert(toUpper(c) != c); 750 } 751 752 foreach (C c; 128 .. C.max) 753 assert(toUpper(c) == c); 754 755 //CTFE 756 static assert(toUpper(cast(C)'a') == 'A'); 757 static assert(toUpper(cast(C)'A') == 'A'); 758 } 759 } 760 761 762 @safe unittest //Test both toUpper and toLower with non-builtin 763 { 764 import std.meta; 765 import std.traits; 766 767 //User Defined [Char|Wchar|Dchar] 768 static struct UDC { char c; alias c this; } 769 static struct UDW { wchar c; alias c this; } 770 static struct UDD { dchar c; alias c this; } 771 //[Char|Wchar|Dchar] Enum 772 enum CE : char {a = 'a', A = 'A'} 773 enum WE : wchar {a = 'a', A = 'A'} 774 enum DE : dchar {a = 'a', A = 'A'} 775 //User Defined [Char|Wchar|Dchar] Enum 776 enum UDCE : UDC {a = UDC('a'), A = UDC('A')} 777 enum UDWE : UDW {a = UDW('a'), A = UDW('A')} 778 enum UDDE : UDD {a = UDD('a'), A = UDD('A')} 779 780 //User defined types with implicit cast to dchar test. 781 static foreach (Char; AliasSeq!(UDC, UDW, UDD)) 782 { 783 assert(toLower(Char('a')) == 'a'); 784 assert(toLower(Char('A')) == 'a'); 785 static assert(toLower(Char('a')) == 'a'); 786 static assert(toLower(Char('A')) == 'a'); 787 static assert(toUpper(Char('a')) == 'A'); 788 static assert(toUpper(Char('A')) == 'A'); 789 } 790 791 //Various enum tests. 792 static foreach (Enum; AliasSeq!(CE, WE, DE, UDCE, UDWE, UDDE)) 793 { 794 assert(toLower(Enum.a) == 'a'); 795 assert(toLower(Enum.A) == 'a'); 796 assert(toUpper(Enum.a) == 'A'); 797 assert(toUpper(Enum.A) == 'A'); 798 static assert(toLower(Enum.a) == 'a'); 799 static assert(toLower(Enum.A) == 'a'); 800 static assert(toUpper(Enum.a) == 'A'); 801 static assert(toUpper(Enum.A) == 'A'); 802 } 803 804 //Return value type tests for enum of non-UDT. These should be the original type. 805 static foreach (T; AliasSeq!(CE, WE, DE)) 806 {{ 807 alias C = OriginalType!T; 808 static assert(is(typeof(toLower(T.init)) == C)); 809 static assert(is(typeof(toUpper(T.init)) == C)); 810 }} 811 812 //Return value tests for UDT and enum of UDT. These should be dchar 813 static foreach (T; AliasSeq!(UDC, UDW, UDD, UDCE, UDWE, UDDE)) 814 { 815 static assert(is(typeof(toLower(T.init)) == dchar)); 816 static assert(is(typeof(toUpper(T.init)) == dchar)); 817 } 818 }