Add resizearray for assoc arrays

This commit is contained in:
Vasilii Rogin 2023-04-23 20:29:45 +03:00
parent 517deb57e6
commit bb37025026
3 changed files with 95 additions and 8 deletions

View File

@ -2,6 +2,7 @@
#include "interpreter.h"
#include "sfall_script_value.h"
#include <algorithm>
#include <cstdint>
#include <map>
#include <memory>
@ -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 <class T>
static void ListSort(std::vector<T>& 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<SFallScriptValue> 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<SFallScriptValue> 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<ArrayId, std::unique_ptr<SFallArray>>;
using ArraysMap
= std::unordered_map<ArrayId, std::unique_ptr<SFallArray>>;
ArraysMap arrays;
std::unordered_set<ArrayId> 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);
}
}

View File

@ -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();

View File

@ -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);