Use ArrayElement for sfall array

This commit is contained in:
Vasilii Rogin 2023-05-14 21:54:41 +03:00
parent 7faccc9923
commit b3fb03d047
5 changed files with 162 additions and 115 deletions

View File

@ -3331,44 +3331,4 @@ int ProgramValue::asInt() const
} }
} }
bool ProgramValue::operator<(ProgramValue const& other) const
{
if (opcode != other.opcode) {
return opcode < other.opcode;
}
switch (opcode) {
case VALUE_TYPE_INT:
case VALUE_TYPE_STRING:
case VALUE_TYPE_DYNAMIC_STRING:
return integerValue < other.integerValue;
case VALUE_TYPE_PTR:
return pointerValue < other.pointerValue;
case VALUE_TYPE_FLOAT:
return floatValue < other.floatValue;
default:
throw(std::exception());
}
}
bool ProgramValue::operator==(ProgramValue const& other) const
{
if (opcode != other.opcode) {
return false;
}
switch (opcode) {
case VALUE_TYPE_INT:
case VALUE_TYPE_STRING:
case VALUE_TYPE_DYNAMIC_STRING:
return integerValue == other.integerValue;
case VALUE_TYPE_PTR:
return pointerValue == other.pointerValue;
case VALUE_TYPE_FLOAT:
return floatValue == other.floatValue;
default:
throw(std::exception());
}
}
} // namespace fallout } // namespace fallout

View File

@ -161,9 +161,6 @@ public:
float asFloat() const; float asFloat() const;
bool isPointer() const; bool isPointer() const;
int asInt() const; int asInt() const;
bool operator<(ProgramValue const& other) const;
bool operator==(ProgramValue const& other) const;
}; };
typedef std::vector<ProgramValue> ProgramStack; typedef std::vector<ProgramValue> ProgramStack;

View File

