xs_list_tools.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /* copyright (c) 2022 - 2026 grunfink et al. / MIT license */
  2. #ifndef _XS_LIST_TOOLS_H
  3. #define _XS_LIST_TOOLS_H
  4. xs_list *xs_list_insert_sorted(xs_list *list, const xs_val *nv);
  5. xs_val **xs_list_to_array(const xs_list *l, int *len);
  6. int xs_list_sort_cmp(const void *p1, const void *p2);
  7. int xs_list_sort_inv_cmp(const void *p1, const void *p2);
  8. int xs_list_sort_dict_cmp(const char *field, const void *p1, const void *p2);
  9. xs_list *xs_list_sort(const xs_list *l, int (*cmp)(const void *, const void *));
  10. xs_list *xs_list_shuffle(const xs_list *l);
  11. #ifdef XS_IMPLEMENTATION
  12. #include "xs_random.h"
  13. xs_list *xs_list_insert_sorted(xs_list *list, const xs_val *nv)
  14. /* inserts a string in the list in its ordered position */
  15. {
  16. XS_ASSERT_TYPE(list, XSTYPE_LIST);
  17. int offset = xs_size(list);
  18. const xs_val *v;
  19. xs_list_foreach(list, v) {
  20. /* if this element is greater or equal, insert here */
  21. if (xs_cmp(v, nv) >= 0) {
  22. offset = v - list;
  23. break;
  24. }
  25. }
  26. return _xs_list_write_litem(list, offset - 1, nv, xs_size(nv));
  27. }
  28. xs_val **xs_list_to_array(const xs_list *l, int *len)
  29. /* converts a list to an array of values */
  30. /* must be freed after use */
  31. {
  32. *len = xs_list_len(l);
  33. xs_val **a = xs_realloc(NULL, *len * sizeof(xs_val *));
  34. const xs_val *v;
  35. int n = 0;
  36. xs_list_foreach(l, v)
  37. a[n++] = (xs_val *)v;
  38. return a;
  39. }
  40. int xs_list_sort_cmp(const void *p1, const void *p2)
  41. /* default list sorting function */
  42. {
  43. const xs_val *v1 = *(xs_val **)p1;
  44. const xs_val *v2 = *(xs_val **)p2;
  45. return xs_cmp(v1, v2);
  46. }
  47. int xs_list_sort_inv_cmp(const void *p1, const void *p2)
  48. /* default list inverse sorting function */
  49. {
  50. const xs_val *v1 = *(xs_val **)p1;
  51. const xs_val *v2 = *(xs_val **)p2;
  52. return xs_cmp(v2, v1);
  53. }
  54. int xs_list_sort_dict_cmp(const char *field, const void *p1, const void *p2)
  55. /* compare sorting function for a field an array of dicts */
  56. {
  57. const xs_dict *d1 = *(xs_val **)p1;
  58. const xs_dict *d2 = *(xs_val **)p2;
  59. if (xs_type(d1) != XSTYPE_DICT || xs_type(d2) != XSTYPE_DICT)
  60. return 0;
  61. return xs_cmp(xs_dict_get_def(d1, field, ""),
  62. xs_dict_get_def(d2, field, ""));
  63. }
  64. xs_list *xs_list_sort(const xs_list *l, int (*cmp)(const void *, const void *))
  65. /* returns a sorted copy of l. cmp can be null for standard sorting */
  66. {
  67. int sz;
  68. xs_val **a = xs_list_to_array(l, &sz);
  69. xs_list *nl = xs_dup(l);
  70. char *p = nl + 1 + _XS_TYPE_SIZE;
  71. /* sort the array */
  72. qsort(a, sz, sizeof(xs_val *), cmp ? cmp : xs_list_sort_cmp);
  73. /* transfer the sorted list over the copy */
  74. for (int n = 0; n < sz; n++) {
  75. /* get the litem */
  76. const char *e = a[n] - 1;
  77. int z = xs_size(e);
  78. memcpy(p, e, z);
  79. p += z;
  80. }
  81. xs_free(a);
  82. return nl;
  83. }
  84. xs_list *xs_list_shuffle(const xs_list *l)
  85. /* returns a shuffled list */
  86. {
  87. int sz;
  88. xs_val **a = xs_list_to_array(l, &sz);
  89. xs_list *nl = xs_list_new();
  90. unsigned int seed = 0;
  91. xs_rnd_buf(&seed, sizeof(seed));
  92. /* shuffle */
  93. for (int n = sz - 1; n > 0; n--) {
  94. int m = xs_rnd_int32_d(&seed) % n;
  95. void *p = a[n];
  96. a[n] = a[m];
  97. a[m] = p;
  98. }
  99. for (int n = 0; n < sz; n++)
  100. nl = xs_list_append(nl, a[n]);
  101. xs_free(a);
  102. return nl;
  103. }
  104. #endif /* XS_IMPLEMENTATION */
  105. #endif /* XS_LIST_TOOLS_H */