diff options
Diffstat (limited to 'lvm.c')
-rw-r--r-- | lvm.c | 116 |
1 files changed, 71 insertions, 45 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.342 2018/02/19 20:06:56 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.343 2018/02/21 12:54:26 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -31,17 +31,14 @@ | |||
31 | #include "lvm.h" | 31 | #include "lvm.h" |
32 | 32 | ||
33 | 33 | ||
34 | /* limit for table tag-method chains (to avoid loops) */ | 34 | /* limit for table tag-method chains (to avoid infinite loops) */ |
35 | #define MAXTAGLOOP 2000 | 35 | #define MAXTAGLOOP 2000 |
36 | 36 | ||
37 | 37 | ||
38 | /* | 38 | /* |
39 | ** 'l_intfitsf' checks whether a given integer can be converted to a | 39 | ** 'l_intfitsf' checks whether a given integer can be converted to a |
40 | ** float without rounding. Used in comparisons. Left undefined if | 40 | ** float without rounding. Used in comparisons. |
41 | ** all integers fit in a float precisely. | ||
42 | */ | 41 | */ |
43 | #if !defined(l_intfitsf) | ||
44 | |||
45 | /* number of bits in the mantissa of a float */ | 42 | /* number of bits in the mantissa of a float */ |
46 | #define NBM (l_mathlim(MANT_DIG)) | 43 | #define NBM (l_mathlim(MANT_DIG)) |
47 | 44 | ||
@@ -58,7 +55,9 @@ | |||
58 | #define l_intfitsf(i) \ | 55 | #define l_intfitsf(i) \ |
59 | (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM)) | 56 | (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM)) |
60 | 57 | ||
61 | #endif | 58 | #else /* all integers fit in a float precisely */ |
59 | |||
60 | #define l_intfitsf(i) 1 | ||
62 | 61 | ||
63 | #endif | 62 | #endif |
64 | 63 | ||
@@ -157,7 +156,7 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, | |||
157 | *p = LUA_MAXINTEGER; | 156 | *p = LUA_MAXINTEGER; |
158 | if (step < 0) *stopnow = 1; | 157 | if (step < 0) *stopnow = 1; |
159 | } | 158 | } |
160 | else { /* float is smaller than min integer */ | 159 | else { /* float is less than min integer */ |
161 | *p = LUA_MININTEGER; | 160 | *p = LUA_MININTEGER; |
162 | if (step >= 0) *stopnow = 1; | 161 | if (step >= 0) *stopnow = 1; |
163 | } | 162 | } |
@@ -255,8 +254,8 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, | |||
255 | 254 | ||
256 | 255 | ||
257 | /* | 256 | /* |
258 | ** Compare two strings 'ls' x 'rs', returning an integer smaller-equal- | 257 | ** Compare two strings 'ls' x 'rs', returning an integer less-equal- |
259 | ** -larger than zero if 'ls' is smaller-equal-larger than 'rs'. | 258 | ** -greater than zero if 'ls' is less-equal-greater than 'rs'. |
260 | ** The code is a little tricky because it allows '\0' in the strings | 259 | ** The code is a little tricky because it allows '\0' in the strings |
261 | ** and it uses 'strcoll' (to respect locales) for each segments | 260 | ** and it uses 'strcoll' (to respect locales) for each segments |
262 | ** of the strings. | 261 | ** of the strings. |
@@ -275,7 +274,7 @@ static int l_strcmp (const TString *ls, const TString *rs) { | |||
275 | if (len == lr) /* 'rs' is finished? */ | 274 | if (len == lr) /* 'rs' is finished? */ |
276 | return (len == ll) ? 0 : 1; /* check 'ls' */ | 275 | return (len == ll) ? 0 : 1; /* check 'ls' */ |
277 | else if (len == ll) /* 'ls' is finished? */ | 276 | else if (len == ll) /* 'ls' is finished? */ |
278 | return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ | 277 | return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */ |
279 | /* both strings longer than 'len'; go on comparing after the '\0' */ | 278 | /* both strings longer than 'len'; go on comparing after the '\0' */ |
280 | len++; | 279 | len++; |
281 | l += len; ll -= len; r += len; lr -= len; | 280 | l += len; ll -= len; r += len; lr -= len; |
@@ -287,25 +286,24 @@ static int l_strcmp (const TString *ls, const TString *rs) { | |||
287 | /* | 286 | /* |
288 | ** Check whether integer 'i' is less than float 'f'. If 'i' has an | 287 | ** Check whether integer 'i' is less than float 'f'. If 'i' has an |
289 | ** exact representation as a float ('l_intfitsf'), compare numbers as | 288 | ** exact representation as a float ('l_intfitsf'), compare numbers as |
290 | ** floats. Otherwise, if 'f' is outside the range for integers, result | 289 | ** floats. Otherwise, use the equivalence 'i < f <=> i < ceil(f)'. |
291 | ** is trivial. Otherwise, compare them as integers. (When 'i' has no | 290 | ** If 'ceil(f)' is out of integer range, either 'f' is greater than |
292 | ** float representation, either 'f' is "far away" from 'i' or 'f' has | 291 | ** all integers or less than all integers. |
293 | ** no precision left for a fractional part; either way, how 'f' is | 292 | ** (The test with 'l_intfitsf' is only for performance; the else |
294 | ** truncated is irrelevant.) When 'f' is NaN, comparisons must result | 293 | ** case is correct for all values, but it is slow due to the conversion |
295 | ** in false. | 294 | ** from float to int.) |
295 | ** When 'f' is NaN, comparisons must result in false. | ||
296 | */ | 296 | */ |
297 | static int LTintfloat (lua_Integer i, lua_Number f) { | 297 | static int LTintfloat (lua_Integer i, lua_Number f) { |
298 | #if defined(l_intfitsf) | 298 | if (l_intfitsf(i)) |
299 | if (!l_intfitsf(i)) { | 299 | return luai_numlt(cast_num(i), f); /* compare them as floats */ |
300 | if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ | 300 | else { /* i < f <=> i < ceil(f) */ |
301 | return 1; /* f >= maxint + 1 > i */ | 301 | lua_Integer fi; |
302 | else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */ | 302 | if (luaV_flttointeger(f, &fi, 2)) /* fi = ceil(f) */ |
303 | return (i < cast(lua_Integer, f)); /* compare them as integers */ | 303 | return i < fi; /* compare them as integers */ |
304 | else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */ | 304 | else /* 'f' is either greater or less than all integers */ |
305 | return 0; | 305 | return f > 0; /* greater? */ |
306 | } | 306 | } |
307 | #endif | ||
308 | return luai_numlt(cast_num(i), f); /* compare them as floats */ | ||
309 | } | 307 | } |
310 | 308 | ||
311 | 309 | ||
@@ -314,17 +312,49 @@ static int LTintfloat (lua_Integer i, lua_Number f) { | |||
314 | ** See comments on previous function. | 312 | ** See comments on previous function. |
315 | */ | 313 | */ |
316 | static int LEintfloat (lua_Integer i, lua_Number f) { | 314 | static int LEintfloat (lua_Integer i, lua_Number f) { |
317 | #if defined(l_intfitsf) | 315 | if (l_intfitsf(i)) |
318 | if (!l_intfitsf(i)) { | 316 | return luai_numle(cast_num(i), f); /* compare them as floats */ |
319 | if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ | 317 | else { /* i <= f <=> i <= floor(f) */ |
320 | return 1; /* f >= maxint + 1 > i */ | 318 | lua_Integer fi; |
321 | else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */ | 319 | if (luaV_flttointeger(f, &fi, 1)) /* fi = floor(f) */ |
322 | return (i <= cast(lua_Integer, f)); /* compare them as integers */ | 320 | return i <= fi; /* compare them as integers */ |
323 | else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */ | 321 | else /* 'f' is either greater or less than all integers */ |
324 | return 0; | 322 | return f > 0; /* greater? */ |
323 | } | ||
324 | } | ||
325 | |||
326 | |||
327 | /* | ||
328 | ** Check whether float 'f' is less than integer 'i'. | ||
329 | ** See comments on previous function. | ||
330 | */ | ||
331 | static int LTfloatint (lua_Number f, lua_Integer i) { | ||
332 | if (l_intfitsf(i)) | ||
333 | return luai_numlt(f, cast_num(i)); /* compare them as floats */ | ||
334 | else { /* f < i <=> floor(f) < i */ | ||
335 | lua_Integer fi; | ||
336 | if (luaV_flttointeger(f, &fi, 1)) /* fi = floor(f) */ | ||
337 | return fi < i; /* compare them as integers */ | ||
338 | else /* 'f' is either greater or less than all integers */ | ||
339 | return f < 0; /* less? */ | ||
340 | } | ||
341 | } | ||
342 | |||
343 | |||
344 | /* | ||
345 | ** Check whether float 'f' is less than or equal to integer 'i'. | ||
346 | ** See comments on previous function. | ||
347 | */ | ||
348 | static int LEfloatint (lua_Number f, lua_Integer i) { | ||
349 | if (l_intfitsf(i)) | ||
350 | return luai_numle(f, cast_num(i)); /* compare them as floats */ | ||
351 | else { /* f <= i <=> ceil(f) <= i */ | ||
352 | lua_Integer fi; | ||
353 | if (luaV_flttointeger(f, &fi, 2)) /* fi = ceil(f) */ | ||
354 | return fi <= i; /* compare them as integers */ | ||
355 | else /* 'f' is either greater or less than all integers */ | ||
356 | return f < 0; /* less? */ | ||
325 | } | 357 | } |
326 | #endif | ||
327 | return luai_numle(cast_num(i), f); /* compare them as floats */ | ||
328 | } | 358 | } |
329 | 359 | ||
330 | 360 | ||
@@ -344,10 +374,8 @@ static int LTnum (const TValue *l, const TValue *r) { | |||
344 | lua_Number lf = fltvalue(l); /* 'l' must be float */ | 374 | lua_Number lf = fltvalue(l); /* 'l' must be float */ |
345 | if (ttisfloat(r)) | 375 | if (ttisfloat(r)) |
346 | return luai_numlt(lf, fltvalue(r)); /* both are float */ | 376 | return luai_numlt(lf, fltvalue(r)); /* both are float */ |
347 | else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ | 377 | else /* 'l' is float and 'r' is int */ |
348 | return 0; /* NaN < i is always false */ | 378 | return LTfloatint(lf, ivalue(r)); |
349 | else /* without NaN, (l < r) <--> not(r <= l) */ | ||
350 | return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */ | ||
351 | } | 379 | } |
352 | } | 380 | } |
353 | 381 | ||
@@ -368,10 +396,8 @@ static int LEnum (const TValue *l, const TValue *r) { | |||
368 | lua_Number lf = fltvalue(l); /* 'l' must be float */ | 396 | lua_Number lf = fltvalue(l); /* 'l' must be float */ |
369 | if (ttisfloat(r)) | 397 | if (ttisfloat(r)) |
370 | return luai_numle(lf, fltvalue(r)); /* both are float */ | 398 | return luai_numle(lf, fltvalue(r)); /* both are float */ |
371 | else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ | 399 | else /* 'l' is float and 'r' is int */ |
372 | return 0; /* NaN <= i is always false */ | 400 | return LEfloatint(lf, ivalue(r)); |
373 | else /* without NaN, (l <= r) <--> not(r < l) */ | ||
374 | return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */ | ||
375 | } | 401 | } |
376 | } | 402 | } |
377 | 403 | ||