summaryrefslogtreecommitdiff
path: root/src/lj_str.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_str.c')
-rw-r--r--src/lj_str.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/src/lj_str.c b/src/lj_str.c
index 4a9477dd..5ba55bdd 100644
--- a/src/lj_str.c
+++ b/src/lj_str.c
@@ -76,15 +76,29 @@ GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx)
76 GCstr *s; 76 GCstr *s;
77 GCobj *o; 77 GCobj *o;
78 MSize len = (MSize)lenx; 78 MSize len = (MSize)lenx;
79 MSize h = len; 79 MSize a, b, h = len;
80 MSize step = (len>>5)+1; /* Partial hash. */
81 MSize l1;
82 if (lenx >= LJ_MAX_STR) 80 if (lenx >= LJ_MAX_STR)
83 lj_err_msg(L, LJ_ERR_STROV); 81 lj_err_msg(L, LJ_ERR_STROV);
84 for (l1 = len; l1 >= step; l1 -= step) /* Compute string hash. */
85 h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1]));
86 /* Check if the string has already been interned. */
87 g = G(L); 82 g = G(L);
83 /* Compute string hash. Constants taken from lookup3 hash by Bob Jenkins. */
84 if (len >= 4) { /* Caveat: unaligned access! */
85 a = *(const uint32_t *)str;
86 h ^= *(const uint32_t *)(str+len-4);
87 b = *(const uint32_t *)(str+(len>>1)-2);
88 h ^= b; h -= lj_rol(b, 14);
89 b += *(const uint32_t *)(str+(len>>2)-1);
90 } else if (len > 0) {
91 a = *(const uint8_t *)str;
92 h ^= *(const uint8_t *)(str+len-1);
93 b = *(const uint8_t *)(str+(len>>1));
94 h ^= b; h -= lj_rol(b, 14);
95 } else {
96 return &g->strempty;
97 }
98 a ^= h; a -= lj_rol(h, 11);
99 b ^= a; b -= lj_rol(a, 25);
100 h ^= b; h -= lj_rol(b, 16);
101 /* Check if the string has already been interned. */
88 for (o = gcref(g->strhash[h & g->strmask]); o != NULL; o = gcnext(o)) { 102 for (o = gcref(g->strhash[h & g->strmask]); o != NULL; o = gcnext(o)) {
89 GCstr *tso = gco2str(o); 103 GCstr *tso = gco2str(o);
90 if (tso->len == len && (memcmp(str, strdata(tso), len) == 0)) { 104 if (tso->len == len && (memcmp(str, strdata(tso), len) == 0)) {