/src/opensips/lib/turbocompare.h
Line | Count | Source |
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 | 313k | ({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 | 313k | #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 | 145k | { \ |
47 | 145k | unsigned itype msk, wrd; \ |
48 | 145k | memcpy(&wrd, wp, sizeof(wrd)); \ |
49 | 145k | msk = TURBO_LCMASK(wrd); \ |
50 | 145k | return (wrd | msk); \ |
51 | 145k | } digest_parser.c:turbo_tolower_long Line | Count | Source | 46 | 23.5k | { \ | 47 | 23.5k | unsigned itype msk, wrd; \ | 48 | 23.5k | memcpy(&wrd, wp, sizeof(wrd)); \ | 49 | 23.5k | msk = TURBO_LCMASK(wrd); \ | 50 | 23.5k | return (wrd | msk); \ | 51 | 23.5k | } |
digest_parser.c:turbo_tolower_int Line | Count | Source | 46 | 30.8k | { \ | 47 | 30.8k | unsigned itype msk, wrd; \ | 48 | 30.8k | memcpy(&wrd, wp, sizeof(wrd)); \ | 49 | 30.8k | msk = TURBO_LCMASK(wrd); \ | 50 | 30.8k | return (wrd | msk); \ | 51 | 30.8k | } |
digest_parser.c:turbo_tolower_short Line | Count | Source | 46 | 1.21k | { \ | 47 | 1.21k | unsigned itype msk, wrd; \ | 48 | 1.21k | memcpy(&wrd, wp, sizeof(wrd)); \ | 49 | 1.21k | msk = TURBO_LCMASK(wrd); \ | 50 | 1.21k | return (wrd | msk); \ | 51 | 1.21k | } |
Unexecuted instantiation: digest_parser.c:turbo_tolower_char Unexecuted instantiation: parse_authenticate.c:turbo_tolower_long parse_authenticate.c:turbo_tolower_int Line | Count | Source | 46 | 82.3k | { \ | 47 | 82.3k | unsigned itype msk, wrd; \ | 48 | 82.3k | memcpy(&wrd, wp, sizeof(wrd)); \ | 49 | 82.3k | msk = TURBO_LCMASK(wrd); \ | 50 | 82.3k | return (wrd | msk); \ | 51 | 82.3k | } |
parse_authenticate.c:turbo_tolower_short Line | Count | Source | 46 | 7.20k | { \ | 47 | 7.20k | unsigned itype msk, wrd; \ | 48 | 7.20k | memcpy(&wrd, wp, sizeof(wrd)); \ | 49 | 7.20k | msk = TURBO_LCMASK(wrd); \ | 50 | 7.20k | return (wrd | msk); \ | 51 | 7.20k | } |
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 | 114k | while (len >= sizeof(unsigned itype)) { \ |
60 | 72.5k | if (turbo_tolower_##itype(us1.itype##_p) != turbo_tolower_##itype(us2.itype##_p)) \ |
61 | 72.5k | return 0; \ |
62 | 72.5k | len -= sizeof(unsigned itype); \ |
63 | 62.4k | if (len == 0) \ |
64 | 62.4k | return 1; \ |
65 | 62.4k | if (len < sizeof(unsigned itype)) { \ |
66 | 25.4k | us1.char_p -= sizeof(unsigned itype) - len; \ |
67 | 25.4k | us2.char_p -= sizeof(unsigned itype) - len; \ |
68 | 25.4k | len = sizeof(unsigned itype); \ |
69 | 25.4k | } \ |
70 | 27.3k | us1.itype##_p++; \ |
71 | 27.3k | us2.itype##_p++; \ |
72 | 27.3k | } |
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 | 45.2k | { |
85 | 45.2k | union { |
86 | 45.2k | const char *char_p; |
87 | 45.2k | const unsigned long *long_p; |
88 | 45.2k | const unsigned int *int_p; |
89 | 45.2k | const unsigned short *short_p; |
90 | 45.2k | } us1, us2; |
91 | 45.2k | us1.char_p = s1; |
92 | 45.2k | us2.char_p = s2; |
93 | 45.2k | FASTCASEMATCH_LOOP(long); |
94 | 38.9k | FASTCASEMATCH_LOOP(int); |
95 | 3.38k | FASTCASEMATCH_LOOP(short); |
96 | 0 | FASTCASEMATCH_LOOP(char); |
97 | 0 | return 1; |
98 | 0 | } digest_parser.c:turbo_casematch Line | Count | Source | 84 | 14.6k | { | 85 | 14.6k | union { | 86 | 14.6k | const char *char_p; | 87 | 14.6k | const unsigned long *long_p; | 88 | 14.6k | const unsigned int *int_p; | 89 | 14.6k | const unsigned short *short_p; | 90 | 14.6k | } us1, us2; | 91 | 14.6k | us1.char_p = s1; | 92 | 14.6k | us2.char_p = s2; | 93 | 14.6k | FASTCASEMATCH_LOOP(long); | 94 | 8.38k | FASTCASEMATCH_LOOP(int); | 95 | 345 | FASTCASEMATCH_LOOP(short); | 96 | 0 | FASTCASEMATCH_LOOP(char); | 97 | 0 | return 1; | 98 | 0 | } |
parse_authenticate.c:turbo_casematch Line | Count | Source | 84 | 30.5k | { | 85 | 30.5k | union { | 86 | 30.5k | const char *char_p; | 87 | 30.5k | const unsigned long *long_p; | 88 | 30.5k | const unsigned int *int_p; | 89 | 30.5k | const unsigned short *short_p; | 90 | 30.5k | } us1, us2; | 91 | 30.5k | us1.char_p = s1; | 92 | 30.5k | us2.char_p = s2; | 93 | 30.5k | FASTCASEMATCH_LOOP(long); | 94 | 30.5k | FASTCASEMATCH_LOOP(int); | 95 | 3.04k | FASTCASEMATCH_LOOP(short); | 96 | 0 | FASTCASEMATCH_LOOP(char); | 97 | 0 | return 1; | 98 | 0 | } |
|
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 | 2.03k | #define turbo_strcasematch(sarg, S, Slen) ((sarg)->len == (Slen) && \ |
105 | 2.03k | turbo_casematch((sarg)->s, (S), (Slen))) |
106 | | |
107 | | #endif |