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