| Server IP : 216.92.14.13 / Your IP : 216.73.216.171 Web Server : Apache System : Linux vps4089.pairvps.com 5.15.0-190-generic #200-Ubuntu SMP Fri Aug 7 15:06:04 UTC 2026 x86_64 User : rmlac2fmr ( 1040637) PHP Version : 8.2.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /usr/include/isc/ |
Upload File : |
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <isc/endian.h>
/*
* ASCII case conversion
*/
extern const uint8_t isc__ascii_tolower[256];
extern const uint8_t isc__ascii_toupper[256];
/*
* Wrappers so we don't have to cast all over the place like <ctype.h>
*/
#define isc_ascii_tolower(c) isc__ascii_tolower[(uint8_t)(c)]
#define isc_ascii_toupper(c) isc__ascii_toupper[(uint8_t)(c)]
/*
* A variant tolower() implementation with no memory accesses,
* for use when the compiler is able to autovectorize.
*/
static inline uint8_t
isc__ascii_tolower1(uint8_t c) {
return c + ('a' - 'A') * ('A' <= c && c <= 'Z');
}
/*
* Copy `len` bytes from `src` to `dst`, converting to lower case.
*/
static inline void
isc_ascii_lowercopy(uint8_t *dst, const uint8_t *src, unsigned int len) {
while (len-- > 0) {
*dst++ = isc__ascii_tolower1(*src++);
}
}
/*
* Convert a string to lower case in place
*/
static inline void
isc_ascii_strtolower(char *str) {
isc_ascii_lowercopy((uint8_t *)str, (uint8_t *)str,
(unsigned int)strlen(str));
}
/*
* Convert 8 bytes to lower case, using SWAR tricks (SIMD within a register).
* Based on "Hacker's Delight" by Henry S. Warren, "searching for a value in a
* given range", p. 95. Eight bytes is wider than many labels in DNS names, so
* it does not seem worth dealing with the portability issues of wide vector
* registers. If there was a vector string load instruction (analogous to
* memove() below) the balance might be different.
*/
static inline uint64_t
isc_ascii_tolower8(uint64_t octets) {
/*
* Multiply a single-byte constant by `all_bytes` to replicate
* it to all eight bytes in a word.
*/
uint64_t all_bytes = 0x0101010101010101;
/*
* Clear the top bit of each byte to make space for a per-byte flag.
*/
uint64_t heptets = octets & (0x7F * all_bytes);
/*
* We will need to avoid going wrong if our flag bits were originally
* set, and clear calculation leftovers in our non-flag bits
*/
uint64_t is_ascii = ~octets & (0x80 * all_bytes);
/*
* To compare a heptet to `N`, we can add `0x7F - N` so that carry
* propagation will set the flag when our heptet is greater than `N`
*/
uint64_t is_gt_Z = heptets + (0x7F - 'Z') * all_bytes;
/*
* Add one for greater-than-or-equal comparison
*/
uint64_t is_ge_A = heptets + (0x80 - 'A') * all_bytes;
/*
* Now we have what we need to identify the ascii uppercase bytes
*/
uint64_t is_upper = (is_ge_A ^ is_gt_Z) & is_ascii;
/*
* Move the is_upper flag bits to bit 0x20 (which is 'a' - 'A')
* and use them to adjust each byte as required
*/
return octets | (is_upper >> 2);
}
/*
* Same, but 4 bytes at a time, used by isc_halfsiphash24()
*/
static inline uint32_t
isc_ascii_tolower4(uint32_t octets) {
uint32_t all_bytes = 0x01010101;
uint32_t heptets = octets & (0x7F * all_bytes);
uint32_t is_ascii = ~octets & (0x80 * all_bytes);
uint32_t is_gt_Z = heptets + (0x7F - 'Z') * all_bytes;
uint32_t is_ge_A = heptets + (0x80 - 'A') * all_bytes;
uint32_t is_upper = (is_ge_A ^ is_gt_Z) & is_ascii;
return octets | (is_upper >> 2);
}
/*
* Helper function to do an unaligned load of 8 bytes in host byte order
*/
static inline uint64_t
isc__ascii_load8(const uint8_t *ptr) {
uint64_t bytes = 0;
memmove(&bytes, ptr, sizeof(bytes));
return bytes;
}
/*
* 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) {
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;
}
len -= 8;
a += 8;
b += 8;
}
while (len-- > 0) {
if (isc_ascii_tolower(*a++) != isc_ascii_tolower(*b++)) {
return false;
}
}
return true;
}
/*
* Compare `len` bytes at `a` and `b` for case-insensitive order.
* Unlike the previous functions (which do not need to care about byte
* order) here we need to ensure the comparisons are lexicographic,
* i.e. they treat the strings as big-endian numbers.
*/
static inline int
isc_ascii_lowercmp(const uint8_t *a, const uint8_t *b, unsigned int len) {
uint64_t a8 = 0, b8 = 0;
while (len >= 8) {
a8 = isc_ascii_tolower8(htobe64(isc__ascii_load8(a)));
b8 = isc_ascii_tolower8(htobe64(isc__ascii_load8(b)));
if (a8 != b8) {
goto ret;
}
len -= 8;
a += 8;
b += 8;
}
while (len-- > 0) {
a8 = isc_ascii_tolower(*a++);
b8 = isc_ascii_tolower(*b++);
if (a8 != b8) {
goto ret;
}
}
ret:
if (a8 < b8) {
return -1;
}
if (a8 > b8) {
return +1;
}
return 0;
}