1
0

xs_list_tools.h 3.8 KB

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