1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950 |
- /// @file
- /// @brief `qsort` with carried along context
- /// @ingroup cgraph_utils
- ///
- /// The non-standard `qsort_r`, Windows’ `qsort_s`, and C11’s `qsort_s` provide
- /// a `qsort` alternative with an extra state parameter. Unfortunately none of
- /// these are easily usable portably in Graphviz. This header implements an
- /// alternative that hopefully is.
- #pragma once
- #include <assert.h>
- #include <stdlib.h>
- /// thread-local storage specifier
- #ifdef _MSC_VER
- #define TLS __declspec(thread)
- #elif defined(__GNUC__)
- #define TLS __thread
- #else
- // assume this environment does not support threads and fall back to (thread
- // unsafe) globals
- #define TLS /* nothing */
- #endif
- static TLS int (*gv_sort_compar)(const void *, const void *, void *);
- static TLS void *gv_sort_arg;
- static inline int gv_sort_compar_wrapper(const void *a, const void *b) {
- assert(gv_sort_compar != NULL && "no comparator set in gv_sort");
- return gv_sort_compar(a, b, gv_sort_arg);
- }
- /// `qsort` with an extra state parameter, ala `qsort_r`
- static inline void gv_sort(void *base, size_t nmemb, size_t size,
- int (*compar)(const void *, const void *, void *),
- void *arg) {
- assert(gv_sort_compar == NULL && gv_sort_arg == NULL &&
- "unsupported recursive call to gv_sort");
- gv_sort_compar = compar;
- gv_sort_arg = arg;
- if (nmemb > 1) {
- qsort(base, nmemb, size, gv_sort_compar_wrapper);
- }
- gv_sort_compar = NULL;
- gv_sort_arg = NULL;
- }
|