* Compare `len` bytes at `a` and `b` for case-insensitive equality
*/
static inline bool
-isc_ascii_lowerequal(const uint8_t *a, const uint8_t *b, unsigned int len) {
+isc_ascii_lowerequal(const uint8_t *restrict a, const uint8_t *restrict b,
+ unsigned int len) {
uint64_t a8 = 0, b8 = 0;
- while (len >= 8) {
- a8 = isc_ascii_tolower8(isc__ascii_load8(a));
- b8 = isc_ascii_tolower8(isc__ascii_load8(b));
- if (a8 != b8) {
- return false;
+ if (len >= 8) {
+ const uint8_t *a_tail = a + len - 8;
+ const uint8_t *b_tail = b + len - 8;
+ while (len >= 8) {
+ a8 = isc_ascii_tolower8(isc__ascii_load8(a));
+ b8 = isc_ascii_tolower8(isc__ascii_load8(b));
+ if (a8 != b8) {
+ return false;
+ }
+ len -= 8;
+ a += 8;
+ b += 8;
}
- len -= 8;
- a += 8;
- b += 8;
+
+ a8 = isc_ascii_tolower8(isc__ascii_load8(a_tail));
+ b8 = isc_ascii_tolower8(isc__ascii_load8(b_tail));
+ return a8 == b8;
}
+
while (len-- > 0) {
if (isc_ascii_tolower(*a++) != isc_ascii_tolower(*b++)) {
return false;
--- /dev/null
+#pragma once
+
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the “Software”), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+/* The constant K from Rust's fxhash */
+#define K 0x9e3779b97f4a7c15ull
+
+static inline size_t
+rotate_left(size_t x, unsigned int n) {
+ return (x << n) | (x >> (sizeof(size_t) * 8 - n));
+}
+
+static inline size_t
+fx_add_to_hash(size_t hash, size_t i) {
+ return rotate_left(hash, 5) ^ i * K;
+}
+
+/*
+ * Beware: this implementation will use an approximate conversion to lowercase.
+ * This is ok as fxhash is already not hash-flooding resistant and we use it
+ * only for config parsing.
+ */
+static inline size_t
+fx_hash_bytes(size_t initial_hash, const uint8_t *restrict bytes, size_t len,
+ bool case_sensitive) {
+ size_t hash = initial_hash;
+ size_t case_mask = case_sensitive
+ ? -1ull
+ : (0b11011111 * 0x0101010101010101ull);
+
+ while (len >= sizeof(size_t)) {
+ size_t value;
+ memmove(&value, bytes, sizeof(size_t));
+ hash = fx_add_to_hash(hash, value & case_mask);
+ bytes += sizeof(size_t);
+ len -= sizeof(size_t);
+ }
+
+ /* Will be ignored if sizeof(size_t) <= 4 */
+ if (len >= 4) {
+ uint32_t value;
+ memmove(&value, bytes, sizeof(uint32_t));
+ hash = fx_add_to_hash(hash, value & case_mask);
+ bytes += 4;
+ len -= 4;
+ }
+
+ /* Will be ignored if sizeof(size_t) <= 2 */
+ if (len >= 2) {
+ uint16_t value;
+ memmove(&value, bytes, sizeof(uint16_t));
+ hash = fx_add_to_hash(hash, value & case_mask);
+ bytes += 2;
+ len -= 2;
+ }
+
+ if (len >= 1) {
+ hash = fx_add_to_hash(hash, bytes[0] & case_mask);
+ }
+
+ return hash;
+}
#include <stdbool.h>
#include <isc/ascii.h>
+#include <isc/fxhash.h>
#include <isc/hash.h>
#include <isc/hashmap.h>
#include <isc/magic.h>
isc_symvalue_t value;
} elt_t;
-/* 7 bits means 128 entries at creation, which matches the common use of
+/* 4 bits means 16 entries at creation, which matches the common use of
* symtab */
-#define ISC_SYMTAB_INIT_HASH_BITS 7
+#define ISC_SYMTAB_INIT_HASH_BITS 4
#define SYMTAB_MAGIC ISC_MAGIC('S', 'y', 'm', 'T')
#define VALID_SYMTAB(st) ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
if (case_sensitive) {
return memcmp(elt->key, key->key, key->size) == 0;
} else {
- return isc_ascii_lowercmp(elt->key, key->key, key->size) == 0;
+ return isc_ascii_lowerequal(elt->key, key->key, key->size);
}
}
return elt__match(node, key, false);
}
-static uint32_t
-elt_hash(elt_t *elt, bool case_sensitive) {
- isc_hash32_t hash;
-
- isc_hash32_init(&hash);
- isc_hash32_hash(&hash, elt->key, elt->size, case_sensitive);
- isc_hash32_hash(&hash, &elt->type, sizeof(elt->type), false);
- return isc_hash32_finalize(&hash);
+static inline uint32_t
+elt_hash(elt_t *restrict elt, bool case_sensitive) {
+ const uint8_t *ptr = elt->key;
+ size_t len = elt->size;
+ return fx_hash_bytes(0, ptr, len, case_sensitive);
}
isc_result_t