File Coverage

tstr_packed_alnum.h
Criterion Covered Total %
statement 13 15 86.6
branch 7 10 70.0
condition n/a
subroutine n/a
pod n/a
total 20 25 80.0


line stmt bran cond sub pod time code
1             #ifndef TSTR_PACKED_ALNUM_H
2             #define TSTR_PACKED_ALNUM_H
3              
4             #include
5             #include
6              
7             /*
8             * Pack up to 10 alphanumeric characters into a uint64_t using 6 bits each.
9             *
10             * Case-insensitive: a-z => 1-26, 0-9 => 27-36, packed MSB-first.
11             * Returns the number of characters consumed, or 0 if none or >10.
12             */
13 1602           static inline size_t tstr_packed_alnum_encode(const char* str,
14             size_t len,
15             uint64_t* packed) {
16 1602           const unsigned char* src = (const unsigned char*)str;
17             uint64_t enc;
18             size_t i;
19              
20 12642 100         for (enc = 0, i = 0; i < len; i++) {
21 11040           unsigned char ch = src[i];
22             unsigned char c;
23 11040           unsigned char lower = ch | 0x20;
24              
25 11040 100         if (lower - 'a' <= (unsigned)('z' - 'a'))
26 7973           c = lower - 'a' + 1;
27 3067 50         else if (ch - '0' <= (unsigned)('9' - '0'))
28 3067           c = ch - '0' + 27;
29             else
30 0           break;
31              
32 11040           enc = (enc << 6) | c;
33             }
34              
35 1602 50         if (i == 0 || i > 10)
    50          
36 0           return 0;
37 1602           *packed = enc;
38 1602           return i;
39             }
40              
41             /* clang-format off */
42             #define TSTR_PACKED_ALNUM_MAP_CHAR(c) \
43             ( ((c) == 'A' || (c) == 'a') ? 1 : \
44             ((c) == 'B' || (c) == 'b') ? 2 : \
45             ((c) == 'C' || (c) == 'c') ? 3 : \
46             ((c) == 'D' || (c) == 'd') ? 4 : \
47             ((c) == 'E' || (c) == 'e') ? 5 : \
48             ((c) == 'F' || (c) == 'f') ? 6 : \
49             ((c) == 'G' || (c) == 'g') ? 7 : \
50             ((c) == 'H' || (c) == 'h') ? 8 : \
51             ((c) == 'I' || (c) == 'i') ? 9 : \
52             ((c) == 'J' || (c) == 'j') ? 10 : \
53             ((c) == 'K' || (c) == 'k') ? 11 : \
54             ((c) == 'L' || (c) == 'l') ? 12 : \
55             ((c) == 'M' || (c) == 'm') ? 13 : \
56             ((c) == 'N' || (c) == 'n') ? 14 : \
57             ((c) == 'O' || (c) == 'o') ? 15 : \
58             ((c) == 'P' || (c) == 'p') ? 16 : \
59             ((c) == 'Q' || (c) == 'q') ? 17 : \
60             ((c) == 'R' || (c) == 'r') ? 18 : \
61             ((c) == 'S' || (c) == 's') ? 19 : \
62             ((c) == 'T' || (c) == 't') ? 20 : \
63             ((c) == 'U' || (c) == 'u') ? 21 : \
64             ((c) == 'V' || (c) == 'v') ? 22 : \
65             ((c) == 'W' || (c) == 'w') ? 23 : \
66             ((c) == 'X' || (c) == 'x') ? 24 : \
67             ((c) == 'Y' || (c) == 'y') ? 25 : \
68             ((c) == 'Z' || (c) == 'z') ? 26 : \
69             ((c) == '0') ? 27 : \
70             ((c) == '1') ? 28 : \
71             ((c) == '2') ? 29 : \
72             ((c) == '3') ? 30 : \
73             ((c) == '4') ? 31 : \
74             ((c) == '5') ? 32 : \
75             ((c) == '6') ? 33 : \
76             ((c) == '7') ? 34 : \
77             ((c) == '8') ? 35 : \
78             ((c) == '9') ? 36 : \
79             0 )
80              
81             #define TSTR_PACKED_ALNUM1(c1) \
82             ((uint64_t)(TSTR_PACKED_ALNUM_MAP_CHAR(c1) & 0x3F))
83             #define TSTR_PACKED_ALNUM2(c1, c2) \
84             ((TSTR_PACKED_ALNUM1(c1) << (6*1)) | TSTR_PACKED_ALNUM1(c2))
85             #define TSTR_PACKED_ALNUM3(c1, c2, c3) \
86             ((TSTR_PACKED_ALNUM1(c1) << (6*2)) | TSTR_PACKED_ALNUM2(c2, c3))
87             #define TSTR_PACKED_ALNUM4(c1, c2, c3, c4) \
88             ((TSTR_PACKED_ALNUM1(c1) << (6*3)) | TSTR_PACKED_ALNUM3(c2, c3, c4))
89             #define TSTR_PACKED_ALNUM5(c1, c2, c3, c4, c5) \
90             ((TSTR_PACKED_ALNUM1(c1) << (6*4)) | TSTR_PACKED_ALNUM4(c2, c3, c4, c5))
91             #define TSTR_PACKED_ALNUM6(c1, c2, c3, c4, c5, c6) \
92             ((TSTR_PACKED_ALNUM1(c1) << (6*5)) | TSTR_PACKED_ALNUM5(c2, c3, c4, c5, c6))
93             #define TSTR_PACKED_ALNUM7(c1, c2, c3, c4, c5, c6, c7) \
94             ((TSTR_PACKED_ALNUM1(c1) << (6*6)) | TSTR_PACKED_ALNUM6(c2, c3, c4, c5, c6, c7))
95             #define TSTR_PACKED_ALNUM8(c1, c2, c3, c4, c5, c6, c7, c8) \
96             ((TSTR_PACKED_ALNUM1(c1) << (6*7)) | TSTR_PACKED_ALNUM7(c2, c3, c4, c5, c6, c7, c8))
97             #define TSTR_PACKED_ALNUM9(c1, c2, c3, c4, c5, c6, c7, c8, c9) \
98             ((TSTR_PACKED_ALNUM1(c1) << (6*8)) | TSTR_PACKED_ALNUM8(c2, c3, c4, c5, c6, c7, c8, c9))
99             #define TSTR_PACKED_ALNUM10(c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) \
100             ((TSTR_PACKED_ALNUM1(c1) << (6*9)) | TSTR_PACKED_ALNUM9(c2, c3, c4, c5, c6, c7, c8, c9, c10))
101             /* clang-format on */
102              
103             #endif /* TSTR_PACKED_ALNUM_H */