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