mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Fixed a crash bug when using sorting functions on an associative array(map) (from Mr.Stalin)
Added support for sorting associative arrays by keys or values.
This commit is contained in:
@@ -129,14 +129,18 @@
|
||||
#define array_exists(array) (len_array(array) != -1)
|
||||
// remove all elements from array
|
||||
#define clear_array(array) resize_array(array, 0)
|
||||
// sort array in ascending order
|
||||
// sort array or map by key in ascending order
|
||||
#define sort_array(array) resize_array(array, -2)
|
||||
// sort array in descending order
|
||||
// sort array or map by key in descending order
|
||||
#define sort_array_reverse(array) resize_array(array, -3)
|
||||
// reverse elements in list
|
||||
// reverse elements in list/map
|
||||
#define reverse_array(array) resize_array(array, -4)
|
||||
// randomly shuffle elements in list
|
||||
// randomly shuffle elements in list/map
|
||||
#define shuffle_array(array) resize_array(array, -5)
|
||||
// sort map in ascending order by value
|
||||
#define sort_map_value(array) resize_array(array, -6)
|
||||
// sort map in descending order by value
|
||||
#define sort_map_value_desc(array) resize_array(array, -7)
|
||||
// remove element from map or just replace value with 0 for list
|
||||
#define unset_array(array, item) set_array(array, item, 0)
|
||||
// same as "key_pressed" but checks VK codes instead of DX codes
|
||||
|
||||
@@ -468,12 +468,66 @@ int _stdcall LenArray(DWORD id) {
|
||||
else return arrays[id].size();
|
||||
}
|
||||
|
||||
void _stdcall ResizeArray(DWORD id, int newlen) {
|
||||
if (arrays.find(id) == arrays.end() || arrays[id].size() == newlen) return;
|
||||
template <class T>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void MapSort(sArrayVar& arr, int type) {
|
||||
std::vector<std::pair<sArrayElement, sArrayElement>> map;
|
||||
bool sortByValue = false;
|
||||
if (type < ARRAY_ACTION_SHUFFLE) {
|
||||
type += 4;
|
||||
sortByValue = true;
|
||||
}
|
||||
|
||||
sArrayElement key, val;
|
||||
for (size_t i = 0; i < arr.val.size(); ++i) {
|
||||
if (sortByValue) {
|
||||
val = arr.val[i++]; // map key > value
|
||||
key = arr.val[i]; // map value > key
|
||||
} else {
|
||||
key = arr.val[i]; // key
|
||||
val = arr.val[++i]; // value
|
||||
}
|
||||
map.emplace_back(std::make_pair(key, val));
|
||||
}
|
||||
ListSort(map, type);
|
||||
|
||||
arr.val.clear();
|
||||
arr.keyHash.clear();
|
||||
for (size_t i = 0; i < map.size(); ++i) {
|
||||
auto el = arr.val.size();
|
||||
if (sortByValue) {
|
||||
arr.val.emplace_back(map[i].second); // map value > key
|
||||
arr.val.emplace_back(map[i].first); // map key > value
|
||||
} else {
|
||||
arr.val.emplace_back(map[i].first);
|
||||
arr.val.emplace_back(map[i].second);
|
||||
}
|
||||
arr.keyHash[arr.val[el]] = el;
|
||||
}
|
||||
}
|
||||
|
||||
long _stdcall ResizeArray(DWORD id, int newlen) {
|
||||
if (newlen == -1 || arrays.find(id) == arrays.end() || arrays[id].size() == newlen) return 0;
|
||||
sArrayVar &arr = arrays[id];
|
||||
if (arr.isAssoc()) {
|
||||
// only allow to reduce number of elements (adding range of elements is meaningless for maps)
|
||||
if (newlen < arrays[id].size()) {
|
||||
if (newlen >= 0 && newlen < arrays[id].size()) {
|
||||
ArrayKeysMap::iterator itHash;
|
||||
std::vector<sArrayElement>::iterator itVal;
|
||||
int actualLen = newlen * 2;
|
||||
@@ -483,8 +537,11 @@ void _stdcall ResizeArray(DWORD id, int newlen) {
|
||||
}
|
||||
arr.clearRange(actualLen);
|
||||
arr.val.resize(actualLen);
|
||||
} else if (newlen < 0) {
|
||||
if (newlen < (ARRAY_ACTION_SHUFFLE - 2)) return -1;
|
||||
MapSort(arr, newlen);
|
||||
}
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
if (newlen >= 0) { // actual resize
|
||||
if (newlen > ARRAY_MAX_SIZE) // safety
|
||||
@@ -493,21 +550,10 @@ void _stdcall ResizeArray(DWORD id, int newlen) {
|
||||
arr.clearRange(newlen);
|
||||
arr.val.resize(newlen);
|
||||
} else { // special functions for lists...
|
||||
switch (newlen) {
|
||||
case ARRAY_ACTION_SORT: // sort ascending
|
||||
std::sort(arr.val.begin(), arr.val.end());
|
||||
break;
|
||||
case ARRAY_ACTION_RSORT: // sort descending
|
||||
std::sort(arr.val.rbegin(), arr.val.rend());
|
||||
break;
|
||||
case ARRAY_ACTION_REVERSE: // reverse elements
|
||||
std::reverse(arr.val.rbegin(), arr.val.rend());
|
||||
break;
|
||||
case ARRAY_ACTION_SHUFFLE: // shuffle elements
|
||||
std::random_shuffle(arr.val.rbegin(), arr.val.rend());
|
||||
break;
|
||||
}
|
||||
if (newlen < ARRAY_ACTION_SHUFFLE) return -1;
|
||||
ListSort(arr.val, newlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _stdcall FixArray(DWORD id) {
|
||||
|
||||
@@ -103,6 +103,7 @@ public:
|
||||
bool isAssoc() const {
|
||||
return (flags & ARRAYFLAG_ASSOC);
|
||||
}
|
||||
|
||||
// logical array size (number of elements for normal arrays; number of key=>value pairs for associative)
|
||||
int size() const {
|
||||
return isAssoc()
|
||||
@@ -118,6 +119,7 @@ public:
|
||||
}
|
||||
|
||||
sArrayVar() : flags(0), key() {}
|
||||
|
||||
// free memory used by strings
|
||||
void clear() {
|
||||
clearRange(0);
|
||||
@@ -168,7 +170,7 @@ void _stdcall SetArray(DWORD id, const ScriptValue& key, const ScriptValue& val,
|
||||
// number of elements in list or pairs in map
|
||||
int _stdcall LenArray(DWORD id);
|
||||
// change array size (only works with list)
|
||||
void _stdcall ResizeArray(DWORD id, int newlen);
|
||||
long _stdcall ResizeArray(DWORD id, int newlen);
|
||||
// make temporary array persistent
|
||||
void _stdcall FixArray(DWORD id);
|
||||
// searches for a given element in array and returns it's index (for list) or key (for map) or int(-1) if not found
|
||||
|
||||
@@ -59,10 +59,10 @@ void sf_get_array(OpcodeContext& ctx) {
|
||||
auto str = Substring(ctx.arg(0).asString(), ctx.arg(1).asInt(), 1);
|
||||
ctx.setReturn(str);
|
||||
} else {
|
||||
ctx.printOpcodeError("get_array - index must be numeric when used on a string.");
|
||||
ctx.printOpcodeError("get_array() - index must be numeric when used on a string.");
|
||||
}
|
||||
} else {
|
||||
ctx.printOpcodeError("get-array - argument 0 must be an array ID or a string.");
|
||||
ctx.printOpcodeError("get_array() - argument 0 must be an array ID or a string.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,9 @@ void sf_len_array(OpcodeContext& ctx) {
|
||||
}
|
||||
|
||||
void sf_resize_array(OpcodeContext& ctx) {
|
||||
ResizeArray(ctx.arg(0).asInt(), ctx.arg(1).asInt());
|
||||
if (ResizeArray(ctx.arg(0).asInt(), ctx.arg(1).asInt())) {
|
||||
ctx.printOpcodeError("resize_array() - array sorting error.");
|
||||
}
|
||||
}
|
||||
|
||||
void sf_temp_array(OpcodeContext& ctx) {
|
||||
|
||||
Reference in New Issue
Block a user