core/logic/smn_sorting.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Wed Aug 14 14:20:57 2013 -0400 (2013-08-14)
changeset 4008 490b01aa0683
parent 3752 619f3ef7f5fc
permissions -rw-r--r--
Updated some CS:GO gamedata.
dvander@2726
     1
/**
dvander@2726
     2
 * vim: set ts=4 :
dvander@2726
     3
 * =============================================================================
dvander@2726
     4
 * SourceMod
dvander@2726
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@2726
     6
 * =============================================================================
dvander@2726
     7
 *
dvander@2726
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2726
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2726
    10
 * Free Software Foundation.
dvander@2726
    11
 * 
dvander@2726
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2726
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2726
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2726
    15
 * details.
dvander@2726
    16
 *
dvander@2726
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2726
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2726
    19
 *
dvander@2726
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2726
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2726
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2726
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2726
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2726
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2726
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2726
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@2726
    28
 *
dvander@2726
    29
 * Version: $Id$
dvander@2726
    30
 */
dvander@2726
    31
dvander@2726
    32
#include <stdlib.h>
dvander@2726
    33
#include <string.h>
dvander@2726
    34
#include <time.h>
dvander@2726
    35
#include "common_logic.h"
dvander@2726
    36
#include "CellArray.h"
dvander@2726
    37
dvander@2726
    38
/***********************************
dvander@2726
    39
 *   About the double array hack   *
dvander@2726
    40
     ***************************   
dvander@2726
    41
dvander@2726
    42
 Double arrays in Pawn are vectors offset by the current offset.  For example:
dvander@2726
    43
dvander@2726
    44
 new array[2][2]
dvander@2726
    45
dvander@2726
    46
   In this array, index 0 contains the offset from the current offset which
dvander@2726
    47
 results in the final vector [2] (at [0][2]).  Meaning, to dereference [1][2], 
dvander@2726
    48
 it is equivalent to:
dvander@2726
    49
dvander@2726
    50
 address = &array[1] + array[1] + 2 * sizeof(cell)
dvander@2726
    51
dvander@2726
    52
   The fact that each offset is from the _current_ position rather than the _base_
dvander@2726
    53
 position is very important.  It means that if you to try to swap vector positions,
dvander@2726
    54
 the offsets will no longer match, because their current position has changed.  A 
dvander@2726
    55
 simple and ingenious way around this is to back up the positions in a separate array,
dvander@2726
    56
 then to overwrite each position in the old array with absolute indices.  Pseudo C++ code:
dvander@2726
    57
dvander@2726
    58
 cell *array; //assumed to be set to the 2+D array
dvander@2726
    59
 cell *old_offsets = new cell[2];
dvander@2726
    60
 for (int i=0; i<2; i++)
dvander@2726
    61
 {
dvander@2726
    62
    old_offsets = array[i];
dvander@2726
    63
	array[i] = i;
dvander@2726
    64
 }
dvander@2726
    65
dvander@2726
    66
   Now, you can swap the array indices with no problem, and do a reverse-lookup to find the original addresses.
dvander@2726
    67
 After sorting/modification is done, you must relocate the new indices.  For example, if the two vectors in our
dvander@2726
    68
 demo array were swapped, array[0] would be 1 and array[1] would be 0.  This is invalid to the virtual machine.
dvander@2726
    69
 Luckily, this is also simple -- all the information is there.
dvander@2726
    70
dvander@2726
    71
 for (int i=0; i<2; i++)
dvander@2726
    72
 {
dvander@2726
    73
	//get the # of the vector we want to relocate in
dvander@2726
    74
	cell vector_index = array[i];			
dvander@2726
    75
	//get the real address of this vector
dvander@2726
    76
	char *real_address = (char *)array + (vector_index * sizeof(cell)) + old_offsets[vector_index];
dvander@2726
    77
	//calc and store the new distance offset
dvander@2726
    78
	array[i] = real_address - ( (char *)array + (vector_index + sizeof(cell)) )
dvander@2726
    79
 }
dvander@2726
    80
dvander@2726
    81
 Note that the inner expression can be heavily reduced; it is expanded for readability.
dvander@2726
    82
 **********************************/
dvander@2726
    83
dvander@2726
    84
