mirror of
https://github.com/nodemcu/nodemcu-firmware.git
synced 2025-01-30 21:12:55 +08:00
526d21dab4
The PR removed the bulk of non-newlib headers from the NodeMCU source base. app/libc has now been cut down to the bare minimum overrides to shadow the corresponding functions in the SDK's libc. The old c_xyz.h headerfiles have been nuked in favour of the standard <xyz.h> headers, with a few exceptions over in sdk-overrides. Again, shipping a libc.a without headers is a terrible thing to do. We're still living on a prayer that libc was configured the same was as a default-configured xtensa gcc toolchain assumes it is. That part I cannot do anything about, unfortunately, but it's no worse than it has been before. This enables our source files to compile successfully using the standard header files, and use the typical malloc()/calloc()/realloc()/free(), the strwhatever()s and memwhatever()s. These end up, through macro and linker magic, mapped to the appropriate SDK or ROM functions.
754 lines
21 KiB
C
754 lines
21 KiB
C
/*
|
|
** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $
|
|
** Lua tables (hash)
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
|
|
|
|
/*
|
|
** Implementation of tables (aka arrays, objects, or hash tables).
|
|
** Tables keep its elements in two parts: an array part and a hash part.
|
|
** Non-negative integer keys are all candidates to be kept in the array
|
|
** part. The actual size of the array is the largest `n' such that at
|
|
** least half the slots between 0 and n are in use.
|
|
** Hash uses a mix of chained scatter table with Brent's variation.
|
|
** A main invariant of these tables is that, if an element is not
|
|
** in its main position (i.e. the `original' position that its hash gives
|
|
** to it), then the colliding element is in its own main position.
|
|
** Hence even when the load factor reaches 100%, performance remains good.
|
|
*/
|
|
|
|
#define ltable_c
|
|
#define LUA_CORE
|
|
#define LUAC_CROSS_FILE
|
|
|
|
#include "lua.h"
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
#include "ldebug.h"
|
|
#include "ldo.h"
|
|
#include "lgc.h"
|
|
#include "lmem.h"
|
|
#include "lobject.h"
|
|
#include "lstate.h"
|
|
#include "ltable.h"
|
|
#include "lrotable.h"
|
|
|
|
/*
|
|
** max size of array part is 2^MAXBITS
|
|
*/
|
|
#if LUAI_BITSINT > 26
|
|
#define MAXBITS 26
|
|
#else
|
|
#define MAXBITS (LUAI_BITSINT-2)
|
|
#endif
|
|
|
|
#define MAXASIZE (1 << MAXBITS)
|
|
|
|
|
|
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
|
|
|
|
#define hashstr(t,str) hashpow2(t, (str)->tsv.hash)
|
|
#define hashboolean(t,p) hashpow2(t, p)
|
|
|
|
|
|
/*
|
|
** for some types, it is better to avoid modulus by power of 2, as
|
|
** they tend to have many 2 factors.
|
|
*/
|
|
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
|
|
|
|
|
|
#define hashpointer(t,p) hashmod(t, IntPoint(p))
|
|
|
|
|
|
/*
|
|
** number of ints inside a lua_Number
|
|
*/
|
|
#define numints cast_int(sizeof(lua_Number)/sizeof(int))
|
|
|
|
|
|
|
|
#define dummynode (&dummynode_)
|
|
|
|
static const Node dummynode_ = {
|
|
{LUA_TVALUE_NIL}, /* value */
|
|
{LUA_TKEY_NIL} /* key */
|
|
};
|
|
|
|
|
|
/*
|
|
** hash for lua_Numbers
|
|
*/
|
|
static Node *hashnum (const Table *t, lua_Number n) {
|
|
unsigned int a[numints];
|
|
int i;
|
|
if (luai_numeq(n, 0)) /* avoid problems with -0 */
|
|
return gnode(t, 0);
|
|
memcpy(a, &n, sizeof(a));
|
|
for (i = 1; i < numints; i++) a[0] += a[i];
|
|
return hashmod(t, a[0]);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** returns the `main' position of an element in a table (that is, the index
|
|
** of its hash value)
|
|
*/
|
|
static Node *mainposition (const Table *t, const TValue *key) {
|
|
switch (ttype(key)) {
|
|
case LUA_TNUMBER:
|
|
return hashnum(t, nvalue(key));
|
|
case LUA_TSTRING:
|
|
return hashstr(t, rawtsvalue(key));
|
|
case LUA_TBOOLEAN:
|
|
return hashboolean(t, bvalue(key));
|
|
case LUA_TROTABLE:
|
|
return hashpointer(t, rvalue(key));
|
|
case LUA_TLIGHTUSERDATA:
|
|
case LUA_TLIGHTFUNCTION:
|
|
return hashpointer(t, pvalue(key));
|
|
default:
|
|
return hashpointer(t, gcvalue(key));
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** returns the index for `key' if `key' is an appropriate key to live in
|
|
** the array part of the table, -1 otherwise.
|
|
*/
|
|
static int arrayindex (const TValue *key) {
|
|
if (ttisnumber(key)) {
|
|
lua_Number n = nvalue(key);
|
|
int k;
|
|
lua_number2int(k, n);
|
|
if (luai_numeq(cast_num(k), n))
|
|
return k;
|
|
}
|
|
return -1; /* `key' did not match some condition */
|
|
}
|
|
|
|
|
|
/*
|
|
** returns the index of a `key' for table traversals. First goes all
|
|
** elements in the array part, then elements in the hash part. The
|
|
** beginning of a traversal is signalled by -1.
|
|
*/
|
|
static int findindex (lua_State *L, Table *t, StkId key) {
|
|
int i;
|
|
if (ttisnil(key)) return -1; /* first iteration */
|
|
i = arrayindex(key);
|
|
if (0 < i && i <= t->sizearray) /* is `key' inside array part? */
|
|
return i-1; /* yes; that's the index (corrected to C) */
|
|
else {
|
|
Node *n = mainposition(t, key);
|
|
do { /* check whether `key' is somewhere in the chain */
|
|
/* key may be dead already, but it is ok to use it in `next' */
|
|
if (luaO_rawequalObj(key2tval(n), key) ||
|
|
(ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) &&
|
|
gcvalue(gkey(n)) == gcvalue(key))) {
|
|
i = cast_int(n - gnode(t, 0)); /* key index in hash table */
|
|
/* hash elements are numbered after array ones */
|
|
return i + t->sizearray;
|
|
}
|
|
else n = gnext(n);
|
|
} while (n);
|
|
luaG_runerror(L, "invalid key to " LUA_QL("next")); /* key not found */
|
|
return 0; /* to avoid warnings */
|
|
}
|
|
}
|
|
|
|
|
|
int luaH_next (lua_State *L, Table *t, StkId key) {
|
|
int i = findindex(L, t, key); /* find original element */
|
|
for (i++; i < t->sizearray; i++) { /* try first array part */
|
|
if (!ttisnil(&t->array[i])) { /* a non-nil value? */
|
|
setnvalue(key, cast_num(i+1));
|
|
setobj2s(L, key+1, &t->array[i]);
|
|
return 1;
|
|
}
|
|
}
|
|
for (i -= t->sizearray; i < sizenode(t); i++) { /* then hash part */
|
|
if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */
|
|
setobj2s(L, key, key2tval(gnode(t, i)));
|
|
setobj2s(L, key+1, gval(gnode(t, i)));
|
|
return 1;
|
|
}
|
|
}
|
|
return 0; /* no more elements */
|
|
}
|
|
|
|
|
|
int luaH_next_ro (lua_State *L, void *t, StkId key) {
|
|
luaR_next(L, t, key, key+1);
|
|
return ttisnil(key) ? 0 : 1;
|
|
}
|
|
|
|
|
|
/*
|
|
** {=============================================================
|
|
** Rehash
|
|
** ==============================================================
|
|
*/
|
|
|
|
|
|
static int computesizes (int nums[], int *narray) {
|
|
int i;
|
|
int twotoi; /* 2^i */
|
|
int a = 0; /* number of elements smaller than 2^i */
|
|
int na = 0; /* number of elements to go to array part */
|
|
int n = 0; /* optimal size for array part */
|
|
for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
|
|
if (nums[i] > 0) {
|
|
a += nums[i];
|
|
if (a > twotoi/2) { /* more than half elements present? */
|
|
n = twotoi; /* optimal size (till now) */
|
|
na = a; /* all elements smaller than n will go to array part */
|
|
}
|
|
}
|
|
if (a == *narray) break; /* all elements already counted */
|
|
}
|
|
*narray = n;
|
|
lua_assert(*narray/2 <= na && na <= *narray);
|
|
return na;
|
|
}
|
|
|
|
|
|
static int countint (const TValue *key, int *nums) {
|
|
int k = arrayindex(key);
|
|
if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */
|
|
nums[ceillog2(k)]++; /* count as such */
|
|
return 1;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int numusearray (const Table *t, int *nums) {
|
|
int lg;
|
|
int ttlg; /* 2^lg */
|
|
int ause = 0; /* summation of `nums' */
|
|
int i = 1; /* count to traverse all array keys */
|
|
for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */
|
|
int lc = 0; /* counter */
|
|
int lim = ttlg;
|
|
if (lim > t->sizearray) {
|
|
lim = t->sizearray; /* adjust upper limit */
|
|
if (i > lim)
|
|
break; /* no more elements to count */
|
|
}
|
|
/* count elements in range (2^(lg-1), 2^lg] */
|
|
for (; i <= lim; i++) {
|
|
if (!ttisnil(&t->array[i-1]))
|
|
lc++;
|
|
}
|
|
nums[lg] += lc;
|
|
ause += lc;
|
|
}
|
|
return ause;
|
|
}
|
|
|
|
|
|
static int numusehash (const Table *t, int *nums, int *pnasize) {
|
|
int totaluse = 0; /* total number of elements */
|
|
int ause = 0; /* summation of `nums' */
|
|
int i = sizenode(t);
|
|
while (i--) {
|
|
Node *n = &t->node[i];
|
|
if (!ttisnil(gval(n))) {
|
|
ause += countint(key2tval(n), nums);
|
|
totaluse++;
|
|
}
|
|
}
|
|
*pnasize += ause;
|
|
return totaluse;
|
|
}
|
|
|
|
|
|
static void setarrayvector (lua_State *L, Table *t, int size) {
|
|
int i;
|
|
luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
|
|
for (i=t->sizearray; i<size; i++)
|
|
setnilvalue(&t->array[i]);
|
|
t->sizearray = size;
|
|
}
|
|
|
|
|
|
static Node *getfreepos (Table *t) {
|
|
while (t->lastfree-- > t->node) {
|
|
if (ttisnil(gkey(t->lastfree)))
|
|
return t->lastfree;
|
|
}
|
|
return NULL; /* could not find a free place */
|
|
}
|
|
|
|
|
|
static void resizenodevector (lua_State *L, Table *t, int oldsize, int newsize) {
|
|
int lsize;
|
|
if (newsize == 0) { /* no elements to hash part? */
|
|
t->node = cast(Node *, dummynode); /* use common `dummynode' */
|
|
lsize = 0;
|
|
}
|
|
else {
|
|
Node *node = t->node;
|
|
int i;
|
|
lsize = ceillog2(newsize);
|
|
if (lsize > MAXBITS)
|
|
luaG_runerror(L, "table overflow");
|
|
newsize = twoto(lsize);
|
|
if (node == dummynode) {
|
|
oldsize = 0;
|
|
node = NULL; /* don't try to realloc `dummynode' pointer. */
|
|
}
|
|
luaM_reallocvector(L, node, oldsize, newsize, Node);
|
|
t->node = node;
|
|
for (i=oldsize; i<newsize; i++) {
|
|
Node *n = gnode(t, i);
|
|
gnext(n) = NULL;
|
|
setnilvalue(gkey(n));
|
|
setnilvalue(gval(n));
|
|
}
|
|
}
|
|
t->lsizenode = cast_byte(lsize);
|
|
t->lastfree = gnode(t, newsize); /* reset lastfree to end of table. */
|
|
}
|
|
|
|
|
|
static Node *find_prev_node(Node *mp, Node *next) {
|
|
Node *prev = mp;
|
|
while (prev != NULL && gnext(prev) != next) prev = gnext(prev);
|
|
return prev;
|
|
}
|
|
|
|
|
|
/*
|
|
** move a node from it's old position to it's new position during a rehash;
|
|
** first, check whether the moving node's main position is free. If not, check whether
|
|
** colliding node is in its main position or not: if it is not, move colliding
|
|
** node to an empty place and put moving node in its main position; otherwise
|
|
** (colliding node is in its main position), moving node goes to an empty position.
|
|
*/
|
|
static int move_node (lua_State *L, Table *t, Node *node) {
|
|
Node *mp = mainposition(t, key2tval(node));
|
|
/* if node is in it's main position, don't need to move node. */
|
|
if (mp == node) return 1;
|
|
/* if node is in it's main position's chain, don't need to move node. */
|
|
if (find_prev_node(mp, node) != NULL) return 1;
|
|
/* is main position is free? */
|
|
if (!ttisnil(gval(mp)) || mp == dummynode) {
|
|
/* no; move main position node if it is out of its main position */
|
|
Node *othermp;
|
|
othermp = mainposition(t, key2tval(mp));
|
|
if (othermp != mp) { /* is colliding node out of its main position? */
|
|
/* yes; swap colliding node with the node that is being moved. */
|
|
Node *prev;
|
|
Node tmp;
|
|
tmp = *node;
|
|
prev = find_prev_node(othermp, mp); /* find previous */
|
|
if (prev != NULL) gnext(prev) = node; /* redo the chain with `n' in place of `mp' */
|
|
*node = *mp; /* copy colliding node into free pos. (mp->next also goes) */
|
|
*mp = tmp;
|
|
return (prev != NULL) ? 1 : 0; /* is colliding node part of its main position chain? */
|
|
}
|
|
else { /* colliding node is in its own main position */
|
|
/* add node to main position's chain. */
|
|
gnext(node) = gnext(mp); /* chain new position */
|
|
gnext(mp) = node;
|
|
}
|
|
}
|
|
else { /* main position is free, move node */
|
|
*mp = *node;
|
|
gnext(node) = NULL;
|
|
setnilvalue(gkey(node));
|
|
setnilvalue(gval(node));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int move_number (lua_State *L, Table *t, Node *node) {
|
|
int key;
|
|
lua_Number n = nvalue(key2tval(node));
|
|
lua_number2int(key, n);
|
|
if (luai_numeq(cast_num(key), nvalue(key2tval(node)))) {/* index is int? */
|
|
/* (1 <= key && key <= t->sizearray) */
|
|
if (cast(unsigned int, key-1) < cast(unsigned int, t->sizearray)) {
|
|
setobjt2t(L, &t->array[key-1], gval(node));
|
|
setnilvalue(gkey(node));
|
|
setnilvalue(gval(node));
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void resize_hashpart (lua_State *L, Table *t, int nhsize) {
|
|
int i;
|
|
int lsize=0;
|
|
int oldhsize = (t->node != dummynode) ? twoto(t->lsizenode) : 0;
|
|
if (nhsize > 0) { /* round new hashpart size up to next power of two. */
|
|
lsize=ceillog2(nhsize);
|
|
if (lsize > MAXBITS)
|
|
luaG_runerror(L, "table overflow");
|
|
}
|
|
nhsize = twoto(lsize);
|
|
/* grow hash part to new size. */
|
|
if (oldhsize < nhsize)
|
|
resizenodevector(L, t, oldhsize, nhsize);
|
|
else { /* hash part might be shrinking */
|
|
if (nhsize > 0) {
|
|
t->lsizenode = cast_byte(lsize);
|
|
t->lastfree = gnode(t, nhsize); /* reset lastfree back to end of table. */
|
|
}
|
|
else { /* new hashpart size is zero. */
|
|
resizenodevector(L, t, oldhsize, nhsize);
|
|
return;
|
|
}
|
|
}
|
|
/* break old chains, try moving int keys to array part and compact keys into new hashpart */
|
|
for (i = 0; i < oldhsize; i++) {
|
|
Node *old = gnode(t, i);
|
|
gnext(old) = NULL;
|
|
if (ttisnil(gval(old))) { /* clear nodes with nil values. */
|
|
setnilvalue(gkey(old));
|
|
continue;
|
|
}
|
|
if (ttisnumber(key2tval(old))) { /* try moving the int keys into array part. */
|
|
if(move_number(L, t, old))
|
|
continue;
|
|
}
|
|
if (i >= nhsize) { /* move all valid keys to indices < nhsize. */
|
|
Node *n = getfreepos(t); /* get a free place */
|
|
lua_assert(n != dummynode && n != NULL);
|
|
*n = *old;
|
|
}
|
|
}
|
|
/* shrink hash part */
|
|
if (oldhsize > nhsize)
|
|
resizenodevector(L, t, oldhsize, nhsize);
|
|
/* move nodes to their new mainposition and re-create node chains */
|
|
for (i = 0; i < nhsize; i++) {
|
|
Node *curr = gnode(t, i);
|
|
if (!ttisnil(gval(curr)))
|
|
while (move_node(L, t, curr) == 0);
|
|
}
|
|
}
|
|
|
|
|
|
static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
|
|
int i;
|
|
int oldasize = t->sizearray;
|
|
if (nasize > oldasize) /* array part must grow? */
|
|
setarrayvector(L, t, nasize);
|
|
if (t->node != dummynode || nhsize>0)
|
|
resize_hashpart(L, t, nhsize);
|
|
if (nasize < oldasize) { /* array part must shrink? */
|
|
t->sizearray = nasize;
|
|
/* re-insert elements from vanishing slice */
|
|
for (i=nasize; i<oldasize; i++) {
|
|
if (!ttisnil(&t->array[i]))
|
|
setobjt2t(L, luaH_setnum(L, t, i+1), &t->array[i]);
|
|
}
|
|
/* shrink array */
|
|
luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
|
|
}
|
|
}
|
|
|
|
|
|
void luaH_resizearray (lua_State *L, Table *t, int nasize) {
|
|
int nsize = (t->node == dummynode) ? 0 : sizenode(t);
|
|
resize(L, t, nasize, nsize);
|
|
}
|
|
|
|
|
|
static void rehash (lua_State *L, Table *t, const TValue *ek) {
|
|
int nasize, na;
|
|
int nums[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */
|
|
int i;
|
|
int totaluse;
|
|
for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */
|
|
nasize = numusearray(t, nums); /* count keys in array part */
|
|
totaluse = nasize; /* all those keys are integer keys */
|
|
totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */
|
|
/* count extra key */
|
|
nasize += countint(ek, nums);
|
|
totaluse++;
|
|
/* compute new size for array part */
|
|
na = computesizes(nums, &nasize);
|
|
/* resize the table to new computed sizes */
|
|
resize(L, t, nasize, totaluse - na);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** }=============================================================
|
|
*/
|
|
|
|
|
|
Table *luaH_new (lua_State *L, int narray, int nhash) {
|
|
Table *t = luaM_new(L, Table);
|
|
luaC_link(L, obj2gco(t), LUA_TTABLE);
|
|
sethvalue2s(L, L->top, t); /* put table on stack */
|
|
incr_top(L);
|
|
t->metatable = NULL;
|
|
t->flags = cast_byte(~0);
|
|
/* temporary values (kept only if some malloc fails) */
|
|
t->array = NULL;
|
|
t->sizearray = 0;
|
|
t->lsizenode = 0;
|
|
t->node = cast(Node *, dummynode);
|
|
setarrayvector(L, t, narray);
|
|
resizenodevector(L, t, 0, nhash);
|
|
L->top--; /* remove table from stack */
|
|
return t;
|
|
}
|
|
|
|
|
|
void luaH_free (lua_State *L, Table *t) {
|
|
if (t->node != dummynode)
|
|
luaM_freearray(L, t->node, sizenode(t), Node);
|
|
luaM_freearray(L, t->array, t->sizearray, TValue);
|
|
luaM_free(L, t);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** inserts a new key into a hash table; first, check whether key's main
|
|
** position is free. If not, check whether colliding node is in its main
|
|
** position or not: if it is not, move colliding node to an empty place and
|
|
** put new key in its main position; otherwise (colliding node is in its main
|
|
** position), new key goes to an empty position.
|
|
*/
|
|
static TValue *newkey (lua_State *L, Table *t, const TValue *key) {
|
|
Node *mp = mainposition(t, key);
|
|
if (!ttisnil(gval(mp)) || mp == dummynode) {
|
|
Node *othern;
|
|
Node *n = getfreepos(t); /* get a free place */
|
|
if (n == NULL) { /* cannot find a free place? */
|
|
rehash(L, t, key); /* grow table */
|
|
return luaH_set(L, t, key); /* re-insert key into grown table */
|
|
}
|
|
lua_assert(n != dummynode);
|
|
othern = mainposition(t, key2tval(mp));
|
|
if (othern != mp) { /* is colliding node out of its main position? */
|
|
/* yes; move colliding node into free position */
|
|
while (gnext(othern) != mp) othern = gnext(othern); /* find previous */
|
|
gnext(othern) = n; /* redo the chain with `n' in place of `mp' */
|
|
*n = *mp; /* copy colliding node into free pos. (mp->next also goes) */
|
|
gnext(mp) = NULL; /* now `mp' is free */
|
|
setnilvalue(gval(mp));
|
|
}
|
|
else { /* colliding node is in its own main position */
|
|
/* new node will go into free position */
|
|
gnext(n) = gnext(mp); /* chain new position */
|
|
gnext(mp) = n;
|
|
mp = n;
|
|
}
|
|
}
|
|
setobj2t(L, gkey(mp), key);
|
|
luaC_barriert(L, t, key);
|
|
lua_assert(ttisnil(gval(mp)));
|
|
return gval(mp);
|
|
}
|
|
|
|
|
|
/*
|
|
** search function for integers
|
|
*/
|
|
const TValue *luaH_getnum (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;
|
|
}
|
|
}
|
|
|
|
/* same thing for rotables */
|
|
const TValue *luaH_getnum_ro (void *t, int key) {
|
|
const TValue *res = NULL; // integer values not supported: luaR_findentryN(t, key, NULL);
|
|
return res ? res : luaO_nilobject;
|
|
}
|
|
|
|
|
|
/*
|
|
** search function for strings
|
|
*/
|
|
const TValue *luaH_getstr (Table *t, TString *key) {
|
|
Node *n = hashstr(t, key);
|
|
do { /* check whether `key' is somewhere in the chain */
|
|
if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key)
|
|
return gval(n); /* that's it */
|
|
else n = gnext(n);
|
|
} while (n);
|
|
return luaO_nilobject;
|
|
}
|
|
|
|
/* same thing for rotables */
|
|
const TValue *luaH_getstr_ro (void *t, TString *key) {
|
|
if (!t || key->tsv.len>LUA_MAX_ROTABLE_NAME)
|
|
return luaO_nilobject;
|
|
return luaR_findentry(t, key, NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
** main search function
|
|
*/
|
|
const TValue *luaH_get (Table *t, const TValue *key) {
|
|
switch (ttype(key)) {
|
|
case LUA_TNIL: return luaO_nilobject;
|
|
case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
|
|
case LUA_TNUMBER: {
|
|
int k;
|
|
lua_Number n = nvalue(key);
|
|
lua_number2int(k, n);
|
|
if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
|
|
return luaH_getnum(t, k); /* use specialized version */
|
|
/* else go through */
|
|
}
|
|
default: {
|
|
Node *n = mainposition(t, key);
|
|
do { /* check whether `key' is somewhere in the chain */
|
|
if (luaO_rawequalObj(key2tval(n), key))
|
|
return gval(n); /* that's it */
|
|
else n = gnext(n);
|
|
} while (n);
|
|
return luaO_nilobject;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* same thing for rotables */
|
|
const TValue *luaH_get_ro (void *t, const TValue *key) {
|
|
switch (ttype(key)) {
|
|
case LUA_TNIL: return luaO_nilobject;
|
|
case LUA_TSTRING: return luaH_getstr_ro(t, rawtsvalue(key));
|
|
case LUA_TNUMBER: {
|
|
int k;
|
|
lua_Number n = nvalue(key);
|
|
lua_number2int(k, n);
|
|
if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
|
|
return luaH_getnum_ro(t, k); /* use specialized version */
|
|
/* else go through */
|
|
}
|
|
default: {
|
|
return luaO_nilobject;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
|
|
const TValue *p = luaH_get(t, key);
|
|
t->flags = 0;
|
|
if (p != luaO_nilobject)
|
|
return cast(TValue *, p);
|
|
else {
|
|
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
|
|
else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
|
|
luaG_runerror(L, "table index is NaN");
|
|
return newkey(L, t, key);
|
|
}
|
|
}
|
|
|
|
|
|
TValue *luaH_setnum (lua_State *L, Table *t, int key) {
|
|
const TValue *p = luaH_getnum(t, key);
|
|
if (p != luaO_nilobject)
|
|
return cast(TValue *, p);
|
|
else {
|
|
TValue k;
|
|
setnvalue(&k, cast_num(key));
|
|
return newkey(L, t, &k);
|
|
}
|
|
}
|
|
|
|
|
|
TValue *luaH_setstr (lua_State *L, Table *t, TString *key) {
|
|
const TValue *p = luaH_getstr(t, key);
|
|
if (p != luaO_nilobject)
|
|
return cast(TValue *, p);
|
|
else {
|
|
TValue k;
|
|
setsvalue(L, &k, key);
|
|
return newkey(L, t, &k);
|
|
}
|
|
}
|
|
|
|
|
|
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 is present and j is not */
|
|
while (!ttisnil(luaH_getnum(t, j))) {
|
|
i = j;
|
|
j *= 2;
|
|
if (j > cast(unsigned int, MAX_INT)) { /* overflow? */
|
|
/* table was built with bad purposes: resort to linear search */
|
|
i = 1;
|
|
while (!ttisnil(luaH_getnum(t, i))) i++;
|
|
return i - 1;
|
|
}
|
|
}
|
|
/* now do a binary search between them */
|
|
while (j - i > 1) {
|
|
unsigned int m = (i+j)/2;
|
|
if (ttisnil(luaH_getnum(t, m))) j = m;
|
|
else i = m;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
|
|
/*
|
|
** Try to find a boundary in table `t'. A `boundary' is an integer index
|
|
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
|
|
*/
|
|
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 (t->node == dummynode) /* hash part is empty? */
|
|
return j; /* that is easy... */
|
|
else return unbound_search(t, j);
|
|
}
|
|
|
|
/* same thing for rotables */
|
|
int luaH_getn_ro (void *t) {
|
|
return 0; // Integer Keys are not currently supported for ROTables
|
|
}
|
|
|
|
int luaH_isdummy (Node *n) { return n == dummynode; }
|
|
|
|
#if defined(LUA_DEBUG)
|
|
Node *luaH_mainposition (const Table *t, const TValue *key) {
|
|
return mainposition(t, key);
|
|
}
|
|
#endif
|
|
|
|
|