From bb370250262011a5a791afd08b812a7e8626008d Mon Sep 17 00:00:00 2001 From: Vasilii Rogin Date: Sun, 23 Apr 2023 20:29:45 +0300 Subject: [PATCH] Add resizearray for assoc arrays --- src/sfall_arrays.cc | 91 ++++++++++++++++++++++++++++++++++++++++---- src/sfall_arrays.h | 1 + src/sfall_opcodes.cc | 11 ++++++ 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/sfall_arrays.cc b/src/sfall_arrays.cc index 0252352..d8b11a2 100644 --- a/src/sfall_arrays.cc +++ b/src/sfall_arrays.cc @@ -2,6 +2,7 @@ #include "interpreter.h" #include "sfall_script_value.h" +#include #include #include #include @@ -17,6 +18,31 @@ static ArrayId stackArrayId = 1; #define ARRAY_MAX_STRING (255) // maximum length of string to be stored as array key or value #define ARRAY_MAX_SIZE (100000) // maximum number of array elements, +// special actions for arrays using array_resize operator +#define ARRAY_ACTION_SORT (-2) +#define ARRAY_ACTION_RSORT (-3) +#define ARRAY_ACTION_REVERSE (-4) +#define ARRAY_ACTION_SHUFFLE (-5) + +template +static void ListSort(std::vector& arr, int type) +{ + switch (type) { + case ARRAY_ACTION_SORT: // sort ascending + std::sort(arr.begin(), arr.end()); + break; + case ARRAY_ACTION_RSORT: // sort descending + std::sort(arr.rbegin(), arr.rend()); + break; + case ARRAY_ACTION_REVERSE: // reverse elements + std::reverse(arr.rbegin(), arr.rend()); + break; + case ARRAY_ACTION_SHUFFLE: // shuffle elements + std::random_shuffle(arr.rbegin(), arr.rend()); + break; + } +} + class SFallArray { protected: uint32_t mFlags; @@ -26,6 +52,7 @@ public: virtual ProgramValue GetArrayKey(int index) = 0; virtual ProgramValue GetArray(const SFallScriptValue& key) = 0; virtual void SetArray(const SFallScriptValue& key, const SFallScriptValue& val, bool allowUnset) = 0; + virtual void ResizeArray(int newLen) = 0; }; class SFallArrayList : public SFallArray { @@ -71,9 +98,6 @@ public: void SetArray(const SFallScriptValue& key, const SFallScriptValue& val, bool allowUnset) { - - // TODO: assoc - if (key.isInt()) { auto index = key.asInt(); if (index >= 0 && index < size()) { @@ -81,6 +105,27 @@ public: } } } + + void ResizeArray(int newLen) + { + if (newLen == -1 || size() == newLen) { + return; + }; + if (newLen == 0) { + values.clear(); + } else if (newLen > 0) { + if (newLen > ARRAY_MAX_SIZE) newLen = ARRAY_MAX_SIZE; // safety + + std::vector newValues; + newValues.reserve(newLen); + for (size_t i = 0; i < std::min(newLen, size()); i++) { + newValues.push_back(values[i]); + }; + values = newValues; + } else if (newLen >= ARRAY_ACTION_SHUFFLE) { + ListSort(values, newLen); + } + } }; class SFallArrayAssoc : public SFallArray { @@ -160,9 +205,35 @@ public: } } } + void ResizeArray(int newLen) + { + if (newLen == -1 || size() == newLen) { + return; + }; + + // only allow to reduce number of elements (adding range of elements is meaningless for maps) + if (newLen >= 0 && newLen < size()) { + std::vector newKeys; + newKeys.reserve(newLen); + + for (size_t i = 0; i < newLen; i++) { + newKeys[i] = keys[i]; + }; + + for (size_t i = newLen; i < size(); i++) { + map.erase(keys[i]); + }; + keys = newKeys; + } else if (newLen < 0) { + if (newLen < (ARRAY_ACTION_SHUFFLE - 2)) return; + // TODO + // MapSort(arr, newlen); + } + }; }; -using ArraysMap = std::unordered_map>; +using ArraysMap + = std::unordered_map>; ArraysMap arrays; std::unordered_set temporaryArrays; @@ -215,15 +286,11 @@ int LenArray(ArrayId array_id) return -1; }; - // TODO: assoc - return arr->size(); } ProgramValue GetArray(ArrayId array_id, const SFallScriptValue& key) { - // TODO: If type is string then do substr - auto& arr = arrays[array_id]; if (!arr) { @@ -270,4 +337,12 @@ void sfallArraysReset() stackArrayId = 1; } +void ResizeArray(ArrayId array_id, int newLen) +{ + auto& arr = arrays[array_id]; + if (!arr) { + return; + }; + arr->ResizeArray(newLen); +} } \ No newline at end of file diff --git a/src/sfall_arrays.h b/src/sfall_arrays.h index 4817c65..edf5839 100644 --- a/src/sfall_arrays.h +++ b/src/sfall_arrays.h @@ -22,6 +22,7 @@ ProgramValue GetArray(ArrayId array_id, const SFallScriptValue& key); void SetArray(ArrayId array_id, const SFallScriptValue& key, const SFallScriptValue& val, bool allowUnset); void FreeArray(ArrayId array_id); void FixArray(ArrayId id); +void ResizeArray(ArrayId array_id, int newLen); void DeleteAllTempArrays(); void sfallArraysReset(); diff --git a/src/sfall_opcodes.cc b/src/sfall_opcodes.cc index 6d8cf59..73c2aee 100644 --- a/src/sfall_opcodes.cc +++ b/src/sfall_opcodes.cc @@ -536,6 +536,8 @@ static void opSetArray(Program* program) // get_array static void opGetArray(Program* program) { + // TODO: If type is string then do substr instead of array operation + auto key = programStackPopValue(program); auto arrayId = programStackPopInteger(program); auto value = GetArray(arrayId, SFallScriptValue { key }); @@ -556,6 +558,14 @@ static void opLenArray(Program* program) programStackPushInteger(program, LenArray(arrayId)); } +// resize_array +static void opResizeArray(Program* program) +{ + auto newLen = programStackPopInteger(program); + auto arrayId = programStackPopInteger(program); + ResizeArray(arrayId, newLen); +} + // party_member_list static void opPartyMemberList(Program* program) { @@ -707,6 +717,7 @@ void sfallOpcodesInit() interpreterRegisterOpcode(0x822F, opGetArray); interpreterRegisterOpcode(0x8230, opFreeArray); interpreterRegisterOpcode(0x8231, opLenArray); + interpreterRegisterOpcode(0x8232, opResizeArray); interpreterRegisterOpcode(0x8233, opTempArray); interpreterRegisterOpcode(0x8233, opFixArray); interpreterRegisterOpcode(0x8237, opParseInt);