enum SortOrder
dvander@2726
    85
{
dvander@2726
    86
	Sort_Ascending = 0,
dvander@2726
    87
	Sort_Descending = 1,
dvander@2726
    88
	Sort_Random = 2,
dvander@2726
    89
};
dvander@2726
    90
dvander@2726
    91
void sort_random(cell_t *array, cell_t size)
dvander@2726
    92
{
dvander@2726
    93
	srand((unsigned int)time(NULL));
dvander@2726
    94
dvander@2726
    95
	for (int i = size-1; i > 0; i--)
dvander@2726
    96
	{
januk@3752
    97
        int n = rand() % (i + 1);
dvander@2726
    98
dvander@2726
    99
		if (array[i] != array[n]) 
dvander@2726
   100
		{
dvander@2726
   101
			array[i] ^= array[n];
dvander@2726
   102
			array[n] ^= array[i];
dvander@2726
   103
			array[i] ^= array[n];
dvander@2726
   104
		}
dvander@2726
   105
	}
dvander@2726
   106
}
dvander@2726
   107
dvander@2726
   108
int sort_ints_asc(const void *int1, const void *int2)
dvander@2726
   109
{
dvander@2726
   110
	return (*(int *)int1) - (*(int *)int2);
dvander@2726
   111
}
dvander@2726
   112
dvander@2726
   113
int sort_ints_desc(const void *int1, const void *int2)
dvander@2726
   114
{
dvander@2726
   115
	return (*(int *)int2) - (*(int *)int1);
dvander@2726
   116
}
dvander@2726
   117
dvander@2726
   118
static cell_t sm_SortIntegers(IPluginContext *pContext, const cell_t *params)
dvander@2726
   119
{
dvander@2726
   120
	cell_t *array;
dvander@2726
   121
	cell_t array_size = params[2];
dvander@2726
   122
	cell_t type = params[3];
dvander@2726
   123
dvander@2726
   124
	pContext->LocalToPhysAddr(params[1], &array);
dvander@2726
   125
dvander@2726
   126
	if (type == Sort_Ascending)
dvander@2726
   127
	{
dvander@2726
   128
		qsort(array, array_size, sizeof(cell_t), sort_ints_asc);
dvander@2726
   129
	} 
dvander@2726
   130
	else if (type == Sort_Descending)
dvander@2726
   131
	{
dvander@2726
   132
		qsort(array, array_size, sizeof(cell_t), sort_ints_desc);
dvander@2726
   133
	}
dvander@2726
   134
	else
dvander@2726
   135
	{
dvander@2726
   136
		sort_random(array, array_size);
dvander@2726
   137
	}
dvander@2726
   138
dvander@2726
   139
	return 1;
dvander@2726
   140
}
dvander@2726
   141
dvander@2726
   142
int sort_floats_asc(const void *float1, const void *float2)
dvander@2726
   143
{
dvander@2726
   144
	float r1 = *(float *)float1;
dvander@2726
   145
	float r2 = *(float *)float2;
dvander@2726
   146
	
dvander@2726
   147
	if (r1 < r2)
dvander@2726
   148
	{
dvander@2726
   149
		return -1;
dvander@2726
   150
	} else if (r2 < r1) {
dvander@2726
   151
		return 1;
dvander@2726
   152
	} else {
dvander@2726
   153
		return 0;
dvander@2726
   154
	}
dvander@2726
   155
}
dvander@2726
   156
dvander@2726
   157
int sort_floats_desc(const void *float1, const void *float2)
dvander@2726
   158
{
dvander@2726
   159
	float r1 = *(float *)float1;
dvander@2726
   160
	float r2 = *(float *)float2;
dvander@2726
   161
dvander@2726
   162
	if (r1 < r2)
dvander@2726
   163
	{
dvander@2726
   164
		return 1;
dvander@2726
   165
	} else if (r2 < r1) {
dvander@2726
   166
		return -1;
dvander@2726
   167
	} else {
dvander@2726
   168
		return 0;
dvander@2726
   169
	}
dvander@2726
   170
}
dvander@2726
   171
dvander@2726
   172
