From cc06c355168e28c673b028279b3c1b4177dd407a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADckolas=20Goline?= Date: Fri, 3 Jul 2026 10:14:06 -0300 Subject: [PATCH] ccan: update ccan to fe99a8e0 Includes rustyrussell/ccan#129, which replaces asort's old quicksort fallback with glibc 2.43's mergesort+heapsort. The old fallback called cmp(pivot, pivot) on all-equal arrays, violating the comparator contract that pointer identity implies distinct elements. Mergesort never self-compares, matching qsort_r behaviour on systems without it. This unblocks removing the temporary self-comparison guard in cmp_rr_number(). Changelog-None --- ccan/README | 2 +- ccan/ccan/asort/asort.c | 610 ++++++++++++++++++++++++------------- ccan/ccan/asort/test/run.c | 42 ++- ccan/ccan/base64/base64.c | 72 +++-- 4 files changed, 479 insertions(+), 247 deletions(-) diff --git a/ccan/README b/ccan/README index 8d518c240daa..80a88ad447a0 100644 --- a/ccan/README +++ b/ccan/README @@ -1,3 +1,3 @@ CCAN imported from https://github.com/rustyrussell/ccan. -CCAN version: efd48386 +CCAN version: fe99a8e0 diff --git a/ccan/ccan/asort/asort.c b/ccan/ccan/asort/asort.c index e7eaf2c2999b..b90891ea199e 100644 --- a/ccan/ccan/asort/asort.c +++ b/ccan/ccan/asort/asort.c @@ -5,9 +5,8 @@ /* Steal glibc's code. */ -/* Copyright (C) 1991,1992,1996,1997,1999,2004 Free Software Foundation, Inc. +/* Copyright (C) 1991-2026 Free Software Foundation, Inc. This file is part of the GNU C Library. - Written by Douglas C. Schmidt (schmidt@ics.uci.edu). The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -20,240 +19,437 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ + License along with the GNU C Library; if not, see + . */ /* If you consider tuning this algorithm, you should consult first: Engineering a sort function; Jon Bentley and M. Douglas McIlroy; Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */ +#include +#include #include +#include #include #include +#include -/* Byte-wise swap two items of size SIZE. */ -#define SWAP(a, b, size) \ - do \ - { \ - register size_t __size = (size); \ - register char *__a = (a), *__b = (b); \ - do \ - { \ - char __tmp = *__a; \ - *__a++ = *__b; \ - *__b++ = __tmp; \ - } while (--__size > 0); \ - } while (0) - -/* Discontinue quicksort algorithm when partition gets below this size. - This particular magic number was chosen to work best on a Sun 4/260. */ -#define MAX_THRESH 4 - -/* Stack node declarations used to store unfulfilled partition obligations. */ -typedef struct +/* glibc-internal type, mapped to ccan's equivalent. */ +typedef _total_order_cb __compar_d_fn_t; + +/* glibc-internal helpers, not available outside glibc. */ +static inline void *__mempcpy(void *dst, const void *src, size_t n) +{ + return (char *) memcpy (dst, src, n) + n; +} + +/* glibc-internal helpers, not available outside glibc. */ +static inline void +__memswap (void *__restrict p1, void *__restrict p2, size_t n) +{ + /* Use multiple small memcpys with constant size to enable inlining on most + targets. */ + enum { SWAP_GENERIC_SIZE = 32 }; + unsigned char tmp[SWAP_GENERIC_SIZE]; + while (n > SWAP_GENERIC_SIZE) + { + memcpy (tmp, p1, SWAP_GENERIC_SIZE); + p1 = __mempcpy (p1, p2, SWAP_GENERIC_SIZE); + p2 = __mempcpy (p2, tmp, SWAP_GENERIC_SIZE); + n -= SWAP_GENERIC_SIZE; + } + while (n > 0) + { + unsigned char t = ((unsigned char *)p1)[--n]; + ((unsigned char *)p1)[n] = ((unsigned char *)p2)[n]; + ((unsigned char *)p2)[n] = t; + } +} + +/* Swap SIZE bytes between addresses A and B. These helpers are provided + along the generic one as an optimization. */ + +enum swap_type_t { - char *lo; - char *hi; - } stack_node; - -/* The next 4 #defines implement a very fast in-line stack abstraction. */ -/* The stack needs log (total_elements) entries (we could even subtract - log(MAX_THRESH)). Since total_elements has type size_t, we get as - upper bound for log (total_elements): - bits per byte (CHAR_BIT) * sizeof(size_t). */ -#define STACK_SIZE (CHAR_BIT * sizeof(size_t)) -#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top)) -#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi))) -#define STACK_NOT_EMPTY (stack < top) - - -/* Order size using quicksort. This implementation incorporates - four optimizations discussed in Sedgewick: - - 1. Non-recursive, using an explicit stack of pointer that store the - next array partition to sort. To save time, this maximum amount - of space required to store an array of SIZE_MAX is allocated on the - stack. Assuming a 32-bit (64 bit) integer for size_t, this needs - only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes). - Pretty cheap, actually. - - 2. Chose the pivot element using a median-of-three decision tree. - This reduces the probability of selecting a bad pivot value and - eliminates certain extraneous comparisons. - - 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving - insertion sort to order the MAX_THRESH items within each partition. - This is a big win, since insertion sort is faster for small, mostly - sorted array segments. - - 4. The larger of the two sub-partitions is always pushed onto the - stack first, with the algorithm then concentrating on the - smaller partition. This *guarantees* no more than log (total_elems) - stack size is needed (actually O(1) in this case)! */ + SWAP_WORDS_64, + SWAP_WORDS_32, + SWAP_VOID_ARG, + SWAP_BYTES + }; -void -_asort (void *const pbase, size_t total_elems, size_t size, - int(*cmp)(const void *, const void *, void *arg), - void *arg) +typedef uint32_t __attribute__ ((__may_alias__)) u32_alias_t; +typedef uint64_t __attribute__ ((__may_alias__)) u64_alias_t; + +static inline void +swap_words_64 (void * restrict a, void * restrict b, size_t n) +{ + assert(n && n % 8 == 0); + do + { + n -= 8; + u64_alias_t t = *(u64_alias_t *)(a + n); + *(u64_alias_t *)(a + n) = *(u64_alias_t *)(b + n); + *(u64_alias_t *)(b + n) = t; + } while (n); +} + +static inline void +swap_words_32 (void * restrict a, void * restrict b, size_t n) +{ + assert(n && n % 4 == 0); + do + { + n -= 4; + u32_alias_t t = *(u32_alias_t *)(a + n); + *(u32_alias_t *)(a + n) = *(u32_alias_t *)(b + n); + *(u32_alias_t *)(b + n) = t; + } while (n); +} + +/* Replace the indirect call with a serie of if statements. It should help + the branch predictor. */ +static void +do_swap (void * restrict a, void * restrict b, size_t size, + enum swap_type_t swap_type) +{ + if (swap_type == SWAP_WORDS_64) + swap_words_64 (a, b, size); + else if (swap_type == SWAP_WORDS_32) + swap_words_32 (a, b, size); + else + __memswap (a, b, size); +} + +/* Establish the heap condition at index K, that is, the key at K will + not be less than either of its children, at 2 * K + 1 and 2 * K + 2 + (if they exist). N is the last valid index. */ +static inline void +siftdown (void *base, size_t size, size_t k, size_t n, + enum swap_type_t swap_type, __compar_d_fn_t cmp, void *arg) +{ + /* There can only be a heap condition violation if there are + children. */ + while (2 * k + 1 <= n) + { + /* Left child. */ + size_t j = 2 * k + 1; + /* If the right child is larger, use it. */ + if (j < n && cmp (base + (j * size), base + ((j + 1) * size), arg) < 0) + j++; + + /* If k is already >= to its children, we are done. */ + if (j == k || cmp (base + (k * size), base + (j * size), arg) >= 0) + break; + + /* Heal the violation. */ + do_swap (base + (size * j), base + (k * size), size, swap_type); + + /* Swapping with j may have introduced a violation at j. Fix + it in the next loop iteration. */ + k = j; + } +} + +/* Establish the heap condition for the indices 0 to N (inclusive). */ +static inline void +heapify (void *base, size_t size, size_t n, enum swap_type_t swap_type, + __compar_d_fn_t cmp, void *arg) { - register char *base_ptr = (char *) pbase; + /* If n is odd, k = n / 2 has a left child at n, so this is the + largest index that can have a heap condition violation regarding + its children. */ + size_t k = n / 2; + while (1) + { + siftdown (base, size, k, n, swap_type, cmp, arg); + if (k-- == 0) + break; + } +} + +static enum swap_type_t +get_swap_type (void *const pbase, size_t size) +{ + if ((size & (sizeof (uint32_t) - 1)) == 0 + && ((uintptr_t) pbase) % __alignof__ (uint32_t) == 0) + { + if (size == sizeof (uint32_t)) + return SWAP_WORDS_32; + else if (size == sizeof (uint64_t) + && ((uintptr_t) pbase) % __alignof__ (uint64_t) == 0) + return SWAP_WORDS_64; + } + return SWAP_BYTES; +} + - const size_t max_thresh = MAX_THRESH * size; +/* A non-recursive heapsort with worst-case performance of O(nlog n) and + worst-case space complexity of O(1). It sorts the array starting at + BASE with n + 1 elements of SIZE bytes. The SWAP_TYPE is the callback + function used to swap elements, and CMP is the function used to compare + elements. */ +static void +heapsort_r (void *base, size_t n, size_t size, __compar_d_fn_t cmp, void *arg) +{ + if (n == 0) + return; + + enum swap_type_t swap_type = get_swap_type (base, size); + + /* Build the binary heap, largest value at the base[0]. */ + heapify (base, size, n, swap_type, cmp, arg); + + while (true) + { + /* Indices 0 .. n contain the binary heap. Extract the largest + element put it into the final position in the array. */ + do_swap (base, base + (n * size), size, swap_type); + + /* The heap is now one element shorter. */ + n--; + if (n == 0) + break; + + /* By swapping in elements 0 and the previous value of n (now at + n + 1), we likely introduced a heap condition violation. Fix + it for the reduced heap. */ + siftdown (base, size, 0, n, swap_type, cmp, arg); + } +} + +/* The maximum size in bytes required by mergesort that will be provided + through a buffer allocated in the stack. */ +#define QSORT_STACK_SIZE 1024 + +/* Elements larger than this value will be sorted through indirect sorting + to minimize the need to memory swap calls. */ +#define INDIRECT_SORT_SIZE_THRES 32 + +struct msort_param +{ + size_t s; + enum swap_type_t var; + __compar_d_fn_t cmp; + void *arg; + char *t; +}; + +static void +msort_with_tmp (const struct msort_param *p, void *b, size_t n) +{ + char *b1, *b2; + size_t n1, n2; - if (total_elems == 0) - /* Avoid lossage with unsigned arithmetic below. */ + if (n <= 1) return; - if (total_elems > MAX_THRESH) + n1 = n / 2; + n2 = n - n1; + b1 = b; + b2 = (char *) b + (n1 * p->s); + + msort_with_tmp (p, b1, n1); + msort_with_tmp (p, b2, n2); + + char *tmp = p->t; + const size_t s = p->s; + __compar_d_fn_t cmp = p->cmp; + void *arg = p->arg; + switch (p->var) { - char *lo = base_ptr; - char *hi = &lo[size * (total_elems - 1)]; - stack_node stack[STACK_SIZE]; - stack_node *top = stack; - - PUSH (NULL, NULL); - - while (STACK_NOT_EMPTY) - { - char *left_ptr; - char *right_ptr; - - /* Select median value from among LO, MID, and HI. Rearrange - LO and HI so the three values are sorted. This lowers the - probability of picking a pathological pivot value and - skips a comparison for both the LEFT_PTR and RIGHT_PTR in - the while loops. */ - - char *mid = lo + size * ((hi - lo) / size >> 1); - - if ((*cmp) ((void *) mid, (void *) lo, arg) < 0) - SWAP (mid, lo, size); - if ((*cmp) ((void *) hi, (void *) mid, arg) < 0) - SWAP (mid, hi, size); + case SWAP_WORDS_32: + while (n1 > 0 && n2 > 0) + { + if (cmp (b1, b2, arg) <= 0) + { + *(u32_alias_t *) tmp = *(u32_alias_t *) b1; + b1 += sizeof (u32_alias_t); + --n1; + } else - goto jump_over; - if ((*cmp) ((void *) mid, (void *) lo, arg) < 0) - SWAP (mid, lo, size); - jump_over:; - - left_ptr = lo + size; - right_ptr = hi - size; - - /* Here's the famous ``collapse the walls'' section of quicksort. - Gotta like those tight inner loops! They are the main reason - that this algorithm runs much faster than others. */ - do { - while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0) - left_ptr += size; - - while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0) - right_ptr -= size; - - if (left_ptr < right_ptr) - { - SWAP (left_ptr, right_ptr, size); - if (mid == left_ptr) - mid = right_ptr; - else if (mid == right_ptr) - mid = left_ptr; - left_ptr += size; - right_ptr -= size; - } - else if (left_ptr == right_ptr) - { - left_ptr += size; - right_ptr -= size; - break; - } + *(u32_alias_t *) tmp = *(u32_alias_t *) b2; + b2 += sizeof (u32_alias_t); + --n2; + } + tmp += sizeof (u32_alias_t); + } + break; + case SWAP_WORDS_64: + while (n1 > 0 && n2 > 0) + { + if (cmp (b1, b2, arg) <= 0) + { + *(u64_alias_t *) tmp = *(u64_alias_t *) b1; + b1 += sizeof (u64_alias_t); + --n1; } - while (left_ptr <= right_ptr); - - /* Set up pointers for next iteration. First determine whether - left and right partitions are below the threshold size. If so, - ignore one or both. Otherwise, push the larger partition's - bounds on the stack and continue sorting the smaller one. */ - - if ((size_t) (right_ptr - lo) <= max_thresh) - { - if ((size_t) (hi - left_ptr) <= max_thresh) - /* Ignore both small partitions. */ - POP (lo, hi); - else - /* Ignore small left partition. */ - lo = left_ptr; - } - else if ((size_t) (hi - left_ptr) <= max_thresh) - /* Ignore small right partition. */ - hi = right_ptr; - else if ((right_ptr - lo) > (hi - left_ptr)) - { - /* Push larger left partition indices. */ - PUSH (lo, right_ptr); - lo = left_ptr; - } - else - { - /* Push larger right partition indices. */ - PUSH (left_ptr, hi); - hi = right_ptr; - } - } + else + { + *(u64_alias_t *) tmp = *(u64_alias_t *) b2; + b2 += sizeof (u64_alias_t); + --n2; + } + tmp += sizeof (u64_alias_t); + } + break; + case SWAP_VOID_ARG: + while (n1 > 0 && n2 > 0) + { + if ((*cmp) (*(const void **) b1, *(const void **) b2, arg) <= 0) + { + *(void **) tmp = *(void **) b1; + b1 += sizeof (void *); + --n1; + } + else + { + *(void **) tmp = *(void **) b2; + b2 += sizeof (void *); + --n2; + } + tmp += sizeof (void *); + } + break; + default: + while (n1 > 0 && n2 > 0) + { + if (cmp (b1, b2, arg) <= 0) + { + tmp = (char *) __mempcpy (tmp, b1, s); + b1 += s; + --n1; + } + else + { + tmp = (char *) __mempcpy (tmp, b2, s); + b2 += s; + --n2; + } + } + break; } - /* Once the BASE_PTR array is partially sorted by quicksort the rest - is completely sorted using insertion sort, since this is efficient - for partitions below MAX_THRESH size. BASE_PTR points to the beginning - of the array to sort, and END_PTR points at the very last element in - the array (*not* one beyond it!). */ + if (n1 > 0) + memcpy (tmp, b1, n1 * s); + memcpy (b, p->t, (n - n2) * s); +} -#define min(x, y) ((x) < (y) ? (x) : (y)) +static void +indirect_msort_with_tmp (const struct msort_param *p, void *b, size_t n, + size_t s) +{ + /* Indirect sorting. */ + char *ip = (char *) b; + void **tp = (void **) (p->t + n * sizeof (void *)); + void **t = tp; + void *tmp_storage = (void *) (tp + n); - { - char *const end_ptr = &base_ptr[size * (total_elems - 1)]; - char *tmp_ptr = base_ptr; - char *thresh = min(end_ptr, base_ptr + max_thresh); - register char *run_ptr; + while ((void *) t < tmp_storage) + { + *t++ = ip; + ip += s; + } + msort_with_tmp (p, p->t + n * sizeof (void *), n); + + /* tp[0] .. tp[n - 1] is now sorted, copy around entries of + the original array. Knuth vol. 3 (2nd ed.) exercise 5.2-10. */ + char *kp; + size_t i; + for (i = 0, ip = (char *) b; i < n; i++, ip += s) + if ((kp = tp[i]) != ip) + { + size_t j = i; + char *jp = ip; + memcpy (tmp_storage, ip, s); + + do + { + size_t k = (kp - (char *) b) / s; + tp[j] = jp; + memcpy (jp, kp, s); + j = k; + jp = kp; + kp = tp[k]; + } + while (kp != ip); + + tp[j] = jp; + memcpy (jp, tmp_storage, s); + } +} - /* Find smallest element in first threshold and place it at the - array's beginning. This is the smallest array element, - and the operation speeds up insertion sort's inner loop. */ +static void +qsort_r_mergesort (void *const pbase, size_t total_elems, size_t size, + __compar_d_fn_t cmp, void *arg, void *buf) +{ + if (size > INDIRECT_SORT_SIZE_THRES) + { + const struct msort_param msort_param = + { + .s = sizeof (void *), + .cmp = cmp, + .arg = arg, + .var = SWAP_VOID_ARG, + .t = buf, + }; + indirect_msort_with_tmp (&msort_param, pbase, total_elems, size); + } + else + { + const struct msort_param msort_param = + { + .s = size, + .cmp = cmp, + .arg = arg, + .var = get_swap_type (pbase, size), + .t = buf, + }; + msort_with_tmp (&msort_param, pbase, total_elems); + } +} - for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) - if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0) - tmp_ptr = run_ptr; +static bool +qsort_r_malloc (void *const pbase, size_t total_elems, size_t size, + __compar_d_fn_t cmp, void *arg, size_t total_size) +{ + int save = errno; + char *buf = malloc (total_size); + errno = save; + if (buf == NULL) + return false; - if (tmp_ptr != base_ptr) - SWAP (tmp_ptr, base_ptr, size); + qsort_r_mergesort (pbase, total_elems, size, cmp, arg, buf); - /* Insertion sort, running from left-hand-side up to right-hand-side. */ + free (buf); - run_ptr = base_ptr + size; - while ((run_ptr += size) <= end_ptr) - { - tmp_ptr = run_ptr - size; - while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0) - tmp_ptr -= size; - - tmp_ptr += size; - if (tmp_ptr != run_ptr) - { - char *trav; - - trav = run_ptr + size; - while (--trav >= run_ptr) - { - char c = *trav; - char *hi, *lo; - - for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) - *hi = *lo; - *hi = c; - } - } - } - } + return true; +} + +void +_asort (void *const pbase, size_t total_elems, size_t size, + _total_order_cb cmp, void *arg) +{ + if (total_elems <= 1) + return; + + /* Align to the maximum size used by the swap optimization. */ + size_t total_size = total_elems * size; + + if (size > INDIRECT_SORT_SIZE_THRES) + total_size = 2 * total_elems * sizeof (void *) + size; + + if (total_size <= QSORT_STACK_SIZE) + { + _Alignas (uint64_t) char tmp[QSORT_STACK_SIZE]; + qsort_r_mergesort (pbase, total_elems, size, cmp, arg, tmp); + } + else + { + if (!qsort_r_malloc (pbase, total_elems, size, cmp, arg, total_size)) + /* Fallback to heapsort in case of memory failure. */ + heapsort_r (pbase, total_elems - 1, size, cmp, arg); + } } #endif /* !HAVE_QSORT_R_PRIVATE_LAST */ diff --git a/ccan/ccan/asort/test/run.c b/ccan/ccan/asort/test/run.c index e07fe283406a..9d4559c586e0 100644 --- a/ccan/ccan/asort/test/run.c +++ b/ccan/ccan/asort/test/run.c @@ -43,6 +43,20 @@ static void pseudo_random_array(int arr[], unsigned int size) arr[i] = i * (INT_MAX / 4 - 7); } +/* Track whether the comparator was ever called with identical pointers. */ +static bool self_compared; + +static int test_cmp_self(const int *a, const int *b, void *unused) +{ + if (a == b) + self_compared = true; + if (*a < *b) + return -1; + if (*a > *b) + return 1; + return 0; +} + #define TEST_SIZE 100 int main(void) @@ -50,7 +64,7 @@ int main(void) int tmparr[TEST_SIZE]; int multiplier = 1; - plan_tests(4); + plan_tests(8); pseudo_random_array(tmparr, TEST_SIZE); ok1(!is_sorted(tmparr, TEST_SIZE)); @@ -64,5 +78,31 @@ int main(void) asort(tmparr, TEST_SIZE, test_cmp, &multiplier); ok1(is_reverse_sorted(tmparr, TEST_SIZE)); + /* Sorting an array with all equal elements must not crash and must + * produce a sorted result regardless of whether the comparator + * receives identical pointers (self-comparisons are permitted by + * the C standard and done by some qsort implementations). */ + for (int i = 0; i < TEST_SIZE; i++) + tmparr[i] = 42; + self_compared = false; + asort(tmparr, TEST_SIZE, test_cmp_self, NULL); + ok1(is_sorted(tmparr, TEST_SIZE)); + + /* Sorting a single element must not crash. */ + tmparr[0] = 7; + asort(tmparr, 1, test_cmp_self, NULL); + ok1(tmparr[0] == 7); + + /* Force a self-comparison directly to verify the comparator handles it. */ + { + int val = 42; + self_compared = false; + ok1(test_cmp_self(&val, &val, NULL) == 0); + ok1(self_compared); + } + + diag("asort comparator called with identical pointers: %s", + self_compared ? "yes" : "no"); + return exit_status(); } diff --git a/ccan/ccan/base64/base64.c b/ccan/ccan/base64/base64.c index 89e0d38b4621..212e9b5583cb 100644 --- a/ccan/ccan/base64/base64.c +++ b/ccan/ccan/base64/base64.c @@ -212,42 +212,38 @@ ssize_t base64_decode_using_maps(const base64_maps_t *maps, const base64_maps_t base64_maps_rfc4648 = { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", - "\xff\xff\xff\xff\xff" /* 0 */ \ - "\xff\xff\xff\xff\xff" /* 5 */ \ - "\xff\xff\xff\xff\xff" /* 10 */ \ - "\xff\xff\xff\xff\xff" /* 15 */ \ - "\xff\xff\xff\xff\xff" /* 20 */ \ - "\xff\xff\xff\xff\xff" /* 25 */ \ - "\xff\xff\xff\xff\xff" /* 30 */ \ - "\xff\xff\xff\xff\xff" /* 35 */ \ - "\xff\xff\xff\x3e\xff" /* 40 */ \ - "\xff\xff\x3f\x34\x35" /* 45 */ \ - "\x36\x37\x38\x39\x3a" /* 50 */ \ - "\x3b\x3c\x3d\xff\xff" /* 55 */ \ - "\xff\xff\xff\xff\xff" /* 60 */ \ - "\x00\x01\x02\x03\x04" /* 65 A */ \ - "\x05\x06\x07\x08\x09" /* 70 */ \ - "\x0a\x0b\x0c\x0d\x0e" /* 75 */ \ - "\x0f\x10\x11\x12\x13" /* 80 */ \ - "\x14\x15\x16\x17\x18" /* 85 */ \ - "\x19\xff\xff\xff\xff" /* 90 */ \ - "\xff\xff\x1a\x1b\x1c" /* 95 */ \ - "\x1d\x1e\x1f\x20\x21" /* 100 */ \ - "\x22\x23\x24\x25\x26" /* 105 */ \ - "\x27\x28\x29\x2a\x2b" /* 110 */ \ - "\x2c\x2d\x2e\x2f\x30" /* 115 */ \ - "\x31\x32\x33\xff\xff" /* 120 */ \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 125 */ \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 155 */ \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 185 */ \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 215 */ \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ - "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 245 */ + /* 0 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 10 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 20 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 30 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 40 */ "\xff\xff\xff\x3e\xff" \ + /* 45 */ "\xff\xff\x3f\x34\x35" \ + /* 50 */ "\x36\x37\x38\x39\x3a" \ + /* 55 */ "\x3b\x3c\x3d\xff\xff" \ + /* 60 */ "\xff\xff\xff\xff\xff" \ + /* 65 */ "\x00\x01\x02\x03\x04" /* A */ \ + /* 70 */ "\x05\x06\x07\x08\x09" \ + /* 75 */ "\x0a\x0b\x0c\x0d\x0e" \ + /* 80 */ "\x0f\x10\x11\x12\x13" \ + /* 85 */ "\x14\x15\x16\x17\x18" \ + /* 90 */ "\x19\xff\xff\xff\xff" \ + /* 95 */ "\xff\xff\x1a\x1b\x1c" \ + /* 100 */ "\x1d\x1e\x1f\x20\x21" \ + /* 105 */ "\x22\x23\x24\x25\x26" \ + /* 110 */ "\x27\x28\x29\x2a\x2b" \ + /* 115 */ "\x2c\x2d\x2e\x2f\x30" \ + /* 120 */ "\x31\x32\x33\xff\xff" \ + /* 125 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 135 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 145 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 155 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 165 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 175 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 185 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 195 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 205 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 215 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 225 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 235 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ + /* 245 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" };