// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2023 Red Hat */ #include "radix-sort.h" #include <linux/limits.h> #include <linux/types.h> #include "memory-alloc.h" #include "string-utils.h" /* * This implementation allocates one large object to do the sorting, which can be reused as many * times as desired. The amount of memory required is logarithmically proportional to the number of * keys to be sorted. */ /* Piles smaller than this are handled with a simple insertion sort. */ #define INSERTION_SORT_THRESHOLD … /* Sort keys are pointers to immutable fixed-length arrays of bytes. */ sort_key_t; /* * The keys are separated into piles based on the byte in each keys at the current offset, so the * number of keys with each byte must be counted. */ struct histogram { … }; /* * Sub-tasks are manually managed on a stack, both for performance and to put a logarithmic bound * on the stack space needed. */ struct task { … }; struct radix_sorter { … }; /* Compare a segment of two fixed-length keys starting at an offset. */ static inline int compare(sort_key_t key1, sort_key_t key2, u16 offset, u16 length) { … } /* Insert the next unsorted key into an array of sorted keys. */ static inline void insert_key(const struct task task, sort_key_t *next) { … } /* * Sort a range of key segments using an insertion sort. This simple sort is faster than the * 256-way radix sort when the number of keys to sort is small. */ static inline void insertion_sort(const struct task task) { … } /* Push a sorting task onto a task stack. */ static inline void push_task(struct task **stack_pointer, sort_key_t *first_key, u32 count, u16 offset, u16 length) { … } static inline void swap_keys(sort_key_t *a, sort_key_t *b) { … } /* * Count the number of times each byte value appears in the arrays of keys to sort at the current * offset, keeping track of the number of non-empty bins, and the index of the first and last * non-empty bin. */ static inline void measure_bins(const struct task task, struct histogram *bins) { … } /* * Convert the bin sizes to pointers to where each pile goes. * * pile[0] = first_key + bin->size[0], * pile[1] = pile[0] + bin->size[1], etc. * * After the keys are moved to the appropriate pile, we'll need to sort each of the piles by the * next radix position. A new task is put on the stack for each pile containing lots of keys, or a * new task is put on the list for each pile containing few keys. * * @stack: pointer the top of the stack * @end_of_stack: the end of the stack * @list: pointer the head of the list * @pile: array for pointers to the end of each pile * @bins: the histogram of the sizes of each pile * @first_key: the first key of the stack * @offset: the next radix position to sort by * @length: the number of bytes remaining in the sort keys * * Return: UDS_SUCCESS or an error code */ static inline int push_bins(struct task **stack, struct task *end_of_stack, struct task **list, sort_key_t *pile[], struct histogram *bins, sort_key_t *first_key, u16 offset, u16 length) { … } int uds_make_radix_sorter(unsigned int count, struct radix_sorter **sorter) { … } void uds_free_radix_sorter(struct radix_sorter *sorter) { … } /* * Sort pointers to fixed-length keys (arrays of bytes) using a radix sort. The sort implementation * is unstable, so the relative ordering of equal keys is not preserved. */ int uds_radix_sort(struct radix_sorter *sorter, const unsigned char *keys[], unsigned int count, unsigned short length) { … }