talgo.c 7.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
15

S
talgo  
Shengliang Guan 已提交
16
#define _DEFAULT_SOURCE
17
#include "talgo.h"
S
Shengliang Guan 已提交
18
#include "tlog.h"
19

S
talgo  
Shengliang Guan 已提交
20 21 22 23 24 25
#define doswap(__left, __right, __size, __buf) \
  do {                                         \
    memcpy((__buf), (__left), (__size));       \
    memcpy((__left), (__right), (__size));     \
    memcpy((__right), (__buf), (__size));      \
  } while (0);
26

S
talgo  
Shengliang Guan 已提交
27 28
static void median(void *src, int64_t size, int64_t s, int64_t e, const void *param, __ext_compar_fn_t comparFn,
                   void *buf) {
S
Shengliang Guan 已提交
29
  int32_t mid = ((int32_t)(e - s) >> 1u) + (int32_t)s;
S
talgo  
Shengliang Guan 已提交
30

31 32 33
  if (comparFn(elePtrAt(src, size, mid), elePtrAt(src, size, s), param) == 1) {
    doswap(elePtrAt(src, size, mid), elePtrAt(src, size, s), size, buf);
  }
S
talgo  
Shengliang Guan 已提交
34

35 36 37 38 39 40
  if (comparFn(elePtrAt(src, size, mid), elePtrAt(src, size, e), param) == 1) {
    doswap(elePtrAt(src, size, mid), elePtrAt(src, size, s), size, buf);
    doswap(elePtrAt(src, size, mid), elePtrAt(src, size, e), size, buf);
  } else if (comparFn(elePtrAt(src, size, s), elePtrAt(src, size, e), param) == 1) {
    doswap(elePtrAt(src, size, s), elePtrAt(src, size, e), size, buf);
  }
S
talgo  
Shengliang Guan 已提交
41

A
Alex Duan 已提交
42
  ASSERT(comparFn(elePtrAt(src, size, mid), elePtrAt(src, size, s), param) <= 0 &&
S
talgo  
Shengliang Guan 已提交
43
         comparFn(elePtrAt(src, size, s), elePtrAt(src, size, e), param) <= 0);
44 45
}

S
talgo  
Shengliang Guan 已提交
46 47
static void tInsertSort(void *src, int64_t size, int32_t s, int32_t e, const void *param, __ext_compar_fn_t comparFn,
                        void *buf) {
48 49 50 51 52 53 54 55 56 57 58
  for (int32_t i = s + 1; i <= e; ++i) {
    for (int32_t j = i; j > s; --j) {
      if (comparFn(elePtrAt(src, size, j), elePtrAt(src, size, j - 1), param) == -1) {
        doswap(elePtrAt(src, size, j), elePtrAt(src, size, j - 1), size, buf);
      } else {
        break;
      }
    }
  }
}

