Discuss the table length problem that many people in Lua have questions about.
<pre name= "code" class= "CPP" >
1. > tbl = {A-i}
> Print (#tbl)
3
>
2. > tbl = {1,nil,3}
> Print (#tbl)
3
>
3. > tbl = {1,nil,3,nil}
> Print (#tbl)
1
Situation 1 Normal, situation 2 is a bit abnormal, the situation 3 is not normal, good, first on the source code.
int Luah_getn (Table *t) {
unsigned int j = t->sizearray;
if (J > 0 && ttisnil (&t->array[j-1])) {/
* There is a boundary in the array part: (binary) search For it */
unsigned int i = 0;
while (J-i > 1) {
unsigned int m = (i+j)/2;
if (Ttisnil (&t->array[m-1]))j = m;
else i = m;
}
return i;
}
/* Else must find a boundary in hash part */
else if (Isdummy (T->node))/ * Hash part is empty? */
return J; /* That's easy ... */
else return Unbound_search (T, j);
}
This function is used to understand the length of the table, and understanding this function is very helpful for the whole principle of LUA table.
Condition 1:j>0 and the last of the array part is empty, the binary lookup is to find an i is not empty, J is empty two index, when j-i>1 jumps out to return I.
Conditional 2:j<=0 or array the last one is not empty, and there is no hash part, at this time, no way, no statistics, compromise returns the length of the array.
Conditional 3:j<=0 or array the last one is not empty, there is a hash part, into the Unbound_search, from the literal meaning, is in a chaotic interval to find, this function is finally a binary search.
First understand the condition 1, the top of the situation three is in line with the conditions of 1, good, directly on the GDB. Take a look at the screenshot below.
Array length j = T->t->sizearray = 4,j>0, print the last element:
Tt_ = 0 indicates that this element is a nil value, matches the condition 1, goes to the binary lookup, this binary search is to find a left is not nil, the right is nil when the left index.
i = 0,j = 4,m = (i+j)/2 = 2,m-1 = 1, Yenso with index 1 is nil,0 is 1, so j = m = 2
i = 0,j = 2,m = (i+j)/2 = 1,m-1 = 0, Yenso with index 0 is 1, so i = m = 1;
i = 1,j=2, exit loop, length 1
It can be learned that even if only the length of the array part of the statistics may not be normal.
Condition 2 Manufacturing is simple, in line with the situation 2, see GDB:
TBL = {1,nil,3}, this table degree j = T->sizearray = 3, the last element tt_ = 3,n = 3, means that this value is number type and the value is 3, that is, the last element of TBL is not nil,t->node And the Isdummy,hash part is also empty, the compromise returns the array length 3 directly.
First look at the Unbound_search function implementation:
static int Unbound_search (Table *t, unsigned int j) {
unsigned int i = j;
/* I is zero or a present index */
j + +;
/* find ' I ' and ' j ' such that I am present and J is not */
while (!ttisnil (Luah_getint (T, j))) {
i = j;
J *= 2;
if (J > cast (unsigned int, max_int)) {
/* overflow */
/* table was built with bad purposes:resort to linear SE Arch */i = 1;
while (!ttisnil (Luah_getint (t, i))
i++;
return i-1;
}}
/* Now does a binary search between them */
while (J-i > 1) {
unsigned int m = (i+j)/2;
if (Ttisnil (Luah_getint (T, m))
j = m;
else i = m;
}
return i;
}
const TValue *luah_getint (Table *t, int key) {
/* (1 <= key && key <= t->sizearray) */
if (CAST (Unsigned int, key-1) < cast (unsigned int, t->sizearray))
return &t->array[key-1];
else {
Lua_number NK = Cast_num (key);
Node *n = Hashnum (T, NK);
Do {
/* check whether ' key ' is somewhere in the chain */
if (Ttisnumber (Gkey (n)) && luai_numeq (Nvalue (Gkey (n)), NK)
return Gval (n);
/* that ' s it */
else
n = gnext (n);
}
while (n);
return luao_nilobject;
}
}
This function passes in an array length, which means that the array is full before entering this function.
The first while is to always find a J, and with this J as key, does not exist in the table, including the array part and the hash part (Luah_getint implementation), side exit the first while, if halfway j>max_int, no way, this j is very big, can only resort to linear search, that is, go to linear lookup, one to find a null to return I-1 to the length of the table.
After the first while found J, at this time I and J is not nil on the left, the right is nil two values, before the two values, find the smallest left is not nil, the right is nil two values, return the former.
Well, to make this happen, look at GDB:
TBL = {1,nil,3,qs = 19891103}, array length is 3, the last element is not nil,
There is a hash section, see QS = 19891103, into a cluttered interval to find (unbound_search), when entering the first while I=3,j=4,luah_getint
, a key of 4 does not exist in both the array part and the hash section. Go directly to the 3 on the left and 4 on the right (this two-point lookup says above). Returns 3 directly to the length of the table.
It can be seen that when entering the unbound_search, it is possible to obtain the data length, which may be reliable and most of the cases are not reliable.
If the array part is full and there is no empty case, and the key that exists in the hash part is contiguous with the array part, at which time the obtained length is expected, and the hash part is entered into the Unbound_search lookup, if tbl = {1,2,3,[4] = 4}, at this point, externally, this tbl is really an array, but in memory, not, in the array part, 4 in the hash part, so in the Unbound_search, this time to get the length is normal.