static cell_t sm_SortFloats(IPluginContext *pContext, const cell_t *params)
dvander@2726
   173
{
dvander@2726
   174
	cell_t *array;
dvander@2726
   175
	cell_t array_size = params[2];
dvander@2726
   176
	cell_t type = params[3];
dvander@2726
   177
dvander@2726
   178
	pContext->LocalToPhysAddr(params[1], &array);
dvander@2726
   179
dvander@2726
   180
	if (type == Sort_Ascending)
dvander@2726
   181
	{
dvander@2726
   182
		qsort(array, array_size, sizeof(cell_t), sort_floats_asc);
dvander@2726
   183
	}
dvander@2726
   184
	else if (type == Sort_Descending)
dvander@2726
   185
	{
dvander@2726
   186
		qsort(array, array_size, sizeof(cell_t), sort_floats_desc);
dvander@2726
   187
	}
dvander@2726
   188
	else
dvander@2726
   189
	{
dvander@2726
   190
		sort_random(array, array_size);
dvander@2726
   191
	}
dvander@2726
   192
dvander@2726
   193
	return 1;
dvander@2726
   194
}
dvander@2726
   195
dvander@2726
   196
static cell_t *g_CurStringArray = NULL;
dvander@2726
   197
static cell_t *g_CurRebaseMap = NULL;
dvander@2726
   198
dvander@2726
   199
int sort_strings_asc(const void *blk1, const void *blk2)
dvander@2726
   200
{
dvander@2726
   201
	cell_t reloc1 = *(cell_t *)blk1;
dvander@2726
   202
	cell_t reloc2 = *(cell_t *)blk2;
dvander@2726
   203
	
dvander@2726
   204
	char *str1 = ((char *)(&g_CurStringArray[reloc1]) + g_CurRebaseMap[reloc1]);
dvander@2726
   205
	char *str2 = ((char *)(&g_CurStringArray[reloc2]) + g_CurRebaseMap[reloc2]);
dvander@2726
   206
dvander@2726
   207
	return strcmp(str1, str2);
dvander@2726
   208
}
dvander@2726
   209
dvander@2726
   210
int sort_strings_desc(const void *blk1, const void *blk2)
dvander@2726
   211
{
dvander@2726
   212
	cell_t reloc1 = *(cell_t *)blk1;
dvander@2726
   213
	cell_t reloc2 = *(cell_t *)blk2;
dvander@2726
   214
dvander@2726
   215
	char *str1 = ((char *)(&g_CurStringArray[reloc1]) + g_CurRebaseMap[reloc1]);
dvander@2726
   216
	char *str2 = ((char *)(&g_CurStringArray[reloc2]) + g_CurRebaseMap[reloc2]);
dvander@2726
   217
dvander@2726
   218
	return strcmp(str2, str1);
dvander@2726
   219
}
dvander@2726
   220
dvander@2726
   221
static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params)
dvander@2726
   222
{
dvander@2726
   223
	cell_t *array;
dvander@2726
   224
	cell_t array_size = params[2];
dvander@2726
   225
	cell_t type = params[3];
dvander@2726
   226
dvander@2726
   227
	pContext->LocalToPhysAddr(params[1], &array);
dvander@2726
   228
dvander@2726
   229
	/** HACKHACK - back up the old indices, replace the indices with something easier */
dvander@2726
   230
	cell_t amx_addr, *phys_addr;
dvander@2726
   231
	int err;
dvander@2726
   232
	if ((err=pContext->HeapAlloc(array_size, &amx_addr, &phys_addr)) != SP_ERROR_NONE)
dvander@2726
   233
	{
dvander@2726
   234
		pContext->ThrowNativeErrorEx(err, "Ran out of memory to sort");
dvander@2726
   235
	}
dvander@2726
   236
dvander@2726
   237
	g_CurStringArray = array;
dvander@2726
   238
	g_CurRebaseMap = phys_addr;
dvander@2726
   239
dvander@2726
   240
	for (int i=0; i<array_size; i++)
dvander@2726
   241
	{
dvander@2726
   242
		phys_addr[i] = array[i];
dvander@2726
   243
		array[i] = i;
dvander@2726
   244
	}
dvander@2726
   245
dvander@2726
   246
	if (type == Sort_Ascending)
dvander@2726
   247
	{
dvander@2726
   248
		qsort(array, array_size, sizeof(cell_t), sort_strings_asc);
dvander@2726
   249
	} 
dvander@2726
   250
	else if (type == Sort_Descending)
dvander@2726
   251
	{
dvander@2726
   252
		qsort(array, array_size, sizeof(cell_t), sort_strings_desc);
dvander@2726
   253
	}
dvander@2726
   254
	else
dvander@2726
   255
	{
dvander@2726
   256
		sort_random(array, array_size);
dvander@2726
   257
	}
dvander@2726
   258
dvander@2726
   259
	/* END HACKHACK - restore what we damaged so Pawn doesn't throw up.
dvander@2726
   260
	 * We'll browse through each index of the array and patch up the distance.
dvander@2726
   261
	 */
dvander@2726
   262
	for (int i=0; i<array_size; i++)
dvander@2726
   263
	{
dvander@2726
   264
		/* Compute the final address of the old array and subtract the new location.
dvander@2726
   265
		 * This is the fixed up distance.
dvander@2726
   266
		 */
dvander@2726
   267
		array[i] = ((char *)&array[array[i]] + phys_addr[array[i]]) - (char *)&array[i];
dvander@2726
   268
	}
dvander@2726
   269
dvander@2726
   270
	pContext->HeapPop(amx_addr);
dvander@2726
   271
dvander@2726
   272
	g_CurStringArray = NULL;
dvander@2726
   273
	g_CurRebaseMap = NULL;
dvander@2726
   274
dvander@2726
   275
	return 1;
dvander@2726
   276
}
dvander@2726
   277
