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"
};