@ -24,6 +24,7 @@ static ArrayId stackArrayId = 0;
#define ARRAY_ACTION_REVERSE (-4) #define ARRAY_ACTION_REVERSE (-4)
#define ARRAY_ACTION_SHUFFLE (-5) #define ARRAY_ACTION_SHUFFLE (-5)
// TODO: Move me into separate file "sfall_arrays_utils"
template <class T, typename Compare> template <class T, typename Compare>
static void ListSort(std::vector<T>& arr, int type, Compare cmp) static void ListSort(std::vector<T>& arr, int type, Compare cmp)
{ {
@ -45,25 +46,126 @@ static void ListSort(std::vector<T>& arr, int type, Compare cmp)
} }
} }
enum class ArrayElementType {
INT,
FLOAT,
STRING,
POINTER
};
class ArrayElement {
private:
ArrayElementType type;
union {
int integerValue;
float floatValue;
unsigned char* stringValue;
void* pointerValue;
};
public:
ArrayElement() {
// todo
};
// TODO: Remove all other constructors
ArrayElement(ProgramValue programValue, Program* program)
{
// todo
}
ProgramValue toValue(Program* program) const
{
// todo
return ProgramValue(0);
}
bool operator<(ArrayElement const& other) const
{
// todo
return false;
}
bool operator==(ArrayElement const& other) const
{
// todo
/*
if (!a.isString()) {
return a == b;
};
if (!b.isString()) {
return false;
};
auto str1 = programGetString(program, a.opcode, a.integerValue);
auto str2 = programGetString(program, a.opcode, a.integerValue);
if (!str1 || !str2) {
return false;
};
return strcmp(str1, str2) == 0;
*/
return false;
}
};
class SFallArray { class SFallArray {
protected: protected:
uint32_t mFlags; uint32_t mFlags;
public: public:
virtual int size() = 0; virtual int size() = 0;
virtual ProgramValue GetArrayKey(int index) = 0; virtual ProgramValue GetArrayKey(int index, Program* program) = 0;
virtual ProgramValue GetArray(const ProgramValue& key) = 0; virtual ProgramValue GetArray(const ProgramValue& key, Program* program) = 0;
virtual void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset) = 0; virtual void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program) = 0;
virtual void ResizeArray(int newLen) = 0; virtual void ResizeArray(int newLen) = 0;
virtual ProgramValue ScanArray(const ProgramValue& value, ValueCompareStrings& cmp) = 0; virtual ProgramValue ScanArray(const ProgramValue& value, Program* program) = 0;
virtual ~SFallArray() = default; virtual ~SFallArray() = default;
}; };
/*
bool ProgramValue::operator<(ProgramValue const& other) const
{
if (opcode != other.opcode) {
return opcode < other.opcode;
}
switch (opcode) {
case VALUE_TYPE_INT:
case VALUE_TYPE_STRING:
case VALUE_TYPE_DYNAMIC_STRING:
return integerValue < other.integerValue;
case VALUE_TYPE_PTR:
return pointerValue < other.pointerValue;
case VALUE_TYPE_FLOAT:
return floatValue < other.floatValue;
default:
throw(std::exception());
}
}
bool ProgramValue::operator==(ProgramValue const& other) const
{
if (opcode != other.opcode) {
return false;
}
switch (opcode) {
case VALUE_TYPE_INT:
case VALUE_TYPE_STRING:
case VALUE_TYPE_DYNAMIC_STRING:
return integerValue == other.integerValue;
case VALUE_TYPE_PTR:
return pointerValue == other.pointerValue;
case VALUE_TYPE_FLOAT:
return floatValue == other.floatValue;
default:
throw(std::exception());
}
}
*/
class SFallArrayList : public SFallArray { class SFallArrayList : public SFallArray {
private: private:
// TODO: SFall copies strings std::vector<ArrayElement> values;
std::vector<ProgramValue> values;
public: public:
SFallArrayList() = delete; SFallArrayList() = delete;
@ -79,7 +181,7 @@ public:
return values.size(); return values.size();
} }
ProgramValue GetArrayKey(int index) ProgramValue GetArrayKey(int index, Program* program)
{ {
if (index < -1 || index > size()) { if (index < -1 || index > size()) {
return ProgramValue(0); return ProgramValue(0);
@ -90,21 +192,21 @@ public:
return ProgramValue(index); return ProgramValue(index);
} }
ProgramValue GetArray(const ProgramValue& key) ProgramValue GetArray(const ProgramValue& key, Program* program)
{ {
auto element_index = key.asInt(); auto element_index = key.asInt();
if (element_index < 0 || element_index >= size()) { if (element_index < 0 || element_index >= size()) {
return ProgramValue(0); return ProgramValue(0);
}; };
return values[element_index]; return values[element_index].toValue(program);
} }
void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset) void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program)
{ {
if (key.isInt()) { if (key.isInt()) {
auto index = key.asInt(); auto index = key.asInt();
if (index >= 0 && index < size()) { if (index >= 0 && index < size()) {
values[index] = key; values[index] = ArrayElement { key, program };
} }
} }
} }
@ -119,21 +221,22 @@ public:
} else if (newLen > 0) { } else if (newLen > 0) {
if (newLen > ARRAY_MAX_SIZE) newLen = ARRAY_MAX_SIZE; // safety if (newLen > ARRAY_MAX_SIZE) newLen = ARRAY_MAX_SIZE; // safety
std::vector<ProgramValue> newValues; std::vector<ArrayElement> newValues;
newValues.reserve(newLen); newValues.reserve(newLen);
for (size_t i = 0; i < std::min(newLen, size()); i++) { for (size_t i = 0; i < std::min(newLen, size()); i++) {
newValues.push_back(values[i]); newValues.push_back(values[i]);
}; };
values = newValues; values = newValues;
} else if (newLen >= ARRAY_ACTION_SHUFFLE) { } else if (newLen >= ARRAY_ACTION_SHUFFLE) {
ListSort(values, newLen, std::less<ProgramValue>()); ListSort(values, newLen, std::less<ArrayElement>());
} }
} }
ProgramValue ScanArray(const ProgramValue& value, ValueCompareStrings& cmp) ProgramValue ScanArray(const ProgramValue& value, Program* program)
{ {
auto arrValue = ArrayElement { value, program };
for (size_t i = 0; i < size(); i++) { for (size_t i = 0; i < size(); i++) {
if (cmp(value, values[i])) { if (arrValue == values[i]) {
return ProgramValue(i); return ProgramValue(i);
} }
} }
@ -144,8 +247,8 @@ public:
class SFallArrayAssoc : public SFallArray { class SFallArrayAssoc : public SFallArray {
private: private:
// TODO: SFall copies strings // TODO: SFall copies strings
std::vector<ProgramValue> keys; std::vector<ArrayElement> keys;
std::map<ProgramValue, ProgramValue> map; std::map<ArrayElement, ArrayElement> map;
void MapSort(int newLen); void MapSort(int newLen);
@ -162,7 +265,7 @@ public:
return keys.size(); return keys.size();
} }
ProgramValue GetArrayKey(int index) ProgramValue GetArrayKey(int index, Program* program)
{ {
if (index < -1 || index > size()) { if (index < -1 || index > size()) {
return ProgramValue(0); return ProgramValue(0);
@ -171,22 +274,24 @@ public:
return ProgramValue(1); return ProgramValue(1);
}; };
return keys[index]; return keys[index].toValue(program);
} }
ProgramValue GetArray(const ProgramValue& key) ProgramValue GetArray(const ProgramValue& key, Program* program)
{ {
auto iter = map.find(key); auto iter = map.find(ArrayElement { key, program });
if (iter == map.end()) { if (iter == map.end()) {
return ProgramValue(0); return ProgramValue(0);
}; };
return iter->second; return iter->second.toValue(program);
} }
void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset) void SetArray(const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program)
{ {
auto iter = map.find(key); auto keyEl = ArrayElement { key, program };
auto iter = map.find(keyEl);
bool lookupMap = (mFlags & SFALL_ARRAYFLAG_CONSTVAL) != 0; bool lookupMap = (mFlags & SFALL_ARRAYFLAG_CONSTVAL) != 0;
@ -199,10 +304,10 @@ public:
// after assigning zero to a key, no need to store it, because "get_array" returns 0 for non-existent keys: try unset // after assigning zero to a key, no need to store it, because "get_array" returns 0 for non-existent keys: try unset
if (iter != map.end()) { if (iter != map.end()) {
map.erase(iter); map.erase(iter);
std::vector<ProgramValue> newKeys; std::vector<ArrayElement> newKeys;
newKeys.reserve(keys.size() - 1); newKeys.reserve(keys.size() - 1);
for (auto keyCandidate : keys) { for (auto keyCandidate : keys) {
if (keyCandidate == key) { if (keyCandidate == keyEl) {
// skip this key // skip this key
} else { } else {
newKeys.push_back(keyCandidate); newKeys.push_back(keyCandidate);
@ -215,8 +320,8 @@ public:
// size check // size check
if (size() >= ARRAY_MAX_SIZE) return; if (size() >= ARRAY_MAX_SIZE) return;
keys.push_back(key); keys.push_back(keyEl);
map[key] = val; map[keyEl] = ArrayElement { val, program };
} }
} }
} }
@ -228,7 +333,7 @@ public:
// only allow to reduce number of elements (adding range of elements is meaningless for maps) // only allow to reduce number of elements (adding range of elements is meaningless for maps)
if (newLen >= 0 && newLen < size()) { if (newLen >= 0 && newLen < size()) {
std::vector<ProgramValue> newKeys; std::vector<ArrayElement> newKeys;
newKeys.reserve(newLen); newKeys.reserve(newLen);
for (size_t i = 0; i < newLen; i++) { for (size_t i = 0; i < newLen; i++) {
@ -245,11 +350,12 @@ public:
} }
}; };
ProgramValue ScanArray(const ProgramValue& value, ValueCompareStrings& cmp) ProgramValue ScanArray(const ProgramValue& value, Program* program)
{ {
for (const auto &pair : map) { auto valueEl = ArrayElement { value, program };
if (cmp(pair.second, value)) { for (const auto& pair : map) {
return pair.first; if (valueEl == pair.second) {
return pair.first.toValue(program);
} }
} }
return ProgramValue(-1); return ProgramValue(-1);
@ -265,11 +371,11 @@ void SFallArrayAssoc::MapSort(int type)
} }
if (sortByValue) { if (sortByValue) {
ListSort(keys, type, [this](const ProgramValue& a, const ProgramValue& b) -> bool { ListSort(keys, type, [this](const ArrayElement& a, const ArrayElement& b) -> bool {
return this->map[a] < this->map[b]; return this->map[a] < this->map[b];
}); });
} else { } else {
ListSort(keys, type, std::less<ProgramValue>()); ListSort(keys, type, std::less<ArrayElement>());
} }
} }
@ -316,13 +422,13 @@ SFallArray* get_array_by_id(ArrayId array_id)
} }
} }
ProgramValue GetArrayKey(ArrayId array_id, int index) ProgramValue GetArrayKey(ArrayId array_id, int index, Program* program)
{ {
auto arr = get_array_by_id(array_id); auto arr = get_array_by_id(array_id);
if (!arr) { if (!arr) {
return ProgramValue(0); return ProgramValue(0);
}; };
return arr->GetArrayKey(index); return arr->GetArrayKey(index, program);
} }
int LenArray(ArrayId array_id) int LenArray(ArrayId array_id)
@ -335,7 +441,7 @@ int LenArray(ArrayId array_id)
return arr->size(); return arr->size();
} }
ProgramValue GetArray(ArrayId array_id, const ProgramValue& key) ProgramValue GetArray(ArrayId array_id, const ProgramValue& key, Program* program)
{ {
auto arr = get_array_by_id(array_id); auto arr = get_array_by_id(array_id);
@ -343,17 +449,17 @@ ProgramValue GetArray(ArrayId array_id, const ProgramValue& key)
return ProgramValue(0); return ProgramValue(0);
}; };
return arr->GetArray(key); return arr->GetArray(key, program);
} }
void SetArray(ArrayId array_id, const ProgramValue& key, const ProgramValue& val, bool allowUnset) void SetArray(ArrayId array_id, const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program)
{ {
auto arr = get_array_by_id(array_id); auto arr = get_array_by_id(array_id);
if (!arr) { if (!arr) {
return; return;
} }
arr->SetArray(key, val, allowUnset); arr->SetArray(key, val, allowUnset, program);
} }
void FreeArray(ArrayId array_id) void FreeArray(ArrayId array_id)
@ -392,7 +498,7 @@ void ResizeArray(ArrayId array_id, int newLen)
arr->ResizeArray(newLen); arr->ResizeArray(newLen);
} }
int StackArray(const ProgramValue& key, const ProgramValue& val) int StackArray(const ProgramValue& key, const ProgramValue& val, Program* program)
{ {
if (stackArrayId == 0) { if (stackArrayId == 0) {
return 0; return 0;
@ -407,18 +513,18 @@ int StackArray(const ProgramValue& key, const ProgramValue& val)
if (size >= ARRAY_MAX_SIZE) return 0; if (size >= ARRAY_MAX_SIZE) return 0;
if (key.asInt() >= size) arr->ResizeArray(size + 1); if (key.asInt() >= size) arr->ResizeArray(size + 1);
SetArray(stackArrayId, key, val, false); SetArray(stackArrayId, key, val, false, program);
return 0; return 0;
} }
ProgramValue ScanArray(ArrayId array_id, const ProgramValue& val, ValueCompareStrings& cmp) ProgramValue ScanArray(ArrayId array_id, const ProgramValue& val, Program* program)
{ {
auto arr = get_array_by_id(array_id); auto arr = get_array_by_id(array_id);
if (!arr) { if (!arr) {
return ProgramValue(-1); return ProgramValue(-1);
}; };
return arr->ScanArray(val, cmp); return arr->ScanArray(val, program);
} }
} }

