aboutsummaryrefslogtreecommitdiff
path: root/ltablib.c
diff options
context:
space:
mode:
Diffstat (limited to 'ltablib.c')
-rw-r--r--ltablib.c111
1 files changed, 73 insertions, 38 deletions
diff --git a/ltablib.c b/ltablib.c
index ef39d5df..a03d0db2 100644
--- a/ltablib.c
+++ b/ltablib.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltablib.c,v 1.86 2015/11/20 12:30:20 roberto Exp roberto $ 2** $Id: ltablib.c,v 1.89 2015/11/24 16:54:32 roberto Exp roberto $
3** Library for Table Manipulation 3** Library for Table Manipulation
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -231,24 +231,68 @@ static int unpack (lua_State *L) {
231** ======================================================= 231** =======================================================
232*/ 232*/
233 233
234
235/*
236** Produce a "random" 'unsigned int' to randomize pivot choice. This
237** macro is used only when 'sort' detects a big imbalance in the result
238** of a partition. (If you don't want/need this "randomness", ~0 is a
239** good choice.)
240*/
241#if !defined(l_randomizePivot) /* { */
242
243#include <time.h>
244
245/* size of 'e' measured in number of 'unsigned int's */
246#define sof(e) (sizeof(e) / sizeof(unsigned int))
247
248/*
249** Use 'time' and 'clock' as sources of "randomness". Because we don't
250** know the types 'clock_t' and 'time_t', we cannot cast them to
251** anything without risking overflows. A safe way to use their values
252** is to copy them to an array of a known type and use the array values.
253*/
254static unsigned int l_randomizePivot (void) {
255 clock_t c = clock();
256 time_t t = time(NULL);
257 unsigned int buff[sof(c) + sof(t)];
258 unsigned int i, rnd = 0;
259 memcpy(buff, &c, sof(c) * sizeof(unsigned int));
260 memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));
261 for (i = 0; i < sof(buff); i++)
262 rnd += buff[i];
263 return rnd;
264}
265
266#endif /* } */
267
268
269/* arrays larger than 'RANLIMIT' may use randomized pivots */
270#define RANLIMIT 100u
271
272
234static void set2 (lua_State *L, unsigned int i, unsigned int j) { 273static void set2 (lua_State *L, unsigned int i, unsigned int j) {
235 lua_seti(L, 1, i); 274 lua_seti(L, 1, i);
236 lua_seti(L, 1, j); 275 lua_seti(L, 1, j);
237} 276}
238 277
278
279/*
280** Return true iff value at stack index 'a' is less than the value at
281** index 'b' (according to the order of the sort).
282*/
239static int sort_comp (lua_State *L, int a, int b) { 283static int sort_comp (lua_State *L, int a, int b) {
240 if (!lua_isnil(L, 2)) { /* function? */ 284 if (lua_isnil(L, 2)) /* no function? */
285 return lua_compare(L, a, b, LUA_OPLT); /* a < b */
286 else { /* function */
241 int res; 287 int res;
242 lua_pushvalue(L, 2); 288 lua_pushvalue(L, 2); /* push function */
243 lua_pushvalue(L, a-1); /* -1 to compensate function */ 289 lua_pushvalue(L, a-1); /* -1 to compensate function */
244 lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ 290 lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */
245 lua_call(L, 2, 1); 291 lua_call(L, 2, 1); /* call function */
246 res = lua_toboolean(L, -1); 292 res = lua_toboolean(L, -1); /* get result */
247 lua_pop(L, 1); 293 lua_pop(L, 1); /* pop result */
248 return res; 294 return res;
249 } 295 }
250 else /* a < b? */
251 return lua_compare(L, a, b, LUA_OPLT);
252} 296}
253 297
254 298
@@ -293,39 +337,26 @@ static unsigned int partition (lua_State *L, unsigned int lo,
293 337
294 338
295/* 339/*
296** Choose a "random" pivot in the middle part of the interval [lo, up]. 340** Choose an element in the middle (2nd-3th quarters) of [lo,up]
297** (If you don't want/need this "randomness", (lo+up)/2 is an excellent 341** "randomized" by 'rnd'
298** choice.)
299*/ 342*/
300#if !defined(l_sortpivot) 343static unsigned int choosePivot (unsigned int lo, unsigned int up,
301/* Use 'time' and 'clock' as sources of "randomness" */ 344 unsigned int rnd) {
302#include <time.h>
303
304#define szi (sizeof(unsigned int))
305#define sof(e) (sizeof(e)/szi)
306
307static unsigned int choosePivot (unsigned int lo, unsigned int up) {
308 clock_t c = clock();
309 time_t t = time(NULL);
310 unsigned int buff[sof(c) + sof(t)];
311 unsigned int r4 = (unsigned int)(up - lo) / 4u; /* range/4 */ 345 unsigned int r4 = (unsigned int)(up - lo) / 4u; /* range/4 */
312 unsigned int p, i, h = 0; 346 unsigned int p = rnd % (r4 * 2) + (lo + r4);
313 memcpy(buff, &c, sof(c) * szi);
314 memcpy(buff + sof(c), &t, sof(t) * szi);
315 for (i = 0; i < sof(buff); i++)
316 h += buff[i];
317 p = h % (r4 * 2) + (lo + r4);
318 lua_assert(lo + r4 <= p && p <= up - r4); 347 lua_assert(lo + r4 <= p && p <= up - r4);
319 return p; 348 return p;
320} 349}
321 350
322#define l_sortpivot(lo,up) choosePivot(lo,up)
323#endif
324
325 351
326static void auxsort (lua_State *L, unsigned int lo, unsigned int up) { 352/*
353** QuickSort algorithm (recursive function)
354*/
355static void auxsort (lua_State *L, unsigned int lo, unsigned int up,
356 unsigned int rnd) {
327 while (lo < up) { /* loop for tail recursion */ 357 while (lo < up) { /* loop for tail recursion */
328 unsigned int p; /* Pivot index */ 358 unsigned int p; /* Pivot index */
359 unsigned int n; /* to be used later */
329 /* sort elements 'lo', 'p', and 'up' */ 360 /* sort elements 'lo', 'p', and 'up' */
330 lua_geti(L, 1, lo); 361 lua_geti(L, 1, lo);
331 lua_geti(L, 1, up); 362 lua_geti(L, 1, up);
@@ -335,10 +366,10 @@ static void auxsort (lua_State *L, unsigned int lo, unsigned int up) {
335 lua_pop(L, 2); /* remove both values */ 366 lua_pop(L, 2); /* remove both values */
336 if (up - lo == 1) /* only 2 elements? */ 367 if (up - lo == 1) /* only 2 elements? */
337 return; /* already sorted */ 368 return; /* already sorted */
338 if (up - lo < 100u) /* small interval? */ 369 if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */
339 p = (lo + up)/2; /* middle element is a good pivot */ 370 p = (lo + up)/2; /* middle element is a good pivot */
340 else /* for larger intervals, it is worth a random pivot */ 371 else /* for larger intervals, it is worth a random pivot */
341 p = l_sortpivot(lo, up); 372 p = choosePivot(lo, up, rnd);
342 lua_geti(L, 1, p); 373 lua_geti(L, 1, p);
343 lua_geti(L, 1, lo); 374 lua_geti(L, 1, lo);
344 if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ 375 if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
@@ -360,14 +391,18 @@ static void auxsort (lua_State *L, unsigned int lo, unsigned int up) {
360 p = partition(L, lo, up); 391 p = partition(L, lo, up);
361 /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ 392 /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
362 if (p - lo < up - p) { /* lower interval is smaller? */ 393 if (p - lo < up - p) { /* lower interval is smaller? */
363 auxsort(L, lo, p - 1); /* call recursively for lower interval */ 394 auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */
395 n = p - lo; /* size of smaller interval */
364 lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ 396 lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */
365 } 397 }
366 else { 398 else {
367 auxsort(L, p + 1, up); /* call recursively for upper interval */ 399 auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */
400 n = up - p; /* size of smaller interval */
368 up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ 401 up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
369 } 402 }
370 } /* tail call auxsort(L, lo, up) */ 403 if ((up - lo) / 128u > n) /* partition too imbalanced? */
404 rnd = l_randomizePivot(); /* try a new randomization */
405 } /* tail call auxsort(L, lo, up, rnd) */
371} 406}
372 407
373 408
@@ -379,7 +414,7 @@ static int sort (lua_State *L) {
379 if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ 414 if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
380 luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ 415 luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
381 lua_settop(L, 2); /* make sure there are two arguments */ 416 lua_settop(L, 2); /* make sure there are two arguments */
382 auxsort(L, 1, (unsigned int)n); 417 auxsort(L, 1, (unsigned int)n, 0u);
383 } 418 }
384 return 0; 419 return 0;
385} 420}