dvander@2726
   278
struct sort_info
dvander@2726
   279
{
dvander@2726
   280
	IPluginFunction *pFunc;
dvander@2726
   281
	Handle_t hndl;
dvander@2726
   282
	cell_t array_addr;
dvander@2726
   283
	cell_t *array_base;
dvander@2726
   284
	cell_t *array_remap;
dvander@2726
   285
};
dvander@2726
   286
dvander@2726
   287
sort_info g_SortInfo;
dvander@2726
   288
dvander@2726
   289
int sort1d_amx_custom(const void *elem1, const void *elem2)
dvander@2726
   290
{
dvander@2726
   291
	cell_t c1 = *(cell_t *)elem1;
dvander@2726
   292
	cell_t c2 = *(cell_t *)elem2;
dvander@2726
   293
dvander@2726
   294
	cell_t result = 0;
dvander@2726
   295
	IPluginFunction *pf = g_SortInfo.pFunc;
dvander@2726
   296
	pf->PushCell(c1);
dvander@2726
   297
	pf->PushCell(c2);
dvander@2726
   298
	pf->PushCell(g_SortInfo.array_addr);
dvander@2726
   299
	pf->PushCell(g_SortInfo.hndl);
dvander@2726
   300
	pf->Execute(&result);
dvander@2726
   301
dvander@2726
   302
	return result;
dvander@2726
   303
}
dvander@2726
   304
dvander@2726
   305
static cell_t sm_SortCustom1D(IPluginContext *pContext, const cell_t *params)
dvander@2726
   306
{
dvander@2726
   307
	cell_t *array;
dvander@2726
   308
	cell_t array_size = params[2];
dvander@2726
   309
dvander@2726
   310
	IPluginFunction *pFunction = pContext->GetFunctionById(params[3]);
dvander@2726
   311
	if (!pFunction)
dvander@2726
   312
	{
dvander@2726
   313
		return pContext->ThrowNativeError("Function %x is not a valid function", params[3]);
dvander@2726
   314
	}
dvander@2726
   315
dvander@2726
   316
	pContext->LocalToPhysAddr(params[1], &array);
dvander@2726
   317
dvander@2726
   318
	sort_info oldinfo = g_SortInfo;
dvander@2726
   319
dvander@2726
   320
	
dvander@2726
   321
	g_SortInfo.hndl = params[4];
dvander@2726
   322
	g_SortInfo.array_addr = params[1];
dvander@2726
   323
	g_SortInfo.array_remap = NULL;
dvander@2726
   324
	g_SortInfo.array_base = NULL;
dvander@2726
   325
	g_SortInfo.pFunc = pFunction;
dvander@2726
   326
dvander@2726
   327
	qsort(array, array_size, sizeof(cell_t), sort1d_amx_custom);
dvander@2726
   328
dvander@2726
   329
	g_SortInfo = oldinfo;
dvander@2726
   330
dvander@2726
   331
	return 1;
dvander@2726
   332
}
dvander@2726
   333
dvander@2726
   334
