xref: /llvm-project/libc/src/__support/ctype_utils.h (revision a0c4f854cad2b97e44a1b58dc1fd982e1c4d60f3)
1 //===-- Collection of utils for implementing ctype functions-------*-C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_LIBC_SRC___SUPPORT_CTYPE_UTILS_H
10 #define LLVM_LIBC_SRC___SUPPORT_CTYPE_UTILS_H
11 
12 #include "src/__support/macros/attributes.h"
13 #include "src/__support/macros/config.h"
14 
15 namespace LIBC_NAMESPACE_DECL {
16 namespace internal {
17 
18 // -----------------------------------------------------------------------------
19 // ******************                 WARNING                 ******************
20 // ****************** DO NOT TRY TO OPTIMIZE THESE FUNCTIONS! ******************
21 // -----------------------------------------------------------------------------
22 // This switch/case form is easier for the compiler to understand, and is
23 // optimized into a form that is almost always the same as or better than
24 // versions written by hand (see https://godbolt.org/z/qvrebqvvr). Also this
25 // form makes these functions encoding independent. If you want to rewrite these
26 // functions, make sure you have benchmarks to show your new solution is faster,
27 // as well as a way to support non-ASCII character encodings.
28 
29 // Similarly, do not change these functions to use case ranges. e.g.
30 //  bool islower(int ch) {
31 //    switch(ch) {
32 //    case 'a'...'z':
33 //      return true;
34 //    }
35 //  }
36 // This assumes the character ranges are contiguous, which they aren't in
37 // EBCDIC. Technically we could use some smaller ranges, but that's even harder
38 // to read.
39 
40 LIBC_INLINE static constexpr bool islower(int ch) {
41   switch (ch) {
42   case 'a':
43   case 'b':
44   case 'c':
45   case 'd':
46   case 'e':
47   case 'f':
48   case 'g':
49   case 'h':
50   case 'i':
51   case 'j':
52   case 'k':
53   case 'l':
54   case 'm':
55   case 'n':
56   case 'o':
57   case 'p':
58   case 'q':
59   case 'r':
60   case 's':
61   case 't':
62   case 'u':
63   case 'v':
64   case 'w':
65   case 'x':
66   case 'y':
67   case 'z':
68     return true;
69   default:
70     return false;
71   }
72 }
73 
74 LIBC_INLINE static constexpr bool isupper(int ch) {
75   switch (ch) {
76   case 'A':
77   case 'B':
78   case 'C':
79   case 'D':
80   case 'E':
81   case 'F':
82   case 'G':
83   case 'H':
84   case 'I':
85   case 'J':
86   case 'K':
87   case 'L':
88   case 'M':
89   case 'N':
90   case 'O':
91   case 'P':
92   case 'Q':
93   case 'R':
94   case 'S':
95   case 'T':
96   case 'U':
97   case 'V':
98   case 'W':
99   case 'X':
100   case 'Y':
101   case 'Z':
102     return true;
103   default:
104     return false;
105   }
106 }
107 
108 LIBC_INLINE static constexpr bool isdigit(int ch) {
109   switch (ch) {
110   case '0':
111   case '1':
112   case '2':
113   case '3':
114   case '4':
115   case '5':
116   case '6':
117   case '7':
118   case '8':
119   case '9':
120     return true;
121   default:
122     return false;
123   }
124 }
125 
126 LIBC_INLINE static constexpr int tolower(int ch) {
127   switch (ch) {
128   case 'A':
129     return 'a';
130   case 'B':
131     return 'b';
132   case 'C':
133     return 'c';
134   case 'D':
135     return 'd';
136   case 'E':
137     return 'e';
138   case 'F':
139     return 'f';
140   case 'G':
141     return 'g';
142   case 'H':
143     return 'h';
144   case 'I':
145     return 'i';
146   case 'J':
147     return 'j';
148   case 'K':
149     return 'k';
150   case 'L':
151     return 'l';
152   case 'M':
153     return 'm';
154   case 'N':
155     return 'n';
156   case 'O':
157     return 'o';
158   case 'P':
159     return 'p';
160   case 'Q':
161     return 'q';
162   case 'R':
163     return 'r';
164   case 'S':
165     return 's';
166   case 'T':
167     return 't';
168   case 'U':
169     return 'u';
170   case 'V':
171     return 'v';
172   case 'W':
173     return 'w';
174   case 'X':
175     return 'x';
176   case 'Y':
177     return 'y';
178   case 'Z':
179     return 'z';
180   default:
181     return ch;
182   }
183 }
184 
185 LIBC_INLINE static constexpr int toupper(int ch) {
186   switch (ch) {
187   case 'a':
188     return 'A';
189   case 'b':
190     return 'B';
191   case 'c':
192     return 'C';
193   case 'd':
194     return 'D';
195   case 'e':
196     return 'E';
197   case 'f':
198     return 'F';
199   case 'g':
200     return 'G';
201   case 'h':
202     return 'H';
203   case 'i':
204     return 'I';
205   case 'j':
206     return 'J';
207   case 'k':
208     return 'K';
209   case 'l':
210     return 'L';
211   case 'm':
212     return 'M';
213   case 'n':
214     return 'N';
215   case 'o':
216     return 'O';
217   case 'p':
218     return 'P';
219   case 'q':
220     return 'Q';
221   case 'r':
222     return 'R';
223   case 's':
224     return 'S';
225   case 't':
226     return 'T';
227   case 'u':
228     return 'U';
229   case 'v':
230     return 'V';
231   case 'w':
232     return 'W';
233   case 'x':
234     return 'X';
235   case 'y':
236     return 'Y';
237   case 'z':
238     return 'Z';
239   default:
240     return ch;
241   }
242 }
243 
244 LIBC_INLINE static constexpr bool isalpha(int ch) {
245   switch (ch) {
246   case 'a':
247   case 'b':
248   case 'c':
249   case 'd':
250   case 'e':
251   case 'f':
252   case 'g':
253   case 'h':
254   case 'i':
255   case 'j':
256   case 'k':
257   case 'l':
258   case 'm':
259   case 'n':
260   case 'o':
261   case 'p':
262   case 'q':
263   case 'r':
264   case 's':
265   case 't':
266   case 'u':
267   case 'v':
268   case 'w':
269   case 'x':
270   case 'y':
271   case 'z':
272   case 'A':
273   case 'B':
274   case 'C':
275   case 'D':
276   case 'E':
277   case 'F':
278   case 'G':
279   case 'H':
280   case 'I':
281   case 'J':
282   case 'K':
283   case 'L':
284   case 'M':
285   case 'N':
286   case 'O':
287   case 'P':
288   case 'Q':
289   case 'R':
290   case 'S':
291   case 'T':
292   case 'U':
293   case 'V':
294   case 'W':
295   case 'X':
296   case 'Y':
297   case 'Z':
298     return true;
299   default:
300     return false;
301   }
302 }
303 
304 LIBC_INLINE static constexpr bool isalnum(int ch) {
305   switch (ch) {
306   case 'a':
307   case 'b':
308   case 'c':
309   case 'd':
310   case 'e':
311   case 'f':
312   case 'g':
313   case 'h':
314   case 'i':
315   case 'j':
316   case 'k':
317   case 'l':
318   case 'm':
319   case 'n':
320   case 'o':
321   case 'p':
322   case 'q':
323   case 'r':
324   case 's':
325   case 't':
326   case 'u':
327   case 'v':
328   case 'w':
329   case 'x':
330   case 'y':
331   case 'z':
332   case 'A':
333   case 'B':
334   case 'C':
335   case 'D':
336   case 'E':
337   case 'F':
338   case 'G':
339   case 'H':
340   case 'I':
341   case 'J':
342   case 'K':
343   case 'L':
344   case 'M':
345   case 'N':
346   case 'O':
347   case 'P':
348   case 'Q':
349   case 'R':
350   case 'S':
351   case 'T':
352   case 'U':
353   case 'V':
354   case 'W':
355   case 'X':
356   case 'Y':
357   case 'Z':
358   case '0':
359   case '1':
360   case '2':
361   case '3':
362   case '4':
363   case '5':
364   case '6':
365   case '7':
366   case '8':
367   case '9':
368     return true;
369   default:
370     return false;
371   }
372 }
373 
374 LIBC_INLINE static constexpr int b36_char_to_int(int ch) {
375   switch (ch) {
376   case '0':
377     return 0;
378   case '1':
379     return 1;
380   case '2':
381     return 2;
382   case '3':
383     return 3;
384   case '4':
385     return 4;
386   case '5':
387     return 5;
388   case '6':
389     return 6;
390   case '7':
391     return 7;
392   case '8':
393     return 8;
394   case '9':
395     return 9;
396   case 'a':
397   case 'A':
398     return 10;
399   case 'b':
400   case 'B':
401     return 11;
402   case 'c':
403   case 'C':
404     return 12;
405   case 'd':
406   case 'D':
407     return 13;
408   case 'e':
409   case 'E':
410     return 14;
411   case 'f':
412   case 'F':
413     return 15;
414   case 'g':
415   case 'G':
416     return 16;
417   case 'h':
418   case 'H':
419     return 17;
420   case 'i':
421   case 'I':
422     return 18;
423   case 'j':
424   case 'J':
425     return 19;
426   case 'k':
427   case 'K':
428     return 20;
429   case 'l':
430   case 'L':
431     return 21;
432   case 'm':
433   case 'M':
434     return 22;
435   case 'n':
436   case 'N':
437     return 23;
438   case 'o':
439   case 'O':
440     return 24;
441   case 'p':
442   case 'P':
443     return 25;
444   case 'q':
445   case 'Q':
446     return 26;
447   case 'r':
448   case 'R':
449     return 27;
450   case 's':
451   case 'S':
452     return 28;
453   case 't':
454   case 'T':
455     return 29;
456   case 'u':
457   case 'U':
458     return 30;
459   case 'v':
460   case 'V':
461     return 31;
462   case 'w':
463   case 'W':
464     return 32;
465   case 'x':
466   case 'X':
467     return 33;
468   case 'y':
469   case 'Y':
470     return 34;
471   case 'z':
472   case 'Z':
473     return 35;
474   default:
475     return 0;
476   }
477 }
478 
479 LIBC_INLINE static constexpr int int_to_b36_char(int num) {
480   // Can't actually use LIBC_ASSERT here because it depends on integer_to_string
481   // which depends on this.
482 
483   // LIBC_ASSERT(num < 36);
484   switch (num) {
485   case 0:
486     return '0';
487   case 1:
488     return '1';
489   case 2:
490     return '2';
491   case 3:
492     return '3';
493   case 4:
494     return '4';
495   case 5:
496     return '5';
497   case 6:
498     return '6';
499   case 7:
500     return '7';
501   case 8:
502     return '8';
503   case 9:
504     return '9';
505   case 10:
506     return 'a';
507   case 11:
508     return 'b';
509   case 12:
510     return 'c';
511   case 13:
512     return 'd';
513   case 14:
514     return 'e';
515   case 15:
516     return 'f';
517   case 16:
518     return 'g';
519   case 17:
520     return 'h';
521   case 18:
522     return 'i';
523   case 19:
524     return 'j';
525   case 20:
526     return 'k';
527   case 21:
528     return 'l';
529   case 22:
530     return 'm';
531   case 23:
532     return 'n';
533   case 24:
534     return 'o';
535   case 25:
536     return 'p';
537   case 26:
538     return 'q';
539   case 27:
540     return 'r';
541   case 28:
542     return 's';
543   case 29:
544     return 't';
545   case 30:
546     return 'u';
547   case 31:
548     return 'v';
549   case 32:
550     return 'w';
551   case 33:
552     return 'x';
553   case 34:
554     return 'y';
555   case 35:
556     return 'z';
557   default:
558     return '!';
559   }
560 }
561 
562 LIBC_INLINE static constexpr bool isspace(int ch) {
563   switch (ch) {
564   case ' ':
565   case '\t':
566   case '\n':
567   case '\v':
568   case '\f':
569   case '\r':
570     return true;
571   default:
572     return false;
573   }
574 }
575 
576 // not yet encoding independent.
577 LIBC_INLINE static constexpr bool isgraph(int ch) {
578   return 0x20 < ch && ch < 0x7f;
579 }
580 
581 } // namespace internal
582 } // namespace LIBC_NAMESPACE_DECL
583 
584 #endif //  LLVM_LIBC_SRC___SUPPORT_CTYPE_UTILS_H
585