ascii.c revision 1.2 1 /* $NetBSD: ascii.c,v 1.2 2025/01/26 16:25:47 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 #include <stdbool.h>
17 #include <stdint.h>
18 #include <stdio.h>
19 #include <string.h>
20
21 #include <isc/ascii.h>
22 #include <isc/random.h>
23 #include <isc/time.h>
24
25 #define SIZE (1024 * 1024)
26
27 typedef void
28 copy_fn(void *a, void *b, unsigned int len);
29
30 static void
31 time_it(copy_fn *copier, void *a, void *b, const char *name) {
32 isc_time_t start;
33 start = isc_time_now_hires();
34
35 copier(a, b, SIZE);
36
37 isc_time_t finish;
38 finish = isc_time_now_hires();
39
40 uint64_t microseconds = isc_time_microdiff(&finish, &start);
41 printf("%f for %s\n", (double)microseconds / 1000000.0, name);
42 }
43
44 static void
45 copy_raw(void *a, void *b, unsigned int size) {
46 memmove(a, b, size);
47 }
48
49 static void
50 copy_toupper(void *va, void *vb, unsigned int size) {
51 uint8_t *a = va, *b = vb;
52 while (size-- > 0) {
53 *a++ = isc_ascii_toupper(*b++);
54 }
55 }
56
57 static void
58 copy_tolower8(void *a, void *b, unsigned int size) {
59 isc_ascii_lowercopy(a, b, size);
60 }
61
62 #define TOLOWER(c) ((c) + ('a' - 'A') * (((c) >= 'A') ^ ((c) > 'Z')))
63
64 static void
65 copy_tolower1(void *va, void *vb, unsigned int size) {
66 for (uint8_t *a = va, *b = vb; size-- > 0; a++, b++) {
67 *a = TOLOWER(*b);
68 }
69 }
70
71 static bool
72 cmp_tolower1(void *va, void *vb, unsigned int size) {
73 for (uint8_t *a = va, *b = vb; size-- > 0; a++, b++) {
74 if (TOLOWER(*a) != TOLOWER(*b)) {
75 return false;
76 }
77 }
78 return true;
79 }
80
81 static bool oldskool_result;
82
83 static void
84 cmp_oldskool(void *va, void *vb, unsigned int size) {
85 uint8_t *a = va, *b = vb, c;
86
87 while (size > 3) {
88 c = isc_ascii_tolower(a[0]);
89 if (c != isc_ascii_tolower(b[0])) {
90 goto diff;
91 }
92 c = isc_ascii_tolower(a[1]);
93 if (c != isc_ascii_tolower(b[1])) {
94 goto diff;
95 }
96 c = isc_ascii_tolower(a[2]);
97 if (c != isc_ascii_tolower(b[2])) {
98 goto diff;
99 }
100 c = isc_ascii_tolower(a[3]);
101 if (c != isc_ascii_tolower(b[3])) {
102 goto diff;
103 }
104 size -= 4;
105 a += 4;
106 b += 4;
107 }
108 while (size-- > 0) {
109 c = isc_ascii_tolower(*a++);
110 if (c != isc_ascii_tolower(*b++)) {
111 goto diff;
112 }
113 }
114 oldskool_result = true;
115 return;
116 diff:
117 oldskool_result = false;
118 return;
119 }
120
121 static bool tolower1_result;
122
123 static void
124 vcmp_tolower1(void *a, void *b, unsigned int size) {
125 tolower1_result = cmp_tolower1(a, b, size);
126 }
127
128 static bool swar_result;
129
130 static void
131 cmp_swar(void *a, void *b, unsigned int size) {
132 swar_result = isc_ascii_lowerequal(a, b, size);
133 }
134
135 static bool chunk_result;
136 static unsigned int chunk_size;
137
138 static void
139 cmp_chunks1(void *va, void *vb, unsigned int size) {
140 uint8_t *a = va, *b = vb;
141
142 chunk_result = false;
143 while (size >= chunk_size) {
144 if (!cmp_tolower1(a, b, chunk_size)) {
145 return;
146 }
147 size -= chunk_size;
148 a += chunk_size;
149 b += chunk_size;
150 }
151 chunk_result = cmp_tolower1(a, b, size);
152 }
153
154 static void
155 cmp_chunks8(void *va, void *vb, unsigned int size) {
156 uint8_t *a = va, *b = vb;
157
158 while (size >= chunk_size) {
159 if (!isc_ascii_lowerequal(a, b, chunk_size)) {
160 goto diff;
161 }
162 size -= chunk_size;
163 a += chunk_size;
164 b += chunk_size;
165 }
166 chunk_result = isc_ascii_lowerequal(a, b, size);
167 return;
168 diff:
169 chunk_result = false;
170 return;
171 }
172
173 static void
174 cmp_oldchunks(void *va, void *vb, unsigned int size) {
175 uint8_t *a = va, *b = vb;
176
177 while (size >= chunk_size) {
178 cmp_oldskool(a, b, chunk_size);
179 if (!oldskool_result) {
180 return;
181 }
182 size -= chunk_size;
183 a += chunk_size;
184 b += chunk_size;
185 }
186 cmp_oldskool(a, b, size);
187 }
188
189 int
190 main(void) {
191 static uint8_t bytes[SIZE];
192
193 isc_random_buf(bytes, SIZE);
194
195 static uint8_t raw_dest[SIZE];
196 time_it(copy_raw, raw_dest, bytes, "memmove");
197
198 static uint8_t toupper_dest[SIZE];
199 time_it(copy_toupper, toupper_dest, bytes, "toupper");
200
201 static uint8_t tolower1_dest[SIZE];
202 time_it(copy_tolower1, tolower1_dest, bytes, "tolower1");
203
204 static uint8_t tolower8_dest[SIZE];
205 time_it(copy_tolower8, tolower8_dest, bytes, "tolower8");
206
207 time_it(cmp_oldskool, toupper_dest, tolower1_dest, "oldskool");
208 printf("-> %s\n", oldskool_result ? "same" : "WAT");
209
210 time_it(vcmp_tolower1, tolower1_dest, tolower8_dest, "tolower1");
211 printf("-> %s\n", tolower1_result ? "same" : "WAT");
212
213 time_it(cmp_swar, toupper_dest, tolower8_dest, "swar");
214 printf("-> %s\n", swar_result ? "same" : "WAT");
215
216 for (chunk_size = 3; chunk_size <= 15; chunk_size += 2) {
217 time_it(cmp_chunks1, toupper_dest, raw_dest, "chunks1");
218 printf("%u -> %s\n", chunk_size, chunk_result ? "same" : "WAT");
219 time_it(cmp_chunks8, toupper_dest, raw_dest, "chunks8");
220 printf("%u -> %s\n", chunk_size, chunk_result ? "same" : "WAT");
221 time_it(cmp_oldchunks, toupper_dest, raw_dest, "oldchunks");
222 printf("%u -> %s\n", chunk_size,
223 oldskool_result ? "same" : "WAT");
224 }
225 }
226