LCOV - code coverage report
Current view: top level - src/compiler - codegen_c_sort.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 12 12 100.0 %
Date: 2016-11-30 13:12:14 Functions: 1 1 100.0 %
Branches: 0 0 -

           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

Generated by: LCOV version 1.12