S
talgo  
Shengliang Guan 已提交
59 60
static void tqsortImpl(void *src, int32_t start, int32_t end, int64_t size, const void *param,
                       __ext_compar_fn_t comparFn, void *buf) {
61 62 63 64 65 66
  // short array sort, incur another sort procedure instead of quick sort process
  const int32_t THRESHOLD_SIZE = 6;
  if (end - start + 1 <= THRESHOLD_SIZE) {
    tInsertSort(src, size, start, end, param, comparFn, buf);
    return;
  }
S
talgo  
Shengliang Guan 已提交
67

68
  median(src, size, start, end, param, comparFn, buf);
S
talgo  
Shengliang Guan 已提交
69

70 71
  int32_t s = start, e = end;
  int32_t endRightS = end, startLeftS = start;
S
talgo  
Shengliang Guan 已提交
72

73 74 75 76 77 78
  while (s < e) {
    while (e > s) {
      int32_t ret = comparFn(elePtrAt(src, size, e), elePtrAt(src, size, s), param);
      if (ret < 0) {
        break;
      }
S
talgo  
Shengliang Guan 已提交
79 80

      // move the data that equals to pivotal value to the right end of the list
81 82 83 84
      if (ret == 0 && e != endRightS) {
        doswap(elePtrAt(src, size, e), elePtrAt(src, size, endRightS), size, buf);
        endRightS--;
      }
S
talgo  
Shengliang Guan 已提交
85

86 87
      e--;
    }
S
talgo  
Shengliang Guan 已提交
88

89 90 91
    if (e != s) {
      doswap(elePtrAt(src, size, e), elePtrAt(src, size, s), size, buf);
    }
S
talgo  
Shengliang Guan 已提交
92

93 94 95 96 97
    while (s < e) {
      int32_t ret = comparFn(elePtrAt(src, size, s), elePtrAt(src, size, e), param);
      if (ret > 0) {
        break;
      }
S
talgo  
Shengliang Guan 已提交
98

99 100 101 102 103 104
      if (ret == 0 && s != startLeftS) {
        doswap(elePtrAt(src, size, s), elePtrAt(src, size, startLeftS), size, buf);
        startLeftS++;
      }
      s++;
    }
S
talgo  
Shengliang Guan 已提交
105

106 107 108 109
    if (e != s) {
      doswap(elePtrAt(src, size, s), elePtrAt(src, size, e), size, buf);
    }
  }
S
talgo  
Shengliang Guan 已提交
110

111 112 113 114
  int32_t rightPartStart = e + 1;
  if (endRightS != end && e < end) {
    int32_t left = rightPartStart;
    int32_t right = end;
S
talgo  
Shengliang Guan 已提交
115

116 117
    while (right > endRightS && left <= endRightS) {
      doswap(elePtrAt(src, size, left), elePtrAt(src, size, right), size, buf);
S
talgo  
Shengliang Guan 已提交
118

119 120 121
      left++;
      right--;
    }
S
talgo  
Shengliang Guan 已提交
122

123 124
    rightPartStart += (end - endRightS);
  }
S
talgo  
Shengliang Guan 已提交
125

126 127 128 129
  int32_t leftPartEnd = e - 1;
  if (startLeftS != end && s > start) {
    int32_t left = start;
    int32_t right = leftPartEnd;
S
talgo  
Shengliang Guan 已提交
130

131 132
    while (left < startLeftS && right >= startLeftS) {
      doswap(elePtrAt(src, size, left), elePtrAt(src, size, right), size, buf);
S
talgo  
Shengliang Guan 已提交
133

134 135 136
      left++;
      right--;
    }
S
talgo  
Shengliang Guan 已提交
137

138 139
    leftPartEnd -= (startLeftS - start);
  }
S
talgo  
Shengliang Guan 已提交
140

141
  if (leftPartEnd > start) {
H
hjxilinx 已提交
142
    tqsortImpl(src, start, leftPartEnd, size, param, comparFn, buf);
143
  }
S
talgo  
Shengliang Guan 已提交
144

145
  if (rightPartStart < end) {
H
hjxilinx 已提交
146
    tqsortImpl(src, rightPartStart, end, size, param, comparFn, buf);
147 148 149
  }
}

S
talgo  
Shengliang Guan 已提交
150
void taosqsort(void *src, int64_t numOfElem, int64_t size, const void *param, __ext_compar_fn_t comparFn) {
wafwerar's avatar
wafwerar 已提交
151
  char *buf = taosMemoryCalloc(1, size);  // prepare the swap buffer
S
Shengliang Guan 已提交
152
  tqsortImpl(src, 0, (int32_t)numOfElem - 1, (int32_t)size, param, comparFn, buf);
wafwerar's avatar
wafwerar 已提交
153
  taosMemoryFreeClear(buf);
154 155
}

