ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

lstring.cpp

Go to the documentation of this file.
00001 /*
00002 ** String table (keeps all strings handled by Lua)
00003 ** See Copyright Notice in lua.h
00004 */
00005 
00006 #define FORBIDDEN_SYMBOL_EXCEPTION_setjmp
00007 #define FORBIDDEN_SYMBOL_EXCEPTION_longjmp
00008 
00009 #include "common/util.h"
00010 
00011 #include "engines/grim/lua/lmem.h"
00012 #include "engines/grim/lua/lobject.h"
00013 #include "engines/grim/lua/lstate.h"
00014 #include "engines/grim/lua/lstring.h"
00015 #include "engines/grim/lua/lua.h"
00016 
00017 namespace Grim {
00018 
00019 #define gcsizestring(l) (1 + (l / 64))  // "weight" for a string with length 'l'
00020 
00021 TaggedString EMPTY = {{nullptr, 2}, 0, 0L, {LUA_T_NIL, {nullptr}}, {0}};
00022 
00023 void luaS_init() {
00024     int32 i;
00025     string_root = luaM_newvector(NUM_HASHS, stringtable);
00026     for (i = 0; i < NUM_HASHS; i++) {
00027         string_root[i].size = 0;
00028         string_root[i].nuse = 0;
00029         string_root[i].hash = nullptr;
00030     }
00031 }
00032 
00033 static uint32 hash(const char *s, int32 tag) {
00034     uint32 h;
00035     if (tag != LUA_T_STRING) {
00036         h = (uintptr)s;
00037     } else {
00038         h = 0;
00039         while (*s)
00040             h = ((h << 5) - h) ^ (byte)*(s++);
00041     }
00042     return h;
00043 }
00044 
00045 static void grow(stringtable *tb) {
00046     int newsize = luaO_redimension(tb->size);
00047     TaggedString **newhash = luaM_newvector(newsize, TaggedString *);
00048     int32 i;
00049 
00050     for (i = 0; i < newsize; i++)
00051         newhash[i] = nullptr;
00052     // rehash
00053     tb->nuse = 0;
00054     for (i = 0; i < tb->size; i++) {
00055         if (tb->hash[i] && tb->hash[i] != &EMPTY) {
00056             int32 h = tb->hash[i]->hash % newsize;
00057             while (newhash[h])
00058                 h = (h + 1) % newsize;
00059             newhash[h] = tb->hash[i];
00060             tb->nuse++;
00061         }
00062     }
00063     luaM_free(tb->hash);
00064     tb->size = newsize;
00065     tb->hash = newhash;
00066 }
00067 
00068 static TaggedString *newone(const char *buff, int32 tag, uint32 h) {
00069     TaggedString *ts;
00070     if (tag == LUA_T_STRING) {
00071         int l = strlen(buff);
00072         ts = (TaggedString *)luaM_malloc(sizeof(TaggedString) + l);
00073         strcpy(ts->str, buff);
00074         ts->globalval.ttype = LUA_T_NIL;  /* initialize global value */
00075         ts->constindex = 0;
00076         nblocks += gcsizestring(l);
00077     } else {
00078         ts = (TaggedString *)luaM_malloc(sizeof(TaggedString));
00079         ts->globalval.value.ts = (TaggedString *)const_cast<char *>(buff);
00080         ts->globalval.ttype = (lua_Type)(tag == LUA_ANYTAG ? 0 : tag);
00081         ts->constindex = -1;  /* tag -> this is a userdata */
00082         nblocks++;
00083     }
00084     ts->head.marked = 0;
00085     ts->head.next = (GCnode *)ts;  // signal it is in no list
00086     ts->hash = h;
00087     return ts;
00088 }
00089 
00090 static TaggedString *insert(const char *buff, int32 tag, stringtable *tb) {
00091     TaggedString *ts;
00092     uint32 h = hash(buff, tag);
00093     int32 size = tb->size;
00094     int32 i;
00095     int32 j = -1;
00096     if (tb->nuse * 3 >= size * 2) {
00097         grow(tb);
00098         size = tb->size;
00099     }
00100     for (i = h % size; (ts = tb->hash[i]) != nullptr; ) {
00101         if (ts == &EMPTY)
00102             j = i;
00103         else if ((ts->constindex >= 0) ? // is a string?
00104                 (tag == LUA_T_STRING && (strcmp(buff, ts->str) == 0)) :
00105                 ((tag == ts->globalval.ttype || tag == LUA_ANYTAG) && buff == (const char *)ts->globalval.value.ts))
00106             return ts;
00107         if (++i == size)
00108             i = 0;
00109     }
00110     // not found
00111     if (j != -1)  // is there an EMPTY space?
00112         i = j;
00113     else
00114         tb->nuse++;
00115     ts = tb->hash[i] = newone(buff, tag, h);
00116     return ts;
00117 }
00118 
00119 TaggedString *luaS_createudata(void *udata, int32 tag) {
00120     return insert((char *)udata, tag, &string_root[(uintptr)udata % NUM_HASHS]);
00121 }
00122 
00123 TaggedString *luaS_new(const char *str) {
00124     return insert(str, LUA_T_STRING, &string_root[(uintptr)str[0] % NUM_HASHS]);
00125 }
00126 
00127 TaggedString *luaS_newfixedstring(const char *str) {
00128     TaggedString *ts = luaS_new(str);
00129     if (ts->head.marked == 0)
00130         ts->head.marked = 2;  // avoid GC
00131     return ts;
00132 }
00133 
00134 void luaS_free(TaggedString *l) {
00135     while (l) {
00136         TaggedString *next = (TaggedString *)l->head.next;
00137         nblocks -= (l->constindex == -1) ? 1 : gcsizestring(strlen(l->str));
00138         luaM_free(l);
00139         l = next;
00140     }
00141 }
00142 
00143 /*
00144 ** Garbage collection functions.
00145 */
00146 
00147 static void remove_from_list(GCnode *l) {
00148     while (l) {
00149         GCnode *next = l->next;
00150         while (next && !next->marked)
00151             next = l->next = next->next;
00152         l = next;
00153     }
00154 }
00155 
00156 TaggedString *luaS_collector() {
00157     TaggedString *frees = nullptr;
00158     int32 i;
00159     remove_from_list(&rootglobal);
00160     for (i = 0; i < NUM_HASHS; i++) {
00161         stringtable *tb = &string_root[i];
00162         int32 j;
00163         for (j = 0; j < tb->size; j++) {
00164             TaggedString *t = tb->hash[j];
00165             if (!t)
00166                 continue;
00167             if (t->head.marked == 1)
00168                 t->head.marked = 0;
00169             else if (!t->head.marked) {
00170                 t->head.next = (GCnode *)frees;
00171                 frees = t;
00172                 tb->hash[j] = &EMPTY;
00173             }
00174         }
00175     }
00176     return frees;
00177 }
00178 
00179 TaggedString *luaS_collectudata() {
00180     TaggedString *frees = nullptr;
00181     int32 i;
00182     rootglobal.next = nullptr;  // empty list of globals
00183     for (i = 0; i < NUM_HASHS; i++) {
00184         stringtable *tb = &string_root[i];
00185         int32 j;
00186         for (j = 0; j < tb->size; j++) {
00187             TaggedString *t = tb->hash[j];
00188             if (!t || t == &EMPTY || t->constindex != -1)
00189                 continue;  // get only user data
00190             t->head.next = (GCnode *)frees;
00191             frees = t;
00192             tb->hash[j] = &EMPTY;
00193         }
00194     }
00195     return frees;
00196 }
00197 
00198 void luaS_freeall() {
00199     int32 i;
00200     for (i = 0; i < NUM_HASHS; i++) {
00201         stringtable *tb = &string_root[i];
00202         int32 j;
00203         for (j = 0; j < tb->size; j++) {
00204             TaggedString *t = tb->hash[j];
00205             if (t == &EMPTY)
00206                 continue;
00207             luaM_free(t);
00208         }
00209         luaM_free(tb->hash);
00210     }
00211     luaM_free(string_root);
00212 }
00213 
00214 void luaS_rawsetglobal(TaggedString *ts, TObject *newval) {
00215     ts->globalval = *newval;
00216     if (ts->head.next == (GCnode *)ts) {  // is not in list?
00217         ts->head.next = rootglobal.next;
00218         rootglobal.next = (GCnode *)ts;
00219     }
00220 }
00221 
00222 char *luaS_travsymbol (int32 (*fn)(TObject *)) {
00223     TaggedString *g;
00224     for (g = (TaggedString *)rootglobal.next; g; g = (TaggedString *)g->head.next)
00225         if (fn(&g->globalval))
00226             return g->str;
00227     return nullptr;
00228 }
00229 
00230 int32 luaS_globaldefined(const char *name) {
00231     TaggedString *ts = luaS_new(name);
00232     return ts->globalval.ttype != LUA_T_NIL;
00233 }
00234 
00235 } // end of namespace Grim


Generated on Sat Feb 16 2019 05:00:56 for ResidualVM by doxygen 1.7.1
curved edge   curved edge