Branch data Line data Source code
1 : : #include "codegen_c_sort.h"
2 : :
3 : : /*
4 : : * We choose heapsort because it is about as fast as quicksort, avoids
5 : : * recursion, the code is compact which makes it practical to specialize for
6 : : * different vector types, it can sort the flatbuffer arrays in-place,
7 : : * and it has only a few places with comparisons. Furthermore, heapsort
8 : : * has worst case (n log n) upperbound where quicksort has O(n^2) which
9 : : * is an attack vector, and could be a problem with large datasets
10 : : * The sort is not stable.
11 : : *
12 : : * Some arguments are similar to those of the __%sfind_by_field macro.
13 : : *
14 : : * NS: The namespace
15 : : * N: the name of the vector type
16 : : * X: the name suffix when there are multiple sorts for same vector type.
17 : : * E: Element accessor (elem = E(vector, index)).
18 : : * L: Vector length.
19 : : * A: Field accessor (or the identity function), result must match the diff function D.
20 : : * TK: The scalar, enum or string key type, (either the element, or a field of the element).
21 : : * TE: The raw element type - uoffset_t for tables and strings.
22 : : * for swap.
23 : : * D: The diff function, but unlike __find_by_field, the second
24 : : * argument is returned by A, not a search key, and there is no third argument.
25 : : * S: Swap operation - must handle offset change when offset elements are moved.
26 : : */
27 : :
28 : 10 : int gen_sort(fb_output_t *out)
29 : : {
30 : 10 : fprintf(out->fp,
31 : : "#define __%sheap_sort(N, X, A, E, L, TK, TE, D, S)\\\n"
32 : : "static inline void __ ## N ## X ## __heap_sift_down(\\\n"
33 : : " N ## _mutable_vec_t vec, size_t start, size_t end)\\\n"
34 : : "{ size_t child, root; TK v1, v2, vroot;\\\n"
35 : : " root = start;\\\n"
36 : : " while ((root << 1) <= end) {\\\n"
37 : : " child = root << 1;\\\n"
38 : : " if (child < end) {\\\n"
39 : : " v1 = A(E(vec, child));\\\n"
40 : : " v2 = A(E(vec, child + 1));\\\n"
41 : : " if (D(v1, v2) < 0) {\\\n"
42 : : " child++;\\\n"
43 : : " }\\\n"
44 : : " }\\\n"
45 : : " vroot = A(E(vec, root));\\\n"
46 : : " v1 = A(E(vec, child));\\\n"
47 : : " if (D(vroot, v1) < 0) {\\\n"
48 : : " S(vec, root, child, TE);\\\n"
49 : : " root = child;\\\n"
50 : : " } else {\\\n"
51 : : " return;\\\n"
52 : : " }\\\n"
53 : : " }\\\n"
54 : : "}\\\n"
55 : : "static inline void __ ## N ## X ## __heap_sort(N ## _mutable_vec_t vec)\\\n"
56 : : "{ size_t start, end, size;\\\n"
57 : : " size = L(vec); if (size == 0) return; end = size - 1; start = size >> 1;\\\n"
58 : : " do { __ ## N ## X ## __heap_sift_down(vec, start, end); } while (start--);\\\n"
59 : : " while (end > 0) { \\\n"
60 : : " S(vec, 0, end, TE);\\\n"
61 : : " __ ## N ## X ## __heap_sift_down(vec, 0, --end); } }\n",
62 : 10 : out->nsc);
63 : 10 : fprintf(out->fp,
64 : : "#define __%sdefine_sort_by_field(N, NK, TK, TE, D, S)\\\n"
65 : : " __%sheap_sort(N, _sort_by_ ## NK, N ## _ ## NK, N ## _vec_at, N ## _vec_len, TK, TE, D, S)\\\n"
66 : : "static inline void N ## _vec_sort_by_ ## NK(N ## _mutable_vec_t vec)\\\n"
67 : : "{ __ ## N ## _sort_by_ ## NK ## __heap_sort(vec); }\n",
68 : : out->nsc, out->nsc);
69 : 10 : fprintf(out->fp,
70 : : "#define __%sdefine_sort(N, TK, TE, D, S)\\\n"
71 : : "__%sheap_sort(N, , __%sidentity, N ## _vec_at, N ## _vec_len, TK, TE, D, S)\\\n"
72 : : "static inline void N ## _vec_sort(N ## _mutable_vec_t vec) { __ ## N ## __heap_sort(vec); }\n",
73 : : out->nsc, out->nsc, out->nsc);
74 : 10 : fprintf(out->fp,
75 : : /* Subtractions doesn't work for unsigned types. */
76 : : "#define __%sscalar_diff(x, y) ((x) < (y) ? -1 : (x) > (y))\n"
77 : : "#define __%sstring_diff(x, y) __%sstring_n_cmp((x), (const char *)(y), %sstring_len(y))\n",
78 : : out->nsc, out->nsc, out->nsc, out->nsc);
79 : 10 : fprintf(out->fp,
80 : : "#define __%sscalar_swap(vec, a, b, TE) { TE tmp = vec[b]; vec[b] = vec[a]; vec[a] = tmp; }\n"
81 : : "#define __%sstring_swap(vec, a, b, TE)\\\n"
82 : : "{ TE ta, tb, d;\\\n"
83 : : " d = (TE)((a - b) * sizeof(vec[0]));\\\n"
84 : : " ta = __flatbuffers_uoffset_read_from_pe(vec + b) - d;\\\n"
85 : : " tb = __flatbuffers_uoffset_read_from_pe(vec + a) + d;\\\n"
86 : : " __flatbuffers_uoffset_write_to_pe(vec + a, ta);\\\n"
87 : : " __flatbuffers_uoffset_write_to_pe(vec + b, tb); }\n",
88 : : out->nsc, out->nsc);
89 : 10 : fprintf(out->fp,
90 : : "#define __%sdefine_sort_by_scalar_field(N, NK, TK, TE)\\\n"
91 : : " __%sdefine_sort_by_field(N, NK, TK, TE, __%sscalar_diff, __%sscalar_swap)\n",
92 : : out->nsc, out->nsc, out->nsc, out->nsc);
93 : 10 : fprintf(out->fp,
94 : : "#define __%sdefine_sort_by_string_field(N, NK)\\\n"
95 : : " __%sdefine_sort_by_field(N, NK, %sstring_t, %suoffset_t, __%sstring_diff, __%sstring_swap)\n",
96 : : out->nsc, out->nsc, out->nsc, out->nsc, out->nsc, out->nsc);
97 : 10 : fprintf(out->fp,
98 : : "#define __%sdefine_scalar_sort(N, T) __%sdefine_sort(N, T, T, __%sscalar_diff, __%sscalar_swap)\n",
99 : : out->nsc, out->nsc, out->nsc, out->nsc);
100 : 10 : fprintf(out->fp,
101 : : "#define __%sdefine_string_sort() __%sdefine_sort(%sstring, %sstring_t, %suoffset_t, __%sstring_diff, __%sstring_swap)\n",
102 : : out->nsc, out->nsc, out->nsc, out->nsc, out->nsc, out->nsc, out->nsc);
103 : 10 : return 0;
104 : : }
105 : :
106 : : /* reference implementation */
107 : : #if 0
108 : :
109 : : /* from github swenson/sort */
110 : : /* heap sort: based on wikipedia */
111 : : static __inline void HEAP_SIFT_DOWN(SORT_TYPE *dst, const int64_t start, const int64_t end) {
112 : : int64_t root = start;
113 : :
114 : : while ((root << 1) <= end) {
115 : : int64_t child = root << 1;
116 : :
117 : : if ((child < end) && (SORT_CMP(dst[child], dst[child + 1]) < 0)) {
118 : : child++;
119 : : }
120 : :
121 : : if (SORT_CMP(dst[root], dst[child]) < 0) {
122 : : SORT_SWAP(dst[root], dst[child]);
123 : : root = child;
124 : : } else {
125 : : return;
126 : : }
127 : : }
128 : : }
129 : :
130 : : static __inline void HEAPIFY(SORT_TYPE *dst, const size_t size) {
131 : : int64_t start = size >> 1;
132 : :
133 : : while (start >= 0) {
134 : : HEAP_SIFT_DOWN(dst, start, size - 1);
135 : : start--;
136 : : }
137 : : }
138 : :
139 : : void HEAP_SORT(SORT_TYPE *dst, const size_t size) {
140 : : /* don't bother sorting an array of size 0 */
141 : : if (size == 0) {
142 : : return;
143 : : }
144 : :
145 : : int64_t end = size - 1;
146 : : HEAPIFY(dst, size);
147 : :
148 : : while (end > 0) {
149 : : SORT_SWAP(dst[end], dst[0]);
150 : : HEAP_SIFT_DOWN(dst, 0, end - 1);
151 : : end--;
152 : : }
153 : : }
154 : :
155 : : #endif
|