H
more  
Hongze Cheng 已提交
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
void *taosbsearch(const void *key, const void *base, int32_t nmemb, int32_t size, __compar_fn_t compar, int32_t flags) {
  uint8_t *p;
  int32_t  lidx;
  int32_t  ridx;
  int32_t  midx;
  int32_t  c;

  if (nmemb <= 0) return NULL;

  lidx = 0;
  ridx = nmemb - 1;
  while (lidx <= ridx) {
    midx = (lidx + ridx) / 2;
    p = (uint8_t *)base + size * midx;

    c = compar(key, p);
    if (c == 0) {
H
Hongze Cheng 已提交
173
      if (flags == TD_GT) {
174
        lidx = midx + 1;
H
Hongze Cheng 已提交
175
      } else if (flags == TD_LT) {
176
        ridx = midx - 1;
H
Hongze Cheng 已提交
177
      } else {
178 179
        break;
      }
H
more  
Hongze Cheng 已提交
180 181 182 183 184 185
    } else if (c < 0) {
      ridx = midx - 1;
    } else {
      lidx = midx + 1;
    }
  }
S
talgo  
Shengliang Guan 已提交
186

187
  if (flags == TD_EQ) {
H
refact  
Hongze Cheng 已提交
188
    return c ? NULL : p;
H
more  
Hongze Cheng 已提交
189
  } else if (flags == TD_GE) {
H
refact  
Hongze Cheng 已提交
190
    return (c <= 0) ? p : (midx + 1 < nmemb ? p + size : NULL);
191
  } else if (flags == TD_LE) {
H
refact  
Hongze Cheng 已提交
192
    return (c >= 0) ? p : (midx > 0 ? p - size : NULL);
193 194 195 196
  } else if (flags == TD_GT) {
    return (c < 0) ? p : (midx + 1 < nmemb ? p + size : NULL);
  } else if (flags == TD_LT) {
    return (c > 0) ? p : (midx > 0 ? p - size : NULL);
197
  } else {
198
    ASSERT(0);
199
    return NULL;
200 201
  }
}
202

S
talgo  
Shengliang Guan 已提交
203
void taosheapadjust(void *base, int32_t size, int32_t start, int32_t end, const void *parcompar,
H
more  
Hongze Cheng 已提交
204
                    __ext_compar_fn_t compar, char *buf, bool maxroot) {
S
talgo  
Shengliang Guan 已提交
205 206
  int32_t parent;
  int32_t child;
207

H
more  
Hongze Cheng 已提交
208
  char *tmp = NULL;
209 210 211 212 213
  if (buf == NULL) {
    tmp = taosMemoryMalloc(size);
  } else {
    tmp = buf;
  }
214 215 216 217 218 219 220

  if (base && size > 0 && compar) {
    parent = start;
    child = 2 * parent + 1;

    if (maxroot) {
      while (child <= end) {
S
talgo  
Shengliang Guan 已提交
221 222
        if (child + 1 <= end &&
            (*compar)(elePtrAt(base, size, child), elePtrAt(base, size, child + 1), parcompar) < 0) {
223 224 225 226 227 228 229
          child++;
        }

        if ((*compar)(elePtrAt(base, size, parent), elePtrAt(base, size, child), parcompar) > 0) {
          break;
        }

230
        doswap(elePtrAt(base, size, parent), elePtrAt(base, size, child), size, tmp);
231 232 233 234 235 236

        parent = child;
        child = 2 * parent + 1;
      }
    } else {
      while (child <= end) {
S
talgo  
Shengliang Guan 已提交
237 238
        if (child + 1 <= end &&
            (*compar)(elePtrAt(base, size, child), elePtrAt(base, size, child + 1), parcompar) > 0) {
239 240 241 242 243 244 245
          child++;
        }

        if ((*compar)(elePtrAt(base, size, parent), elePtrAt(base, size, child), parcompar) < 0) {
          break;
        }

246
        doswap(elePtrAt(base, size, parent), elePtrAt(base, size, child), size, tmp);
247 248 249 250 251

        parent = child;
        child = 2 * parent + 1;
      }
    }
252
  }
253

254 255
  if (buf == NULL) {
    taosMemoryFree(tmp);
256 257 258
  }
}

S
talgo  
Shengliang Guan 已提交
259
void taosheapsort(void *base, int32_t size, int32_t len, const void *parcompar, __ext_compar_fn_t compar,
260
                  bool maxroot) {
S
talgo  
Shengliang Guan 已提交
261
  int32_t i;
262

H
more  
Hongze Cheng 已提交
263
  char *buf = taosMemoryCalloc(1, size);
264 265 266 267
  if (buf == NULL) {
    return;
  }

268 269
  if (base && size > 0) {
    for (i = len / 2 - 1; i >= 0; i--) {
270
      taosheapadjust(base, size, i, len - 1, parcompar, compar, buf, maxroot);
271 272 273
    }
  }

274
  taosMemoryFree(buf);
275
}