int sort2d_amx_custom(const void *elem1, const void *elem2)
dvander@2726
   335
{
dvander@2726
   336
	cell_t c1 = *(cell_t *)elem1;
dvander@2726
   337
	cell_t c2 = *(cell_t *)elem2;
dvander@2726
   338
dvander@2726
   339
	cell_t c1_addr = g_SortInfo.array_addr + (c1 * sizeof(cell_t)) + g_SortInfo.array_remap[c1];
dvander@2726
   340
	cell_t c2_addr = g_SortInfo.array_addr + (c2 * sizeof(cell_t)) + g_SortInfo.array_remap[c2];
dvander@2726
   341
dvander@2726
   342
	IPluginContext *pContext = g_SortInfo.pFunc->GetParentContext();
dvander@2726
   343
	cell_t *c1_r, *c2_r;
dvander@2726
   344
	pContext->LocalToPhysAddr(c1_addr, &c1_r);
dvander@2726
   345
	pContext->LocalToPhysAddr(c2_addr, &c2_r);
dvander@2726
   346
dvander@2726
   347
	cell_t result = 0;
dvander@2726
   348
	g_SortInfo.pFunc->PushCell(c1_addr);
dvander@2726
   349
	g_SortInfo.pFunc->PushCell(c2_addr);
dvander@2726
   350
	g_SortInfo.pFunc->PushCell(g_SortInfo.array_addr);
dvander@2726
   351
	g_SortInfo.pFunc->PushCell(g_SortInfo.hndl);
dvander@2726
   352
	g_SortInfo.pFunc->Execute(&result);
dvander@2726
   353
dvander@2726
   354
	return result;
dvander@2726
   355
}
dvander@2726
   356
dvander@2726
   357
static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
dvander@2726
   358
{
dvander@2726
   359
	cell_t *array;
dvander@2726
   360
	cell_t array_size = params[2];
dvander@2726
   361
	IPluginFunction *pFunction;
dvander@2726
   362
dvander@2726
   363
	pContext->LocalToPhysAddr(params[1], &array);
dvander@2726
   364
dvander@2726
   365
	if ((pFunction=pContext->GetFunctionById(params[3])) == NULL)
dvander@2726
   366
	{
dvander@2726
   367
		return pContext->ThrowNativeError("Function %x is not a valid function", params[3]);
dvander@2726
   368
	}
dvander@2726
   369
dvander@2726
   370
	/** back up the old indices, replace the indices with something easier */
dvander@2726
   371
	cell_t amx_addr, *phys_addr;
dvander@2726
   372
	int err;
dvander@2726
   373
	if ((err=pContext->HeapAlloc(array_size, &amx_addr, &phys_addr)) != SP_ERROR_NONE)
dvander@2726
   374
	{
dvander@2726
   375
		pContext->ThrowNativeErrorEx(err, "Ran out of memory to sort");
dvander@2726
   376
		return 0;
dvander@2726
   377
	}
dvander@2726
   378
dvander@2726
   379
	sort_info oldinfo = g_SortInfo;
dvander@2726
   380
dvander@2726
   381
	g_SortInfo.pFunc = pFunction;
dvander@2726
   382
	g_SortInfo.hndl = params[4];
dvander@2726
   383
	g_SortInfo.array_addr = params[1];
dvander@2726
   384
	
dvander@2726
   385
	/** Same process as in strings, back up the old indices for later fixup */
dvander@2726
   386
	g_SortInfo.array_base = array;
dvander@2726
   387
	g_SortInfo.array_remap = phys_addr;
dvander@2726
   388
	
dvander@2726
   389
	for (int i=0; i<array_size; i++)
dvander@2726
   390
	{
dvander@2726
   391
		phys_addr[i] = array[i];
dvander@2726
   392
		array[i] = i;
dvander@2726
   393
	}
dvander@2726
   394
dvander@2726
   395
	qsort(array, array_size, sizeof(cell_t), sort2d_amx_custom);
dvander@2726
   396
dvander@2726
   397
	/** Fixup process! */
dvander@2726
   398
	for (int i=0; i<array_size; i++)
dvander@2726
   399
	{
dvander@2726
   400
		/* Compute the final address of the old array and subtract the new location.
dvander@2726
   401
		 * This is the fixed up distance.
dvander@2726
   402
		 */
dvander@2726
   403
		array[i] = ((char *)&array[array[i]] + phys_addr[array[i]]) - (char *)&array[i];
dvander@2726
   404
	}
dvander@2726
   405
dvander@2726
   406
	pContext->HeapPop(amx_addr);
dvander@2726
   407
dvander@2726
   408
	g_SortInfo = oldinfo;
dvander@2726
   409
	
dvander@2726
   410
	return 1;
dvander@2726
   411
}
dvander@2726
   412
