diff --git a/core/CellArray.h b/core/CellArray.h index 39e9197b..c9ee2831 100644 --- a/core/CellArray.h +++ b/core/CellArray.h @@ -32,6 +32,8 @@ #include #include +extern HandleType_t htCellArray; + class CellArray { public: @@ -149,6 +151,11 @@ public: return array; } + cell_t *base() + { + return m_Data; + } + private: bool GrowIfNeeded(size_t count) { diff --git a/core/smn_sorting.cpp b/core/smn_sorting.cpp index f78bff74..9bf9426d 100644 --- a/core/smn_sorting.cpp +++ b/core/smn_sorting.cpp @@ -33,6 +33,8 @@ #include #include #include +#include "HandleSys.h" +#include "CellArray.h" /*********************************** * About the double array hack * @@ -373,6 +375,139 @@ static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *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); +} + +static cell_t sm_SortADTArray(IPluginContext *pContext, const cell_t *params) +{ + CellArray *cArray; + HandleError err; + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); + + if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&cArray)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); + } + + cell_t order = params[2]; + cell_t type = params[3]; + size_t arraysize = cArray->size(); + size_t blocksize = cArray->blocksize(); + cell_t *array = cArray->base(); + + if (type == Sort_Integer) + { + if (order == Sort_Ascending) + { + qsort(array, arraysize, blocksize * sizeof(cell_t), sort_ints_asc); + } + else + { + qsort(array, arraysize, blocksize * sizeof(cell_t), sort_ints_desc); + } + } + else if (type == Sort_Float) + { + if (type == Sort_Ascending) + { + qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_asc); + } + else + { + qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_desc); + } + } + else if (type == Sort_String) + { + if (type == Sort_Ascending) + { + qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_asc); + } + else + { + qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_desc); + } + } + + return 1; +} + +struct sort_infoADT +{ + IPluginFunction *pFunc; + cell_t *array_base; + cell_t array_bsize; + Handle_t array_hndl; + Handle_t hndl; +}; + +sort_infoADT g_SortInfoADT; + +int sort_adtarray_custom(const void *elem1, const void *elem2) +{ + cell_t result = 0; + IPluginFunction *pf = g_SortInfoADT.pFunc; + pf->PushCell(((cell_t) ((cell_t *) elem1 - g_SortInfoADT.array_base)) / g_SortInfoADT.array_bsize); + pf->PushCell(((cell_t) ((cell_t *) elem2 - g_SortInfoADT.array_base)) / g_SortInfoADT.array_bsize); + pf->PushCell(g_SortInfoADT.array_hndl); + pf->PushCell(g_SortInfoADT.hndl); + pf->Execute(&result); + + return result; +} + +static cell_t sm_SortADTArrayCustom(IPluginContext *pContext, const cell_t *params) +{ + CellArray *cArray; + HandleError err; + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); + + if ((err = g_HandleSys.ReadHandle(params[1], htCellArray, &sec, (void **)&cArray)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err); + } + + IPluginFunction *pFunction = pContext->GetFunctionById(params[2]); + if (!pFunction) + { + return pContext->ThrowNativeError("Function %x is not a valid function", params[2]); + } + + size_t arraysize = cArray->size(); + size_t blocksize = cArray->blocksize(); + cell_t *array = cArray->base(); + + sort_infoADT oldinfo = g_SortInfoADT; + + g_SortInfoADT.pFunc = pFunction; + g_SortInfoADT.array_base = array; + g_SortInfoADT.array_bsize = (cell_t) blocksize; + g_SortInfoADT.array_hndl = params[1]; + g_SortInfoADT.hndl = params[3]; + + qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_custom); + + g_SortInfoADT = oldinfo; + + return 1; +} + REGISTER_NATIVES(sortNatives) { {"SortIntegers", sm_SortIntegers}, @@ -380,5 +515,7 @@ REGISTER_NATIVES(sortNatives) {"SortStrings", sm_SortStrings}, {"SortCustom1D", sm_SortCustom1D}, {"SortCustom2D", sm_SortCustom2D}, + {"SortADTArray", sm_SortADTArray}, + {"SortADTArrayCustom", sm_SortADTArrayCustom}, {NULL, NULL}, }; diff --git a/plugins/include/sorting.inc b/plugins/include/sorting.inc index dfdcb53e..6d49a238 100644 --- a/plugins/include/sorting.inc +++ b/plugins/include/sorting.inc @@ -45,6 +45,16 @@ enum SortOrder Sort_Descending = 1, /**< Descending order */ }; +/** + * Data types for ADT Array Sorts + */ + enum SortType + { + Sort_Integer = 0, + Sort_Float, + Sort_String, +}; + /** * Sorts an array of integers. * @@ -128,3 +138,38 @@ funcenum SortFunc2D * @noreturn */ native SortCustom2D(array[][], array_size, SortFunc2D:sortfunc, Handle:hndl=INVALID_HANDLE); + +/** + * Sort an ADT Array. Specify the type as Integer, Float, or String. + * + * @param array Array Handle to sort + * @param order Sort order to use, same as other sorts. + * @param type Data type stored in the ADT Array + * @noreturn + */ +native SortADTArray(Handle:array, SortOrder:order = Sort_Ascending, SortType:type = Sort_Integer); + +/** + * Sort comparison function for ADT Array elements. Function provides you with + * indexes currently being sorted, use ADT Array functions to retrieve the + * index values and compare. + * + * @param index1 First index to compare. + * @param index2 Second index to compare. + * @param array Array that is being sorted (order is undefined). + * @param hndl Handle optionally passed in while sorting. + * @return -1 if first should go before second + * 0 if first is equal to second + * 1 if first should go after second + */ +functag SortFuncADTArray public(index1, index2, Handle:array, Handle:hndl); + +/** + * Custom sorts an ADT Array. You must pass in a comparison function. + * + * @param array Array Handle to sort + * @param sortfunc Sort comparision function to use + * @param hndl Optional Handle to pass through the comparison calls. + * @noreturn + */ +native SortADTArrayCustom(Handle:array, SortFuncADTArray:sortfunc, Handle:hndl=INVALID_HANDLE); \ No newline at end of file diff --git a/plugins/testsuite/sorttest.sp b/plugins/testsuite/sorttest.sp index 1398a7d5..bd9d4d87 100644 --- a/plugins/testsuite/sorttest.sp +++ b/plugins/testsuite/sorttest.sp @@ -9,13 +9,17 @@ public Plugin:myinfo = url = "http://www.sourcemod.net/" }; -public OnPluginStart(Handle:myself) +public OnPluginStart() { RegServerCmd("test_sort_ints", Command_TestSortInts) RegServerCmd("test_sort_floats", Command_TestSortFloats) RegServerCmd("test_sort_strings", Command_TestSortStrings) RegServerCmd("test_sort_1d", Command_TestSort1D) RegServerCmd("test_sort_2d", Command_TestSort2D) + RegServerCmd("test_adtsort_ints", Command_TestSortADTInts) + RegServerCmd("test_adtsort_floats", Command_TestSortADTFloats) + RegServerCmd("test_adtsort_strings", Command_TestSortADTStrings) + RegServerCmd("test_adtsort_custom", Command_TestSortADTCustom) } /***************** @@ -138,7 +142,7 @@ public Action:Command_TestSortStrings(args) public Custom2DSort(String:elem1[], String:elem2[], String:array[][], Handle:hndl) { - return StrCompare(elem1, elem2) + return strcmp(elem1, elem2) } public Action:Command_TestSort2D(args) @@ -162,3 +166,142 @@ public Action:Command_TestSort2D(args) return Plugin_Handled } + +/******************* + * ADT ARRAY TESTS * + *******************/ +// Int and floats work the same as normal comparisions. Strings are direct +// comparisions with no hacky memory stuff like Pawn arrays. + +PrintADTArrayIntegers(Handle:array) +{ + new size = GetArraySize(array); + for (new i=0; i