sort.h 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. /// @file
  2. /// @brief `qsort` with carried along context
  3. /// @ingroup cgraph_utils
  4. ///
  5. /// The non-standard `qsort_r`, Windows’ `qsort_s`, and C11’s `qsort_s` provide
  6. /// a `qsort` alternative with an extra state parameter. Unfortunately none of
  7. /// these are easily usable portably in Graphviz. This header implements an
  8. /// alternative that hopefully is.
  9. #pragma once
  10. #include <assert.h>
  11. #include <stdlib.h>
  12. /// thread-local storage specifier
  13. #ifdef _MSC_VER
  14. #define TLS __declspec(thread)
  15. #elif defined(__GNUC__)
  16. #define TLS __thread
  17. #else
  18. // assume this environment does not support threads and fall back to (thread
  19. // unsafe) globals
  20. #define TLS /* nothing */
  21. #endif
  22. static TLS int (*gv_sort_compar)(const void *, const void *, void *);
  23. static TLS void *gv_sort_arg;
  24. static inline int gv_sort_compar_wrapper(const void *a, const void *b) {
  25. assert(gv_sort_compar != NULL && "no comparator set in gv_sort");
  26. return gv_sort_compar(a, b, gv_sort_arg);
  27. }
  28. /// `qsort` with an extra state parameter, ala `qsort_r`
  29. static inline void gv_sort(void *base, size_t nmemb, size_t size,
  30. int (*compar)(const void *, const void *, void *),
  31. void *arg) {
  32. assert(gv_sort_compar == NULL && gv_sort_arg == NULL &&
  33. "unsupported recursive call to gv_sort");
  34. gv_sort_compar = compar;
  35. gv_sort_arg = arg;
  36. if (nmemb > 1) {
  37. qsort(base, nmemb, size, gv_sort_compar_wrapper);
  38. }
  39. gv_sort_compar = NULL;
  40. gv_sort_arg = NULL;
  41. }