dvander@2726
   413
enum SortType
dvander@2726
   414
{
dvander@2726
   415
	Sort_Integer = 0,
dvander@2726
   416
	Sort_Float,
dvander@2726
   417
	Sort_String,
dvander@2726
   418
};
dvander@2726
   419
dvander@2726
   420
int sort_adtarray_strings_asc(const void *str1, const void *str2)
dvander@2726
   421
{
dvander@2726
   422
	return strcmp((char *) str1, (char *) str2);
dvander@2726
   423
}
dvander@2726
   424
dvander@2726
   425
int sort_adtarray_strings_desc(const void *str1, const void *str2)
dvander@2726
   426
{
dvander@2726
   427
	return strcmp((char *) str2, (char *) str1);
dvander@2726
   428
}
dvander@2726
   429
dvander@2726
   430
void sort_adt_random(CellArray *cArray)
dvander@2726
   431
{
dvander@2726
   432
	size_t arraysize = cArray->size();
dvander@2726
   433
dvander@2726
   434
	srand((unsigned int)time(NULL));
dvander@2726
   435
dvander@2726
   436
	for (int i = arraysize-1; i > 0; i--)
dvander@2726
   437
	{
januk@3752
   438
        int n = rand() % (i + 1);
dvander@2726
   439
dvander@2726
   440
		cArray->swap(i, n);
dvander@2726
   441
	}
dvander@2726
   442
}
dvander@2726
   443
dvander@2726
   444
static cell_t sm_SortADTArray(IPluginContext *pContext, const cell_t *params)
dvander@2726
   445
{
dvander@2726
   446
	CellArray *cArray;
dvander@2726
   447
	HandleError err;
dvander@2726
   448
	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
dvander@2726
   449
dvander@2726
   450
	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&cArray)) 
dvander@2726
   451
		!= HandleError_None)
dvander@2726
   452
	{
dvander@2726
   453
		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
dvander@2726
   454
	}
dvander@2726
   455
dvander@2726
   456
	cell_t order = params[2];
dvander@2726
   457
	
dvander@2726
   458
	if (order == Sort_Random)
dvander@2726
   459
	{
dvander@2726
   460
		sort_adt_random(cArray);
dvander@2726
   461
dvander@2726
   462
		return 1;
dvander@2726
   463
	}
dvander@2726
   464
dvander@2726
   465
	cell_t type = params[3];
dvander@2726
   466
	size_t arraysize = cArray->size();
dvander@2726
   467
	size_t blocksize = cArray->blocksize();
dvander@2726
   468
	cell_t *array = cArray->base();
dvander@2726
   469
dvander@2726
   470
	if (type == Sort_Integer)
dvander@2726
   471
	{
dvander@2726
   472
		if (order == Sort_Ascending)
dvander@2726
   473
		{
dvander@2726
   474
			qsort(array, arraysize, blocksize * sizeof(cell_t), sort_ints_asc);
dvander@2726
   475
		}
dvander@2726
   476
		else
dvander@2726
   477
		{
dvander@2726
   478
			qsort(array, arraysize, blocksize * sizeof(cell_t), sort_ints_desc);
dvander@2726
   479
		}
dvander@2726
   480
	}
dvander@2726
   481
	else if (type == Sort_Float)
dvander@2726
   482
	{
dvander@2726
   483
		if (order == Sort_Ascending)
dvander@2726
   484
		{
dvander@2726
   485
			qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_asc);
dvander@2726
   486
		}
dvander@2726
   487
		else 
dvander@2726
   488
		{
dvander@2726
   489
			qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_desc);
dvander@2726
   490
		}
dvander@2726
   491
	}
dvander@2726
   492
	else if (type == Sort_String)
dvander@2726
   493
	{
dvander@2726
   494
		if (order == Sort_Ascending)
dvander@2726
   495
		{
dvander@2726
   496
			qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_asc);
dvander@2726
   497
		}
dvander@2726
   498
		else 
