Add ArraySortEx/SortADTArray natives and new sort method Sort_Random (bug 5494, r=Nextra)

Former-commit-id: 1ff337d9801e2fbd9ad210bc1285d31679b3029e
This commit is contained in:
Vincent Herbet
2013-08-05 16:56:59 +02:00
parent 71ac17464a
commit 5a6d3fde61
7 changed files with 581 additions and 7 deletions

View File

@ -491,6 +491,10 @@ typedef struct ArraySort_s
int forward;
cell data;
cell size;
CellVector *vec;
AMX* amx;
cell addr1;
cell addr2;
} ArraySort_t;
@ -577,6 +581,135 @@ static cell AMX_NATIVE_CALL ArraySort(AMX* amx, cell* params)
}
int SortArrayListExCell(const void *itema, const void *itemb)
{
ArraySort_t *Info = ArraySortStack.front();
cell vala, valb;
Info->vec->GetCell(*((int *)itema), &vala);
Info->vec->GetCell(*((int *)itemb), &valb);
return executeForwards(Info->forward, Info->handle, vala, valb, Info->data, Info->size);
}
int SortArrayListExArray(const void *itema, const void *itemb)
{
ArraySort_t *Info = ArraySortStack.front();
Info->vec->GetArray(*((int *)itema), get_amxaddr(Info->amx, Info->addr1));
Info->vec->GetArray(*((int *)itemb), get_amxaddr(Info->amx, Info->addr2));
return executeForwards(Info->forward, Info->handle, Info->addr1, Info->addr2, Info->data, Info->size);
}
// native ArraySortEx(Array:array, const comparefunc[], data[]="", data_size=0);
static cell AMX_NATIVE_CALL ArraySortEx(AMX* amx, cell* params)
{
int handle=params[1];
CellVector* vec=HandleToVector(amx, handle);
if (!vec)
{
return 0;
}
cell amx_addr1, amx_addr2, *phys_addr = NULL;
size_t cellcount = vec->GetCellCount();
if (cellcount > 1)
{
int err;
if ((err=amx_Allot(amx, cellcount, &amx_addr1, &phys_addr)) != AMX_ERR_NONE
|| (err=amx_Allot(amx, cellcount, &amx_addr2, &phys_addr)) != AMX_ERR_NONE)
{
LogError(amx, err, "Ran out of memory");
return 0;
}
}
// This is kind of a cheating way to go about this but...
// Create an array of integers as big as however many elements are in the vector.
// Pass that array to qsort
// After the array is sorted out, then create a NEW cellvector
// and copy in the old data in the order of what was sorted
int len;
char* FuncName=get_amxstring(amx, params[2], 0, len);
// MySortFunc(Array:array, item1, item2, const data[], data_size)
int Forward = registerSPForwardByName(amx, FuncName, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
if (Forward < 0)
{
if (cellcount > 1)
{
amx_Release(amx, amx_addr1);
amx_Release(amx, amx_addr2);
}
LogError(amx, AMX_ERR_NATIVE, "The public function \"%s\" was not found.", FuncName);
return 0;
}
int *IntList=new int[vec->Size()];
for (int i=0; i< vec->Size(); i++)
{
IntList[i]=i;
}
ArraySort_t *Info=new ArraySort_t;
Info->handle=handle;
Info->forward=Forward;
Info->data=params[3];
Info->size=params[4];
Info->vec = vec;
Info->amx = amx;
Info->addr1 = amx_addr1;
Info->addr2 = amx_addr2;
ArraySortStack.push(Info);
qsort(IntList, vec->Size(), sizeof(int), cellcount > 1 ? SortArrayListExArray : SortArrayListExCell);
ArraySortStack.pop();
CellVector* newvec=new CellVector(vec->GetCellCount());
// Set the new vector's values
for (int i=0; i< vec->Size(); i++)
{
if (newvec->SetArray(newvec->Push(), vec->GetCellPointer(IntList[i]))!=1)
{
// This should never happen..
LogError(amx, AMX_ERR_NATIVE, "Failed to SetArray in ArraySort (i=%d, IntList=%d)",i,IntList[i]);
if (cellcount > 1)
{
amx_Release(amx, amx_addr1);
amx_Release(amx, amx_addr2);
}
return 0;
}
}
// Delete the old vector
delete vec;
// Now save the new vector in its handle location
VectorHolder[handle-1]=newvec;
// Cleanup
delete Info;
delete IntList;
unregisterSPForward(Forward);
if (cellcount > 1)
{
amx_Release(amx, amx_addr1);
amx_Release(amx, amx_addr2);
}
return 1;
}
AMX_NATIVE_INFO g_DataStructNatives[] =
{
@ -603,6 +736,7 @@ AMX_NATIVE_INFO g_DataStructNatives[] =
{ "ArrayGetStringHandle", ArrayGetStringHandle },
{ "ArrayDestroy", ArrayDestroy },
{ "ArraySort", ArraySort },
{ "ArraySortEx", ArraySortEx },
{ NULL, NULL }
};

View File

@ -203,6 +203,10 @@ public:
cursize=1;
count=0;
};
cell* Base()
{
return data;
}
cell* GetCellPointer(size_t which)
{
if (which >= count)

View File

@ -1,5 +1,7 @@
#include "amxmodx.h"
#include <stdlib.h>
#include <time.h>
#include "datastructs.h"
/***********************************
* About the double array hack *
@ -51,6 +53,7 @@ enum SortOrder
{
Sort_Ascending = 0,
Sort_Descending = 1,
Sort_Random = 2,
};
int sort_ints_asc(const void *int1, const void *int2)
@ -63,17 +66,40 @@ int sort_ints_desc(const void *int1, const void *int2)
return (*(int *)int2) - (*(int *)int1);
}
void sort_random(cell *array, cell size)
{
srand((unsigned int)time(NULL));
for (int i = size-1; i > 0; i--)
{
int n = rand() % (i + 1);
if (array[i] != array[n])
{
array[i] ^= array[n];
array[n] ^= array[i];
array[i] ^= array[n];
}
}
}
static cell AMX_NATIVE_CALL SortIntegers(AMX *amx, cell *params)
{
cell *array = get_amxaddr(amx, params[1]);
cell array_size = params[2];
cell type = params[3];
if (type == Sort_Ascending)
if (type == Sort_Ascending)
{
qsort(array, array_size, sizeof(cell), sort_ints_asc);
} else {
}
else if (type == Sort_Descending)
{
qsort(array, array_size, sizeof(cell), sort_ints_desc);
}
else
{
sort_random(array, array_size);
}
return 1;
@ -118,9 +144,15 @@ static cell AMX_NATIVE_CALL SortFloats(AMX *amx, cell *params)
if (type == Sort_Ascending)
{
qsort(array, array_size, sizeof(cell), sort_floats_asc);
} else {
}
else if (type == Sort_Descending)
{
qsort(array, array_size, sizeof(cell), sort_floats_desc);
}
else
{
sort_random(array, array_size);
}
return 1;
}
@ -193,9 +225,15 @@ static cell AMX_NATIVE_CALL SortStrings(AMX *amx, cell *params)
if (type == Sort_Ascending)
{
qsort(array, array_size, sizeof(cell), sort_strings_asc);
} else {
}
else if (type == Sort_Descending)
{
qsort(array, array_size, sizeof(cell), sort_strings_desc);
}
else
{
sort_random(array, array_size);
}
/* END HACKHACK - restore what we damaged so Pawn doesn't throw up.
* We'll browse through each index of the array and patch up the distance.
@ -348,6 +386,98 @@ static cell AMX_NATIVE_CALL SortCustom2D(AMX *amx, cell *params)
return 1;
}
enum SortType
{
Sort_Integer = 0,
Sort_Float,
Sort_String,
};
int sort_adtarray_strings_asc(const void *str1, const void *str2)
{
return strcmp((char *) str1, (char *) str2);
}
int sort_adtarray_strings_desc(const void *str1, const void *str2)
{
return strcmp((char *) str2, (char *) str1);
}
void sort_adt_random(CellVector *cArray)
{
size_t arraysize = cArray->Size();
srand((unsigned int)time(NULL));
for (int i = arraysize-1; i > 0; i--)
{
int n = rand() % (i + 1);
cArray->Swap(i, n);
}
}
static cell AMX_NATIVE_CALL SortADTArray(AMX *amx, cell *params)
{
CellVector* vec=HandleToVector(amx, params[1]);
if (vec==NULL)
{
return 0;
}
cell order = params[2];
if (order == Sort_Random)
{
sort_adt_random(vec);
return 1;
}
cell type = params[3];
size_t arraysize = vec->Size();
size_t blocksize = vec->GetCellCount();
cell *array = vec->Base();
if (type == Sort_Integer)
{
if (order == Sort_Ascending)
{
qsort(array, arraysize, blocksize * sizeof(cell), sort_ints_asc);
}
else
{
qsort(array, arraysize, blocksize * sizeof(cell), sort_ints_desc);
}
}
else if (type == Sort_Float)
{
if (order == Sort_Ascending)
{
qsort(array, arraysize, blocksize * sizeof(cell), sort_floats_asc);
}
else
{
qsort(array, arraysize, blocksize * sizeof(cell), sort_floats_desc);
}
}
else if (type == Sort_String)
{
if (order == Sort_Ascending)
{
qsort(array, arraysize, blocksize * sizeof(cell), sort_adtarray_strings_asc);
}
else
{
qsort(array, arraysize, blocksize * sizeof(cell), sort_adtarray_strings_desc);
}
}
return 1;
}
AMX_NATIVE_INFO g_SortNatives[] =
{
{"SortIntegers", SortIntegers},
@ -355,6 +485,7 @@ AMX_NATIVE_INFO g_SortNatives[] =
{"SortStrings", SortStrings},
{"SortCustom1D", SortCustom1D},
{"SortCustom2D", SortCustom2D},
{"SortADTArray", SortADTArray},
{NULL, NULL},
};