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