dvander@2726
   499
		{
dvander@2726
   500
			qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_desc);
dvander@2726
   501
		}
dvander@2726
   502
	}
dvander@2726
   503
dvander@2726
   504
	return 1;
dvander@2726
   505
}
dvander@2726
   506
dvander@2726
   507
struct sort_infoADT
dvander@2726
   508
{
dvander@2726
   509
	IPluginFunction *pFunc;
dvander@2726
   510
	cell_t *array_base;
dvander@2726
   511
	cell_t array_bsize;
dvander@2726
   512
	Handle_t array_hndl;
dvander@2726
   513
	Handle_t hndl;
dvander@2726
   514
};
dvander@2726
   515
dvander@2726
   516
sort_infoADT g_SortInfoADT;
dvander@2726
   517
dvander@2726
   518
int sort_adtarray_custom(const void *elem1, const void *elem2)
dvander@2726
   519
{
dvander@2726
   520
	cell_t result = 0;
dvander@2726
   521
	IPluginFunction *pf = g_SortInfoADT.pFunc;
dvander@2726
   522
	pf->PushCell(((cell_t) ((cell_t *) elem1 - g_SortInfoADT.array_base)) / g_SortInfoADT.array_bsize);
dvander@2726
   523
	pf->PushCell(((cell_t) ((cell_t *) elem2 - g_SortInfoADT.array_base)) / g_SortInfoADT.array_bsize);
dvander@2726
   524
	pf->PushCell(g_SortInfoADT.array_hndl);
dvander@2726
   525
	pf->PushCell(g_SortInfoADT.hndl);
dvander@2726
   526
	pf->Execute(&result);
dvander@2726
   527
dvander@2726
   528
	return result;
dvander@2726
   529
}
dvander@2726
   530
dvander@2726
   531
static cell_t sm_SortADTArrayCustom(IPluginContext *pContext, const cell_t *params)
dvander@2726
   532
{
dvander@2726
   533
	CellArray *cArray;
dvander@2726
   534
	HandleError err;
dvander@2726
   535
	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
dvander@2726
   536
dvander@2726
   537
	if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&cArray)) 
dvander@2726
   538
		!= HandleError_None)
dvander@2726
   539
	{
dvander@2726
   540
		return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
dvander@2726
   541
	}
dvander@2726
   542
dvander@2726
   543
	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
dvander@2726
   544
	if (!pFunction)
dvander@2726
   545
	{
dvander@2726
   546
		return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
dvander@2726
   547
	}
dvander@2726
   548
dvander@2726
   549
	size_t arraysize = cArray->size();
dvander@2726
   550
	size_t blocksize = cArray->blocksize();
dvander@2726
   551
	cell_t *array = cArray->base();
dvander@2726
   552
dvander@2726
   553
	sort_infoADT oldinfo = g_SortInfoADT;
dvander@2726
   554
dvander@2726
   555
	g_SortInfoADT.pFunc = pFunction;
dvander@2726
   556
	g_SortInfoADT.array_base = array;
dvander@2726
   557
	g_SortInfoADT.array_bsize = (cell_t) blocksize;
dvander@2726
   558
	g_SortInfoADT.array_hndl = params[1];
dvander@2726
   559
	g_SortInfoADT.hndl = params[3];
dvander@2726
   560
	
dvander@2726
   561
	qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_custom);
dvander@2726
   562
dvander@2726
   563
	g_SortInfoADT = oldinfo;
dvander@2726
   564
dvander@2726
   565
	return 1;
dvander@2726
   566
}
dvander@2726
   567
dvander@2726
   568
REGISTER_NATIVES(sortNatives)
dvander@2726
   569
{
dvander@2726
   570
	{"SortIntegers",			sm_SortIntegers},
dvander@2726
   571
	{"SortFloats",				sm_SortFloats},
dvander@2726
   572
	{"SortStrings",				sm_SortStrings},
dvander@2726
   573
	{"SortCustom1D",			sm_SortCustom1D},
dvander@2726
   574
	{"SortCustom2D",			sm_SortCustom2D},
dvander@2726
   575
	{"SortADTArray",			sm_SortADTArray},
dvander@2726
   576
	{"SortADTArrayCustom",		sm_SortADTArrayCustom},
dvander@2726
   577
	{NULL,						NULL},
dvander@2726
   578
};