diff --git a/src/d_think.h b/src/d_think.h index 12d44a8a202af5aeca9f7f58a18c5efc9f3242e1..a7924105664224ad8b13b774f7934e950695ecff 100644 --- a/src/d_think.h +++ b/src/d_think.h @@ -35,6 +35,7 @@ typedef struct { unsigned length; char *chars; + UINT32 hash; } action_string_t; typedef struct @@ -44,7 +45,7 @@ typedef struct { INT32 v_integer; boolean v_bool; - action_string_t v_string; + UINT32 v_string_id; }; } action_val_t; @@ -56,11 +57,11 @@ typedef struct #define ACTION_NULL_VAL (action_val_t){ .type = ACTION_VAL_NULL } #define ACTION_INTEGER_VAL(val) (action_val_t){ .type = ACTION_VAL_INTEGER, .v_integer = (val) } #define ACTION_BOOLEAN_VAL(val) (action_val_t){ .type = ACTION_VAL_BOOLEAN, .v_bool = (val) } -#define ACTION_STRING_VAL(val) (action_val_t){ .type = ACTION_VAL_STRING, .v_string = (val) } +#define ACTION_STRING_VAL(val) (action_val_t){ .type = ACTION_VAL_STRING, .v_string_id = (val) } #define ACTION_VAL_AS_INTEGER(val) ((val).v_integer) #define ACTION_VAL_AS_BOOLEAN(val) ((val).v_bool) -#define ACTION_VAL_AS_STRING(val) ((val).v_string) +#define ACTION_VAL_AS_STRING(val) ((val).v_string_id) // // Experimental stuff. diff --git a/src/deh_lua.c b/src/deh_lua.c index 257d8ae0ad5a131a01ac747c0389712211ba1d79..6e6cacf312cd2a9cc4a669e029a63a1570091f2f 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -203,8 +203,6 @@ static int action_call(lua_State *L) { if (!LUA_ValueIsValidActionVal(L, i)) { - for (int k = 0; k < j; k++) - Action_FreeValue(call_args[k]); Z_Free(call_args); return luaL_error(L, va("value of type %s cannot be passed to an action", luaL_typename(L, i))); } @@ -215,9 +213,6 @@ static int action_call(lua_State *L) action->acpscr(actor, call_args, num_action_args); - for (int i = 0; i < num_action_args; i++) - Action_FreeValue(call_args[i]); - Z_Free(call_args); return 0; diff --git a/src/deh_soc.c b/src/deh_soc.c index 877b1c43886889b7836e923a56c2d68cd7f85631..9b8d7cc5dd65f7ceadf2accd270c57fdef3fe64e 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -86,17 +86,17 @@ static boolean check_string_token(char *word) return true; } -static boolean parse_string_token(action_string_t *string, char *word) +static boolean parse_string_token(char **string_chars, unsigned *string_length, char *word) { int token_length = strlen(word); int length = token_length - 2; if (length <= 0) return false; - string->chars = Z_Calloc(length + 1, PU_STATIC, NULL); - string->length = 0; + *string_chars = Z_Calloc(length + 1, PU_STATIC, NULL); + *string_length = 0; - char *chars = string->chars; + char *chars = *string_chars; char *str = word + 1; char *str_end = word + token_length - 1; @@ -116,7 +116,7 @@ static boolean parse_string_token(action_string_t *string, char *word) *chars = '\\'; else { - Z_Free(string->chars); + Z_Free(*string_chars); deh_warning("Invalid escape character in string token"); return false; } @@ -124,7 +124,7 @@ static boolean parse_string_token(action_string_t *string, char *word) else *chars = *str; - string->length++; + (*string_length)++; chars++; str++; } @@ -142,15 +142,18 @@ static boolean parse_word(action_val_t *value, char *word) return false; } - action_string_t string; + char *string_chars = NULL; + unsigned string_length = 0; - if (!parse_string_token(&string, word)) + if (!parse_string_token(&string_chars, &string_length, word)) { *value = ACTION_NULL_VAL; return false; } - *value = ACTION_STRING_VAL(string); + *value = ACTION_STRING_VAL(Action_AddString(string_chars, string_length)); + + Z_Free(string_chars); } else if (fastcmp(word, "true")) { @@ -2905,7 +2908,6 @@ void readframe(MYFILE *f, INT32 num) && word1[3] >= '1' && word1[3] <= '8') { unsigned varSlot = (word1[3] - 0x30) - 1; - Action_FreeValue(states[num].vars[varSlot]); parse_word(&states[num].vars[varSlot], word2); } else diff --git a/src/lua_infolib.c b/src/lua_infolib.c index 6eba2308c4e576dbef543cf1bac6fcc54b22dc78..2a273b823ce40eafa1cee6cb8fcee06b41890c00 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -67,9 +67,9 @@ void LUA_ValueToActionVal(lua_State *L, int i, action_val_t *val) break; case LUA_TSTRING: { - action_string_t stringval; - Action_MakeString(&stringval, Z_StrDup(lua_tostring(L, i))); - value = ACTION_STRING_VAL(stringval); + size_t string_length = 0; + const char *string = lua_tolstring(L, i, &string_length); + value = ACTION_STRING_VAL(Action_AddString(string, string_length)); break; } default: @@ -107,7 +107,6 @@ static boolean GetActionValuesFromTable(lua_State *L, action_val_t *vars, int n) } CHECK_ACTION_VAL_TYPE(n + 2); - Action_FreeValue(vars[i]); LUA_ValueToActionVal(L, n + 2, &vars[i]); lua_pop(L, 1); } @@ -716,7 +715,13 @@ static void PushActionValue(lua_State *L, action_val_t arg) else if (ACTION_VAL_IS_BOOLEAN(arg)) lua_pushboolean(L, ACTION_VAL_AS_BOOLEAN(arg)); else if (ACTION_VAL_IS_STRING(arg)) - lua_pushlstring(L, arg.v_string.chars, arg.v_string.length); + { + action_string_t *string = Action_GetString(ACTION_VAL_AS_STRING(arg)); + if (string) + lua_pushlstring(L, string->chars, string->length); + else + lua_pushnil(L); + } else if (ACTION_VAL_IS_NULL(arg)) lua_pushnil(L); } @@ -864,11 +869,9 @@ static int lib_setState(lua_State *L) } } else if (i == 5 || (str && fastcmp(str, "var1"))) { CHECK_ACTION_VAL_TYPE(3); - Action_FreeValue(state->vars[0]); LUA_ValueToActionVal(L, 3, &state->vars[0]); } else if (i == 6 || (str && fastcmp(str, "var2"))) { CHECK_ACTION_VAL_TYPE(3); - Action_FreeValue(state->vars[1]); LUA_ValueToActionVal(L, 3, &state->vars[1]); } else if (i == 7 || (str && fastcmp(str, "nextstate"))) { value = luaL_checkinteger(L, 3); @@ -1123,12 +1126,10 @@ static int state_set(lua_State *L) } } else if (fastcmp(field,"var1")) { CHECK_ACTION_VAL_TYPE(3); - Action_FreeValue(st->vars[0]); LUA_ValueToActionVal(L, 3, &st->vars[0]); } else if (fastcmp(field,"var2")) { CHECK_ACTION_VAL_TYPE(3); - Action_FreeValue(st->vars[1]); LUA_ValueToActionVal(L, 3, &st->vars[1]); } else if (fastcmp(field,"vars")) { @@ -1171,7 +1172,6 @@ static int statevars_set(lua_State *L) if (n <= 0 || n > MAX_ACTION_VARS) return luaL_error(L, LUA_QL("state_t") " field 'vars' index %d out of range (1 - %d)", n, MAX_ACTION_VARS); n--; - Action_FreeValue(vars[n]); LUA_ValueToActionVal(L, 3, &vars[n]); return 0; } diff --git a/src/p_action.c b/src/p_action.c index 637fdbb20e8576a81418a78f2e2cbea6e3e13432..1b8a9fbd8e77825e7603b92166d9c312858116c6 100644 --- a/src/p_action.c +++ b/src/p_action.c @@ -26,27 +26,60 @@ #include "lua_hook.h" #include "m_cond.h" // SECRET_SKIN -INT32 modulothing; +#if 0 +static void Action_FreeStringChars(action_string_t *str) +{ + Z_Free(str->chars); + str->chars = NULL; +} +#endif -// -// ACTION ROUTINES -// -void Action_FreeValue(action_val_t value) +static action_string_t *actionstrings = NULL; +static UINT32 numactionstrings = 0; + +UINT32 Action_FindMatchingString(const char *str, unsigned length) { - if (ACTION_VAL_IS_STRING(value)) - Action_FreeStringChars(&value.v_string); + UINT32 hash = quickncasehash(str, strlen(str)); + + for (UINT32 i = 0; i < numactionstrings; i++) + { + if (length == actionstrings[i].length + && hash == actionstrings[i].hash + && memcmp(str, actionstrings[i].chars, length) == 0) + return i; + } + + return ACTION_NO_STRING; } -void Action_MakeString(action_string_t *out, char *str) +UINT32 Action_AddString(const char *str, unsigned length) { - out->chars = str; - out->length = strlen(str); + UINT32 hash = quickncasehash(str, length); + + UINT32 id = Action_FindMatchingString(str, length); + if (id != ACTION_NO_STRING) + return id; + + id = numactionstrings++; + actionstrings = Z_Realloc(actionstrings, sizeof(action_string_t) * numactionstrings, PU_STATIC, NULL); + + action_string_t *astr = &actionstrings[id]; + astr->length = length; + astr->hash = hash; + + astr->chars = ZZ_Alloc(length + 1); + memcpy(astr->chars, str, length); + astr->chars[length] = '\0'; + + return id; } -void Action_FreeStringChars(action_string_t *str) +action_string_t *Action_GetString(UINT32 string_id) { - Z_Free(str->chars); - str->chars = NULL; + if (string_id >= numactionstrings) + return NULL; + + return &actionstrings[string_id]; } static const char *Action_GetTypeName(UINT8 type) @@ -92,9 +125,10 @@ INT32 Action_ValueToInteger(action_val_t value) char *Action_ValueToString(action_val_t value) { + size_t bufsize = 128; + if (ACTION_VAL_IS_INTEGER(value)) { - size_t bufsize = 128; char *buffer = Z_Malloc(bufsize, PU_STATIC, NULL); snprintf(buffer, bufsize, "<integer> %d", Action_ValueToInteger(value)); return buffer; @@ -102,7 +136,11 @@ char *Action_ValueToString(action_val_t value) else if (ACTION_VAL_IS_BOOLEAN(value)) return ACTION_VAL_AS_BOOLEAN(value) ? Z_StrDup("<boolean> true") : Z_StrDup("<boolean> false"); else if (ACTION_VAL_IS_STRING(value)) - return Z_StrDup("<string>"); + { + char *buffer = Z_Malloc(bufsize, PU_STATIC, NULL); + snprintf(buffer, bufsize, "<string> %d", ACTION_VAL_AS_STRING(value)); + return buffer; + } else if (ACTION_VAL_IS_NULL(value)) return Z_StrDup("<null>"); @@ -129,6 +167,12 @@ static INT32 GetInteger(action_val_t *args, unsigned argcount, unsigned argnum, #define LUA_CALL_ACTION(action) LUA_CallAction(action, actor, args, argcount) +// +// ACTION ROUTINES +// + +INT32 modulothing; + // Function: A_Look // // Description: Look for a player and set your target to them. diff --git a/src/p_action.h b/src/p_action.h index fcf95f7fdac8ac4f62e5e649efee319965387de1..49c5e298f6ed111404af5d60ba5e78ffe3dce6c7 100644 --- a/src/p_action.h +++ b/src/p_action.h @@ -16,14 +16,16 @@ #include "p_mobj.h" +#define ACTION_NO_STRING 0xFFFFFFFF + INT32 Action_ValueToInteger(action_val_t value); char *Action_ValueToString(action_val_t value); -void Action_FreeValue(action_val_t value); +UINT32 Action_FindMatchingString(const char *str, unsigned length); +UINT32 Action_AddString(const char *str, unsigned length); -void Action_MakeString(action_string_t *out, char *str); -void Action_FreeStringChars(action_string_t *str); +action_string_t *Action_GetString(UINT32 string_id); // IMPORTANT NOTE: If you add/remove from this list of action // functions, don't forget to update them in deh_tables.c!