View File

@ -3,7 +3,6 @@
#include "interpreter.h" #include "interpreter.h"
#include "object.h" #include "object.h"
#include <functional>
#include <cstdint> #include <cstdint>
namespace fallout { namespace fallout {
@ -14,21 +13,19 @@ namespace fallout {
using ArrayId = unsigned int; using ArrayId = unsigned int;
using ValueCompareStrings = const std::function<bool(const ProgramValue&, const ProgramValue&)>;
ArrayId CreateArray(int len, uint32_t flags); ArrayId CreateArray(int len, uint32_t flags);
ArrayId CreateTempArray(int len, uint32_t flags); ArrayId CreateTempArray(int len, uint32_t flags);
ProgramValue GetArrayKey(ArrayId array_id, int index); ProgramValue GetArrayKey(ArrayId array_id, int index, Program* program);
int LenArray(ArrayId array_id); int LenArray(ArrayId array_id);
ProgramValue GetArray(ArrayId array_id, const ProgramValue& key); ProgramValue GetArray(ArrayId array_id, const ProgramValue& key, Program* program);
void SetArray(ArrayId array_id, const ProgramValue& key, const ProgramValue& val, bool allowUnset); void SetArray(ArrayId array_id, const ProgramValue& key, const ProgramValue& val, bool allowUnset, Program* program);
void FreeArray(ArrayId array_id); void FreeArray(ArrayId array_id);
void FixArray(ArrayId id); void FixArray(ArrayId id);
void ResizeArray(ArrayId array_id, int newLen); void ResizeArray(ArrayId array_id, int newLen);
void DeleteAllTempArrays(); void DeleteAllTempArrays();
void sfallArraysReset(); void sfallArraysReset();
int StackArray(const ProgramValue& key, const ProgramValue& val); int StackArray(const ProgramValue& key, const ProgramValue& val, Program* program);
ProgramValue ScanArray(ArrayId array_id, const ProgramValue& val, ValueCompareStrings& cmp); ProgramValue ScanArray(ArrayId array_id, const ProgramValue& val, Program* program);
} }
#endif /* SFALL_ARRAYS */ #endif /* SFALL_ARRAYS */

View File

@ -494,7 +494,7 @@ static void opGetArrayKey(Program* program)
{ {
auto index = programStackPopInteger(program); auto index = programStackPopInteger(program);
auto arrayId = programStackPopInteger(program); auto arrayId = programStackPopInteger(program);
auto value = GetArrayKey(arrayId, index); auto value = GetArrayKey(arrayId, index, program);
programStackPushValue(program, value); programStackPushValue(program, value);
} }
@ -530,7 +530,7 @@ static void opSetArray(Program* program)
auto key = programStackPopValue(program); auto key = programStackPopValue(program);
auto arrayId = programStackPopInteger(program); auto arrayId = programStackPopInteger(program);
SetArray(arrayId, key, value, true); SetArray(arrayId, key, value, true, program);
} }
// arrayexpr // arrayexpr
@ -538,7 +538,7 @@ static void opStackArray(Program* program)
{ {
auto value = programStackPopValue(program); auto value = programStackPopValue(program);
auto key = programStackPopValue(program); auto key = programStackPopValue(program);
auto returnValue = StackArray(key, value); auto returnValue = StackArray(key, value, program);
programStackPushInteger(program, returnValue); programStackPushInteger(program, returnValue);
} }
@ -548,20 +548,7 @@ static void opScanArray(Program* program)
auto value = programStackPopValue(program); auto value = programStackPopValue(program);
auto arrayId = programStackPopInteger(program); auto arrayId = programStackPopInteger(program);
auto returnValue = ScanArray(arrayId, value, [&program](const ProgramValue& a, const ProgramValue& b) -> bool { auto returnValue = ScanArray(arrayId, value, program);
if (!a.isString()) {
return a == b;
};
if (!b.isString()) {
return false;
};
auto str1 = programGetString(program, a.opcode, a.integerValue);
auto str2 = programGetString(program, a.opcode, a.integerValue);
if (!str1 || !str2) {
return false;
};
return strcmp(str1, str2) == 0;
});
programStackPushValue(program, returnValue); programStackPushValue(program, returnValue);
} }
@ -572,7 +559,7 @@ static void opGetArray(Program* program)
auto arrayId = programStackPopValue(program); auto arrayId = programStackPopValue(program);
if (arrayId.isInt()) { if (arrayId.isInt()) {
auto value = GetArray(arrayId.integerValue, key); auto value = GetArray(arrayId.integerValue, key, program);
programStackPushValue(program, value); programStackPushValue(program, value);
} else if (arrayId.isString() && key.isInt()) { } else if (arrayId.isString() && key.isInt()) {
@ -621,7 +608,7 @@ static void opPartyMemberList(Program* program)
auto objects = get_all_party_members_objects(includeHidden); auto objects = get_all_party_members_objects(includeHidden);
auto array_id = CreateTempArray(objects.size(), SFALL_ARRAYFLAG_RESERVED); auto array_id = CreateTempArray(objects.size(), SFALL_ARRAYFLAG_RESERVED);
for (int i = 0; i < LenArray(array_id); i++) { for (int i = 0; i < LenArray(array_id); i++) {
SetArray(array_id, ProgramValue { i }, ProgramValue { objects[i] }, false); SetArray(array_id, ProgramValue { i }, ProgramValue { objects[i] }, false, program);
} }
programStackPushInteger(program, array_id); programStackPushInteger(program, array_id);
} }