diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-12 16:13:50 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-12 16:13:50 -0300 |
| commit | 1fb4d539254b67e7e35ed698250c66d1edff0e08 (patch) | |
| tree | 8f48b7ca736a7fb02834bcfac1415cd43307f529 | |
| parent | f6aab3ec1f111cd8d968bdcb7ca800e93b819d24 (diff) | |
| download | lua-1fb4d539254b67e7e35ed698250c66d1edff0e08.tar.gz lua-1fb4d539254b67e7e35ed698250c66d1edff0e08.tar.bz2 lua-1fb4d539254b67e7e35ed698250c66d1edff0e08.zip | |
OP_NEWTABLE keeps exact size of arrays
OP_NEWTABLE is followed by an OP_EXTRAARG, so that it can keep
the exact size of the array part of the table to be created.
(Functions 'luaO_int2fb'/'luaO_fb2int' were removed.)
| -rw-r--r-- | lcode.c | 6 | ||||
| -rw-r--r-- | lcode.h | 1 | ||||
| -rw-r--r-- | lobject.c | 26 | ||||
| -rw-r--r-- | lobject.h | 2 | ||||
| -rw-r--r-- | lopcodes.h | 10 | ||||
| -rw-r--r-- | lparser.c | 37 | ||||
| -rw-r--r-- | ltests.c | 9 | ||||
| -rw-r--r-- | lvm.c | 6 | ||||
| -rw-r--r-- | testes/code.lua | 6 | ||||
| -rw-r--r-- | testes/nextvar.lua | 52 |
10 files changed, 67 insertions, 88 deletions
| @@ -430,7 +430,7 @@ static int codesJ (FuncState *fs, OpCode o, int sj, int k) { | |||
| 430 | /* | 430 | /* |
| 431 | ** Emit an "extra argument" instruction (format 'iAx') | 431 | ** Emit an "extra argument" instruction (format 'iAx') |
| 432 | */ | 432 | */ |
| 433 | static int codeextraarg (FuncState *fs, int a) { | 433 | int luaK_codeextraarg (FuncState *fs, int a) { |
| 434 | lua_assert(a <= MAXARG_Ax); | 434 | lua_assert(a <= MAXARG_Ax); |
| 435 | return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); | 435 | return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); |
| 436 | } | 436 | } |
| @@ -446,7 +446,7 @@ static int luaK_codek (FuncState *fs, int reg, int k) { | |||
| 446 | return luaK_codeABx(fs, OP_LOADK, reg, k); | 446 | return luaK_codeABx(fs, OP_LOADK, reg, k); |
| 447 | else { | 447 | else { |
| 448 | int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); | 448 | int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); |
| 449 | codeextraarg(fs, k); | 449 | luaK_codeextraarg(fs, k); |
| 450 | return p; | 450 | return p; |
| 451 | } | 451 | } |
| 452 | } | 452 | } |
| @@ -1687,7 +1687,7 @@ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { | |||
| 1687 | luaK_codeABC(fs, OP_SETLIST, base, b, c); | 1687 | luaK_codeABC(fs, OP_SETLIST, base, b, c); |
| 1688 | else if (c <= MAXARG_Ax) { | 1688 | else if (c <= MAXARG_Ax) { |
| 1689 | luaK_codeABC(fs, OP_SETLIST, base, b, 0); | 1689 | luaK_codeABC(fs, OP_SETLIST, base, b, 0); |
| 1690 | codeextraarg(fs, c); | 1690 | luaK_codeextraarg(fs, c); |
| 1691 | } | 1691 | } |
| 1692 | else | 1692 | else |
| 1693 | luaX_syntaxerror(fs->ls, "constructor too long"); | 1693 | luaX_syntaxerror(fs->ls, "constructor too long"); |
| @@ -55,6 +55,7 @@ LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); | |||
| 55 | LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); | 55 | LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); |
| 56 | LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, | 56 | LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, |
| 57 | int B, int C, int k); | 57 | int B, int C, int k); |
| 58 | LUAI_FUNC int luaK_codeextraarg (FuncState *fs, int a); | ||
| 58 | LUAI_FUNC int luaK_isKint (expdesc *e); | 59 | LUAI_FUNC int luaK_isKint (expdesc *e); |
| 59 | LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); | 60 | LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); |
| 60 | LUAI_FUNC void luaK_fixline (FuncState *fs, int line); | 61 | LUAI_FUNC void luaK_fixline (FuncState *fs, int line); |
| @@ -30,32 +30,6 @@ | |||
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | /* | 32 | /* |
| 33 | ** converts an integer to a "floating point byte", represented as | ||
| 34 | ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if | ||
| 35 | ** eeeee != 0 and (xxx) otherwise. | ||
| 36 | */ | ||
| 37 | int luaO_int2fb (unsigned int x) { | ||
| 38 | int e = 0; /* exponent */ | ||
| 39 | if (x < 8) return x; | ||
| 40 | while (x >= (8 << 4)) { /* coarse steps */ | ||
| 41 | x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ | ||
| 42 | e += 4; | ||
| 43 | } | ||
| 44 | while (x >= (8 << 1)) { /* fine steps */ | ||
| 45 | x = (x + 1) >> 1; /* x = ceil(x / 2) */ | ||
| 46 | e++; | ||
| 47 | } | ||
| 48 | return ((e+1) << 3) | (cast_int(x) - 8); | ||
| 49 | } | ||
| 50 | |||
| 51 | |||
| 52 | /* converts back */ | ||
| 53 | int luaO_fb2int (int x) { | ||
| 54 | return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1); | ||
| 55 | } | ||
| 56 | |||
| 57 | |||
| 58 | /* | ||
| 59 | ** Computes ceil(log2(x)) | 33 | ** Computes ceil(log2(x)) |
| 60 | */ | 34 | */ |
| 61 | int luaO_ceillog2 (unsigned int x) { | 35 | int luaO_ceillog2 (unsigned int x) { |
| @@ -734,8 +734,6 @@ typedef struct Table { | |||
| 734 | /* size of buffer for 'luaO_utf8esc' function */ | 734 | /* size of buffer for 'luaO_utf8esc' function */ |
| 735 | #define UTF8BUFFSZ 8 | 735 | #define UTF8BUFFSZ 8 |
| 736 | 736 | ||
| 737 | LUAI_FUNC int luaO_int2fb (unsigned int x); | ||
| 738 | LUAI_FUNC int luaO_fb2int (int x); | ||
| 739 | LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); | 737 | LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); |
| 740 | LUAI_FUNC int luaO_ceillog2 (unsigned int x); | 738 | LUAI_FUNC int luaO_ceillog2 (unsigned int x); |
| 741 | LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1, | 739 | LUAI_FUNC int luaO_rawarith (lua_State *L, int op, const TValue *p1, |
| @@ -324,7 +324,8 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ | |||
| 324 | (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then | 324 | (*) In OP_SETLIST, if (B == 0) then real B = 'top'; if (C == 0) then |
| 325 | next 'instruction' is EXTRAARG(real C). | 325 | next 'instruction' is EXTRAARG(real C). |
| 326 | 326 | ||
| 327 | (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG. | 327 | (*) In OP_LOADKX and OP_NEWTABLE, the next 'instruction' is always |
| 328 | EXTRAARG. | ||
| 328 | 329 | ||
| 329 | (*) For comparisons, k specifies what condition the test should accept | 330 | (*) For comparisons, k specifies what condition the test should accept |
| 330 | (true or false). | 331 | (true or false). |
| @@ -375,4 +376,11 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];) | |||
| 375 | #define LFIELDS_PER_FLUSH 50 | 376 | #define LFIELDS_PER_FLUSH 50 |
| 376 | 377 | ||
| 377 | 378 | ||
| 379 | /* | ||
| 380 | ** In OP_NEWTABLE, array sizes smaller than LIMTABSZ are represented | ||
| 381 | ** directly in R(B). Otherwise, array size is given by | ||
| 382 | ** (R(B) - LIMTABSZ) + EXTRAARG * LFIELDS_PER_FLUSH | ||
| 383 | */ | ||
| 384 | #define LIMTABSZ (MAXARG_B - LFIELDS_PER_FLUSH) | ||
| 385 | |||
| 378 | #endif | 386 | #endif |
| @@ -811,16 +811,16 @@ static void yindex (LexState *ls, expdesc *v) { | |||
| 811 | */ | 811 | */ |
| 812 | 812 | ||
| 813 | 813 | ||
| 814 | struct ConsControl { | 814 | typedef struct ConsControl { |
| 815 | expdesc v; /* last list item read */ | 815 | expdesc v; /* last list item read */ |
| 816 | expdesc *t; /* table descriptor */ | 816 | expdesc *t; /* table descriptor */ |
| 817 | int nh; /* total number of 'record' elements */ | 817 | int nh; /* total number of 'record' elements */ |
| 818 | int na; /* total number of array elements */ | 818 | int na; /* total number of array elements */ |
| 819 | int tostore; /* number of array elements pending to be stored */ | 819 | int tostore; /* number of array elements pending to be stored */ |
| 820 | }; | 820 | } ConsControl; |
| 821 | 821 | ||
| 822 | 822 | ||
| 823 | static void recfield (LexState *ls, struct ConsControl *cc) { | 823 | static void recfield (LexState *ls, ConsControl *cc) { |
| 824 | /* recfield -> (NAME | '['exp']') = exp */ | 824 | /* recfield -> (NAME | '['exp']') = exp */ |
| 825 | FuncState *fs = ls->fs; | 825 | FuncState *fs = ls->fs; |
| 826 | int reg = ls->fs->freereg; | 826 | int reg = ls->fs->freereg; |
| @@ -841,7 +841,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) { | |||
| 841 | } | 841 | } |
| 842 | 842 | ||
| 843 | 843 | ||
| 844 | static void closelistfield (FuncState *fs, struct ConsControl *cc) { | 844 | static void closelistfield (FuncState *fs, ConsControl *cc) { |
| 845 | if (cc->v.k == VVOID) return; /* there is no list item */ | 845 | if (cc->v.k == VVOID) return; /* there is no list item */ |
| 846 | luaK_exp2nextreg(fs, &cc->v); | 846 | luaK_exp2nextreg(fs, &cc->v); |
| 847 | cc->v.k = VVOID; | 847 | cc->v.k = VVOID; |
| @@ -852,7 +852,7 @@ static void closelistfield (FuncState *fs, struct ConsControl *cc) { | |||
| 852 | } | 852 | } |
| 853 | 853 | ||
| 854 | 854 | ||
| 855 | static void lastlistfield (FuncState *fs, struct ConsControl *cc) { | 855 | static void lastlistfield (FuncState *fs, ConsControl *cc) { |
| 856 | if (cc->tostore == 0) return; | 856 | if (cc->tostore == 0) return; |
| 857 | if (hasmultret(cc->v.k)) { | 857 | if (hasmultret(cc->v.k)) { |
| 858 | luaK_setmultret(fs, &cc->v); | 858 | luaK_setmultret(fs, &cc->v); |
| @@ -867,16 +867,15 @@ static void lastlistfield (FuncState *fs, struct ConsControl *cc) { | |||
| 867 | } | 867 | } |
| 868 | 868 | ||
| 869 | 869 | ||
| 870 | static void listfield (LexState *ls, struct ConsControl *cc) { | 870 | static void listfield (LexState *ls, ConsControl *cc) { |
| 871 | /* listfield -> exp */ | 871 | /* listfield -> exp */ |
| 872 | expr(ls, &cc->v); | 872 | expr(ls, &cc->v); |
| 873 | checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); | ||
| 874 | cc->na++; | 873 | cc->na++; |
| 875 | cc->tostore++; | 874 | cc->tostore++; |
| 876 | } | 875 | } |
| 877 | 876 | ||
| 878 | 877 | ||
| 879 | static void field (LexState *ls, struct ConsControl *cc) { | 878 | static void field (LexState *ls, ConsControl *cc) { |
| 880 | /* field -> listfield | recfield */ | 879 | /* field -> listfield | recfield */ |
| 881 | switch(ls->t.token) { | 880 | switch(ls->t.token) { |
| 882 | case TK_NAME: { /* may be 'listfield' or 'recfield' */ | 881 | case TK_NAME: { /* may be 'listfield' or 'recfield' */ |
| @@ -898,13 +897,30 @@ static void field (LexState *ls, struct ConsControl *cc) { | |||
| 898 | } | 897 | } |
| 899 | 898 | ||
| 900 | 899 | ||
| 900 | static void settablesize (FuncState *fs, ConsControl *cc, int pc) { | ||
| 901 | Instruction *inst = &fs->f->code[pc]; | ||
| 902 | int rc = (cc->nh == 0) ? 0 : luaO_ceillog2(cc->nh) + 1; | ||
| 903 | int rb = cc->na; | ||
| 904 | int extra = 0; | ||
| 905 | if (rb >= LIMTABSZ) { | ||
| 906 | extra = rb / LFIELDS_PER_FLUSH; | ||
| 907 | rb = rb % LFIELDS_PER_FLUSH + LIMTABSZ; | ||
| 908 | checklimit(fs, extra, MAXARG_Ax, "items in a constructor"); | ||
| 909 | } | ||
| 910 | SETARG_C(*inst, rc); /* set initial table size */ | ||
| 911 | SETARG_B(*inst, rb); /* set initial array size */ | ||
| 912 | SETARG_Ax(*(inst + 1), extra); | ||
| 913 | } | ||
| 914 | |||
| 915 | |||
| 901 | static void constructor (LexState *ls, expdesc *t) { | 916 | static void constructor (LexState *ls, expdesc *t) { |
| 902 | /* constructor -> '{' [ field { sep field } [sep] ] '}' | 917 | /* constructor -> '{' [ field { sep field } [sep] ] '}' |
| 903 | sep -> ',' | ';' */ | 918 | sep -> ',' | ';' */ |
| 904 | FuncState *fs = ls->fs; | 919 | FuncState *fs = ls->fs; |
| 905 | int line = ls->linenumber; | 920 | int line = ls->linenumber; |
| 906 | int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); | 921 | int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); |
| 907 | struct ConsControl cc; | 922 | ConsControl cc; |
| 923 | luaK_codeextraarg(fs, 0); | ||
| 908 | cc.na = cc.nh = cc.tostore = 0; | 924 | cc.na = cc.nh = cc.tostore = 0; |
| 909 | cc.t = t; | 925 | cc.t = t; |
| 910 | init_exp(t, VRELOC, pc); | 926 | init_exp(t, VRELOC, pc); |
| @@ -919,8 +935,7 @@ static void constructor (LexState *ls, expdesc *t) { | |||
| 919 | } while (testnext(ls, ',') || testnext(ls, ';')); | 935 | } while (testnext(ls, ',') || testnext(ls, ';')); |
| 920 | check_match(ls, '}', '{', line); | 936 | check_match(ls, '}', '{', line); |
| 921 | lastlistfield(fs, &cc); | 937 | lastlistfield(fs, &cc); |
| 922 | SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ | 938 | settablesize(fs, &cc, pc); |
| 923 | SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ | ||
| 924 | } | 939 | } |
| 925 | 940 | ||
| 926 | /* }====================================================================== */ | 941 | /* }====================================================================== */ |
| @@ -1103,14 +1103,6 @@ static int doremote (lua_State *L) { | |||
| 1103 | } | 1103 | } |
| 1104 | 1104 | ||
| 1105 | 1105 | ||
| 1106 | static int int2fb_aux (lua_State *L) { | ||
| 1107 | int b = luaO_int2fb((unsigned int)luaL_checkinteger(L, 1)); | ||
| 1108 | lua_pushinteger(L, b); | ||
| 1109 | lua_pushinteger(L, (unsigned int)luaO_fb2int(b)); | ||
| 1110 | return 2; | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | |||
| 1114 | static int log2_aux (lua_State *L) { | 1106 | static int log2_aux (lua_State *L) { |
| 1115 | unsigned int x = (unsigned int)luaL_checkinteger(L, 1); | 1107 | unsigned int x = (unsigned int)luaL_checkinteger(L, 1); |
| 1116 | lua_pushinteger(L, luaO_ceillog2(x)); | 1108 | lua_pushinteger(L, luaO_ceillog2(x)); |
| @@ -1780,7 +1772,6 @@ static const struct luaL_Reg tests_funcs[] = { | |||
| 1780 | {"pobj", gc_printobj}, | 1772 | {"pobj", gc_printobj}, |
| 1781 | {"getref", getref}, | 1773 | {"getref", getref}, |
| 1782 | {"hash", hash_query}, | 1774 | {"hash", hash_query}, |
| 1783 | {"int2fb", int2fb_aux}, | ||
| 1784 | {"log2", log2_aux}, | 1775 | {"log2", log2_aux}, |
| 1785 | {"limits", get_limits}, | 1776 | {"limits", get_limits}, |
| 1786 | {"listcode", listcode}, | 1777 | {"listcode", listcode}, |
| @@ -1250,11 +1250,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1250 | int b = GETARG_B(i); | 1250 | int b = GETARG_B(i); |
| 1251 | int c = GETARG_C(i); | 1251 | int c = GETARG_C(i); |
| 1252 | Table *t; | 1252 | Table *t; |
| 1253 | c = (c == 0) ? 0 : 1 << (c - 1); /* size is 2^c */ | ||
| 1254 | if (b >= LIMTABSZ) | ||
| 1255 | b += LFIELDS_PER_FLUSH * GETARG_Ax(*pc) - LIMTABSZ; | ||
| 1256 | pc++; /* skip extra argument */ | ||
| 1253 | L->top = ci->top; /* correct top in case of GC */ | 1257 | L->top = ci->top; /* correct top in case of GC */ |
| 1254 | t = luaH_new(L); /* memory allocation */ | 1258 | t = luaH_new(L); /* memory allocation */ |
| 1255 | sethvalue2s(L, ra, t); | 1259 | sethvalue2s(L, ra, t); |
| 1256 | if (b != 0 || c != 0) | 1260 | if (b != 0 || c != 0) |
| 1257 | luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); /* idem */ | 1261 | luaH_resize(L, t, b, c); /* idem */ |
| 1258 | checkGC(L, ra + 1); | 1262 | checkGC(L, ra + 1); |
| 1259 | vmbreak; | 1263 | vmbreak; |
| 1260 | } | 1264 | } |
diff --git a/testes/code.lua b/testes/code.lua index 49d682f8..b2702c61 100644 --- a/testes/code.lua +++ b/testes/code.lua | |||
| @@ -93,11 +93,13 @@ end | |||
| 93 | -- some basic instructions | 93 | -- some basic instructions |
| 94 | check(function () -- function does not create upvalues | 94 | check(function () -- function does not create upvalues |
| 95 | (function () end){f()} | 95 | (function () end){f()} |
| 96 | end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN0') | 96 | end, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL', |
| 97 | 'SETLIST', 'CALL', 'RETURN0') | ||
| 97 | 98 | ||
| 98 | check(function (x) -- function creates upvalues | 99 | check(function (x) -- function creates upvalues |
| 99 | (function () return x end){f()} | 100 | (function () return x end){f()} |
| 100 | end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN') | 101 | end, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL', |
| 102 | 'SETLIST', 'CALL', 'RETURN') | ||
| 101 | 103 | ||
| 102 | 104 | ||
| 103 | -- sequence of LOADNILs | 105 | -- sequence of LOADNILs |
diff --git a/testes/nextvar.lua b/testes/nextvar.lua index 87a6bfa8..bdc9fc29 100644 --- a/testes/nextvar.lua +++ b/testes/nextvar.lua | |||
| @@ -49,33 +49,13 @@ if not T then | |||
| 49 | else --[ | 49 | else --[ |
| 50 | -- testing table sizes | 50 | -- testing table sizes |
| 51 | 51 | ||
| 52 | local function log2 (x) return math.log(x, 2) end | ||
| 53 | 52 | ||
| 54 | local function mp2 (n) -- minimum power of 2 >= n | 53 | local function mp2 (n) -- minimum power of 2 >= n |
| 55 | local mp = 2^math.ceil(log2(n)) | 54 | local mp = 2^math.ceil(math.log(n, 2)) |
| 56 | assert(n == 0 or (mp/2 < n and n <= mp)) | 55 | assert(n == 0 or (mp/2 < n and n <= mp)) |
| 57 | return mp | 56 | return mp |
| 58 | end | 57 | end |
| 59 | 58 | ||
| 60 | local function fb (n) | ||
| 61 | local r, nn = T.int2fb(n) | ||
| 62 | assert(r < 256) | ||
| 63 | return nn | ||
| 64 | end | ||
| 65 | |||
| 66 | -- test fb function | ||
| 67 | for a = 1, 10000 do -- all numbers up to 10^4 | ||
| 68 | local n = fb(a) | ||
| 69 | assert(a <= n and n <= a*1.125) | ||
| 70 | end | ||
| 71 | local a = 1024 -- plus a few up to 2 ^30 | ||
| 72 | local lim = 2^30 | ||
| 73 | while a < lim do | ||
| 74 | local n = fb(a) | ||
| 75 | assert(a <= n and n <= a*1.125) | ||
| 76 | a = math.ceil(a*1.3) | ||
| 77 | end | ||
| 78 | |||
| 79 | 59 | ||
| 80 | local function check (t, na, nh) | 60 | local function check (t, na, nh) |
| 81 | local a, h = T.querytab(t) | 61 | local a, h = T.querytab(t) |
| @@ -95,24 +75,30 @@ end | |||
| 95 | 75 | ||
| 96 | 76 | ||
| 97 | -- testing constructor sizes | 77 | -- testing constructor sizes |
| 98 | local lim = 40 | 78 | local sizes = {0, 1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17, |
| 99 | local s = 'return {' | 79 | 30, 31, 32, 33, 34, 500, 1000} |
| 100 | for i=1,lim do | 80 | |
| 101 | s = s..i..',' | 81 | for _, sa in ipairs(sizes) do -- 'sa' is size of the array part |
| 102 | local s = s | 82 | local arr = {"return {"} |
| 103 | for k=0,lim do | 83 | -- array part |
| 104 | local t = load(s..'}', '')() | 84 | for i = 1, sa do arr[1 + i] = "1," end |
| 105 | assert(#t == i) | 85 | for _, sh in ipairs(sizes) do -- 'sh' is size of the hash part |
| 106 | check(t, fb(i), mp2(k)) | 86 | for j = 1, sh do -- hash part |
| 107 | s = string.format('%sa%d=%d,', s, k, k) | 87 | arr[1 + sa + j] = string.format('k%x=%d,', j, j) |
| 88 | end | ||
| 89 | arr[1 + sa + sh + 1] = "}" | ||
| 90 | local prog = table.concat(arr) | ||
| 91 | local t = assert(load(prog))() | ||
| 92 | assert(#t == sa) | ||
| 93 | check(t, sa, mp2(sh)) | ||
| 108 | end | 94 | end |
| 109 | end | 95 | end |
| 110 | 96 | ||
| 111 | 97 | ||
| 112 | -- tests with unknown number of elements | 98 | -- tests with unknown number of elements |
| 113 | local a = {} | 99 | local a = {} |
| 114 | for i=1,lim do a[i] = i end -- build auxiliary table | 100 | for i=1,sizes[#sizes] do a[i] = i end -- build auxiliary table |
| 115 | for k=0,lim do | 101 | for k in ipairs(sizes) do |
| 116 | local a = {table.unpack(a,1,k)} | 102 | local a = {table.unpack(a,1,k)} |
| 117 | assert(#a == k) | 103 | assert(#a == k) |
| 118 | check(a, k, 0) | 104 | check(a, k, 0) |
