123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- /*
- ** hash.c
- ** hash manager for lua
- ** Luiz Henrique de Figueiredo - 17 Aug 90
- ** Modified by Waldemar Celes Filho
- ** 12 May 93
- */
- #include <string.h>
- #include <stdlib.h>
- #include "opcode.h"
- #include "hash.h"
- #include "inout.h"
- #include "table.h"
- #include "lua.h"
- #define streq(s1,s2) (strcmp(s1,s2)==0)
- #define strneq(s1,s2) (strcmp(s1,s2)!=0)
- #define new(s) ((s *)malloc(sizeof(s)))
- #define newvector(n,s) ((s *)calloc(n,sizeof(s)))
- #define nhash(t) ((t)->nhash)
- #define nodelist(t) ((t)->list)
- #define list(t,i) ((t)->list[i])
- #define ref_tag(n) (tag(&(n)->ref))
- #define ref_nvalue(n) (nvalue(&(n)->ref))
- #define ref_svalue(n) (svalue(&(n)->ref))
- static int head (Hash *t, Object *ref) /* hash function */
- {
- if (tag(ref) == T_NUMBER) return (((int)nvalue(ref))%nhash(t));
- else if (tag(ref) == T_STRING)
- {
- int h;
- char *name = svalue(ref);
- for (h=0; *name!=0; name++) /* interpret name as binary number */
- {
- h <<= 8;
- h += (unsigned char) *name; /* avoid sign extension */
- h %= nhash(t); /* make it a valid index */
- }
- return h;
- }
- else
- {
- lua_reportbug ("unexpected type to index table");
- return -1;
- }
- }
- static Node *present(Hash *t, Object *ref, int h)
- {
- Node *n=NULL, *p;
- if (tag(ref) == T_NUMBER)
- {
- for (p=NULL,n=list(t,h); n!=NULL; p=n, n=n->next)
- if (ref_tag(n) == T_NUMBER && nvalue(ref) == ref_nvalue(n)) break;
- }
- else if (tag(ref) == T_STRING)
- {
- for (p=NULL,n=list(t,h); n!=NULL; p=n, n=n->next)
- if (ref_tag(n) == T_STRING && streq(svalue(ref),ref_svalue(n))) break;
- }
- if (n==NULL) /* name not present */
- return NULL;
- #if 0
- if (p!=NULL) /* name present but not first */
- {
- p->next=n->next; /* move-to-front self-organization */
- n->next=list(t,h);
- list(t,h)=n;
- }
- #endif
- return n;
- }
- static void freelist (Node *n)
- {
- while (n)
- {
- Node *next = n->next;
- free (n);
- n = next;
- }
- }
- /*
- ** Create a new hash. Return the hash pointer or NULL on error.
- */
- Hash *lua_hashcreate (unsigned int nhash)
- {
- Hash *t = new (Hash);
- if (t == NULL)
- {
- lua_error ("not enough memory");
- return NULL;
- }
- nhash(t) = nhash;
- markarray(t) = 0;
- nodelist(t) = newvector (nhash, Node*);
- if (nodelist(t) == NULL)
- {
- lua_error ("not enough memory");
- return NULL;
- }
- return t;
- }
- /*
- ** Delete a hash
- */
- void lua_hashdelete (Hash *h)
- {
- int i;
- for (i=0; i<nhash(h); i++)
- freelist (list(h,i));
- free (nodelist(h));
- free(h);
- }
- /*
- ** If the hash node is present, return its pointer, otherwise create a new
- ** node for the given reference and also return its pointer.
- ** On error, return NULL.
- */
- Object *lua_hashdefine (Hash *t, Object *ref)
- {
- int h;
- Node *n;
- h = head (t, ref);
- if (h < 0) return NULL;
-
- n = present(t, ref, h);
- if (n == NULL)
- {
- n = new(Node);
- if (n == NULL)
- {
- lua_error ("not enough memory");
- return NULL;
- }
- n->ref = *ref;
- tag(&n->val) = T_NIL;
- n->next = list(t,h); /* link node to head of list */
- list(t,h) = n;
- }
- return (&n->val);
- }
- /*
- ** Mark a hash and check its elements
- */
- void lua_hashmark (Hash *h)
- {
- int i;
-
- markarray(h) = 1;
-
- for (i=0; i<nhash(h); i++)
- {
- Node *n;
- for (n = list(h,i); n != NULL; n = n->next)
- {
- lua_markobject (&n->ref);
- lua_markobject (&n->val);
- }
- }
- }
- /*
- ** Internal function to manipulate arrays.
- ** Given an array object and a reference value, return the next element
- ** in the hash.
- ** This function pushs the element value and its reference to the stack.
- */
- #include "lua.h"
- static void firstnode (Hash *a, int h)
- {
- if (h < nhash(a))
- {
- int i;
- for (i=h; i<nhash(a); i++)
- {
- if (list(a,i) != NULL && tag(&list(a,i)->val) != T_NIL)
- {
- lua_pushobject (&list(a,i)->ref);
- lua_pushobject (&list(a,i)->val);
- return;
- }
- }
- }
- lua_pushnil();
- lua_pushnil();
- }
- void lua_next (void)
- {
- Hash *a;
- Object *o = lua_getparam (1);
- Object *r = lua_getparam (2);
- if (o == NULL || r == NULL)
- { lua_error ("too few arguments to function `next'"); return; }
- if (lua_getparam (3) != NULL)
- { lua_error ("too many arguments to function `next'"); return; }
- if (tag(o) != T_ARRAY)
- { lua_error ("first argument of function `next' is not a table"); return; }
- a = avalue(o);
- if (tag(r) == T_NIL)
- {
- firstnode (a, 0);
- return;
- }
- else
- {
- int h = head (a, r);
- if (h >= 0)
- {
- Node *n = list(a,h);
- while (n)
- {
- if (memcmp(&n->ref,r,sizeof(Object)) == 0)
- {
- if (n->next == NULL)
- {
- firstnode (a, h+1);
- return;
- }
- else if (tag(&n->next->val) != T_NIL)
- {
- lua_pushobject (&n->next->ref);
- lua_pushobject (&n->next->val);
- return;
- }
- else
- {
- Node *next = n->next->next;
- while (next != NULL && tag(&next->val) == T_NIL) next = next->next;
- if (next == NULL)
- {
- firstnode (a, h+1);
- return;
- }
- else
- {
- lua_pushobject (&next->ref);
- lua_pushobject (&next->val);
- }
- return;
- }
- }
- n = n->next;
- }
- if (n == NULL)
- lua_error ("error in function 'next': reference not found");
- }
- }
- }
|