/src/opensips/lib/turbocompare.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2020 Maksym Sobolyev |
3 | | * |
4 | | * This file is part of opensips, a free SIP server. |
5 | | * |
6 | | * opensips is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version |
10 | | * |
11 | | * opensips is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | * |
20 | | */ |
21 | | |
22 | | #if !defined(_turbocompare_h) |
23 | | #define _turbocompare_h |
24 | | |
25 | | /* |
26 | | * markbetween() macro takes int-like type in x treats it as a sequence of bytes |
27 | | * and produces a value of the same type and lengh with bytes of original |
28 | | * value in the range m > bX < n replaced with 0x80 and the rest with 0x00, i.e. |
29 | | * |
30 | | * markbetween((uint64_t)0x0102030405060708, 0x03, 0x08) == (uint64_t)0x0000008080808000 |
31 | | * |
32 | | * Obtained from Bit Twiddling Hacks By Sean Eron Anderson <seander@cs.stanford.edu> |
33 | | */ |
34 | | #define markbetween(x,m,n) \ |
35 | 0 | ({const typeof(x) cFF = ~(typeof(x))0, c01 = cFF / 255; (((c01*(127+(n))-((x)&c01*127))&~(x)&(((x)&c01*127)+c01*(127-(m))))&c01*128);}) |
36 | | |
37 | | /* |
38 | | * TURBO_LCMASK() generates mask that can be ORed with original int-like |
39 | | * value x to produce lower-case version of the sequence of bytes contained |
40 | | * in x. |
41 | | */ |
42 | 0 | #define TURBO_LCMASK(x) (markbetween(x, 'A' - 1, 'Z' + 1) >> 2) |
43 | | #define TOLOWER_FUNC(itype) \ |
44 | | static inline unsigned itype \ |
45 | | turbo_tolower_##itype(const void *wp) \ |
46 | 0 | { \ |
47 | 0 | unsigned itype msk, wrd; \ |
48 | 0 | memcpy(&wrd, wp, sizeof(wrd)); \ |
49 | 0 | msk = TURBO_LCMASK(wrd); \ |
50 | 0 | return (wrd | msk); \ |
51 | 0 | } Unexecuted instantiation: digest_parser.c:turbo_tolower_long Unexecuted instantiation: digest_parser.c:turbo_tolower_int Unexecuted instantiation: digest_parser.c:turbo_tolower_short Unexecuted instantiation: digest_parser.c:turbo_tolower_char Unexecuted instantiation: parse_authenticate.c:turbo_tolower_long Unexecuted instantiation: parse_authenticate.c:turbo_tolower_int Unexecuted instantiation: parse_authenticate.c:turbo_tolower_short Unexecuted instantiation: parse_authenticate.c:turbo_tolower_char |
52 | | |
53 | | TOLOWER_FUNC(long); |
54 | | TOLOWER_FUNC(int); |
55 | | TOLOWER_FUNC(short); |
56 | | TOLOWER_FUNC(char); |
57 | | |
58 | | #define FASTCASEMATCH_LOOP(itype) \ |
59 | 0 | while (len >= sizeof(unsigned itype)) { \ |
60 | 0 | if (turbo_tolower_##itype(us1.itype##_p) != turbo_tolower_##itype(us2.itype##_p)) \ |
61 | 0 | return 0; \ |
62 | 0 | len -= sizeof(unsigned itype); \ |
63 | 0 | if (len == 0) \ |
64 | 0 | return 1; \ |
65 | 0 | if (len < sizeof(unsigned itype)) { \ |
66 | 0 | us1.char_p -= sizeof(unsigned itype) - len; \ |
67 | 0 | us2.char_p -= sizeof(unsigned itype) - len; \ |
68 | 0 | len = sizeof(unsigned itype); \ |
69 | 0 | } \ |
70 | 0 | us1.itype##_p++; \ |
71 | 0 | us2.itype##_p++; \ |
72 | 0 | } |
73 | | |
74 | | /* |
75 | | * The turbo_casematch() function compares ASCII byte strings s1 against s2, |
76 | | * ignoring case and returning non-zero if they are identical, zero otherwise. |
77 | | * Both strings are assumed to be len bytes long. Zero-length strings are always |
78 | | * identical. No special treatment for \0 is performed, the comparison will |
79 | | * continue if both strings are matching until len bytes are compared, i.e. |
80 | | * turbo_casematch("1234\05678", "1234\05679", 9) will return 0 (i.e. mismatch). |
81 | | */ |
82 | | static inline int |
83 | | turbo_casematch(const char *s1, const char *s2, unsigned int len) |
84 | 0 | { |
85 | 0 | union { |
86 | 0 | const char *char_p; |
87 | 0 | const unsigned long *long_p; |
88 | 0 | const unsigned int *int_p; |
89 | 0 | const unsigned short *short_p; |
90 | 0 | } us1, us2; |
91 | 0 | us1.char_p = s1; |
92 | 0 | us2.char_p = s2; |
93 | 0 | FASTCASEMATCH_LOOP(long); |
94 | 0 | FASTCASEMATCH_LOOP(int); |
95 | 0 | FASTCASEMATCH_LOOP(short); |
96 | 0 | FASTCASEMATCH_LOOP(char); |
97 | 0 | return 1; |
98 | 0 | } Unexecuted instantiation: digest_parser.c:turbo_casematch Unexecuted instantiation: parse_authenticate.c:turbo_casematch |
99 | | |
100 | | /* |
101 | | * Convinience macro: return true if both sargs->len is the same as Slen and |
102 | | * string S matches sarg->s (ignoring the case in both). |
103 | | */ |
104 | 0 | #define turbo_strcasematch(sarg, S, Slen) ((sarg)->len == (Slen) && \ |
105 | 0 | turbo_casematch((sarg)->s, (S), (Slen))) |
106 | | |
107 | | #endif |