core/logic/smn_adt_trie.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Wed May 21 17:25:30 2014 -0400 (2014-05-21)
changeset 4377 7a44be5b7162
parent 4340 c6e0fecd7f42
permissions -rw-r--r--
Trigger build for hl2sdk-l4d changes.
dvander@1779
     1
/**
dvander@4096
     2
 * vim: set ts=4 sw=4 tw=99 noet :
dvander@1779
     3
 * =============================================================================
dvander@1779
     4
 * SourceMod
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@1779
     6
 * =============================================================================
dvander@1779
     7
 *
dvander@1779
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@1779
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@1779
    10
 * Free Software Foundation.
dvander@1779
    11
 * 
dvander@1779
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@1779
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@1779
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@1779
    15
 * details.
dvander@1779
    16
 *
dvander@1779
    17
 * You should have received a copy of the GNU General Public License along with
dvander@1779
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1779
    19
 *
dvander@1779
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@1779
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@1779
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@1779
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@1779
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@1779
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@1779
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@1779
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@1779
    28
 *
dvander@1779
    29
 * Version: $Id$
dvander@1779
    30
 */
dvander@1779
    31
dvander@2471
    32
#include <stdlib.h>
dvander@2728
    33
#include "common_logic.h"
dvander@4096
    34
#include <am-moveable.h>
dvander@4096
    35
#include <am-refcounting.h>
dvander@4096
    36
#include <sm_stringhashmap.h>
dvander@4096
    37
#include "sm_memtable.h"
dvander@1779
    38
dvander@1779
    39
HandleType_t htCellTrie;
dvander@4096
    40
HandleType_t htSnapshot;
dvander@1779
    41
dvander@4096
    42
enum EntryType
dvander@1779
    43
{
dvander@4096
    44
	EntryType_Cell,
dvander@4096
    45
	EntryType_CellArray,
dvander@4096
    46
	EntryType_String,
dvander@1779
    47
};
dvander@1779
    48
dvander@4096
    49
class Entry
dvander@1779
    50
{
dvander@4096
    51
	struct ArrayInfo
dvander@1779
    52
	{
dvander@4096
    53
		size_t length;
dvander@4096
    54
		size_t maxbytes;
dvander@4096
    55
dvander@4096
    56
		void *base() {
dvander@4096
    57
			return this + 1;
dvander@4096
    58
		}
dvander@4096
    59
	};
dvander@4096
    60
dvander@4096
    61
public:
dvander@4096
    62
	Entry()
dvander@4096
    63
		: control_(0)
dvander@4096
    64
	{
dvander@1779
    65
	}
dvander@4096
    66
	Entry(ke::Moveable<Entry> other)
dvander@4096
    67
	{
dvander@4096
    68
		control_ = other->control_;
dvander@4096
    69
		data_ = other->data_;
dvander@4096
    70
		other->control_ = 0;
dvander@4096
    71
	}
dvander@4096
    72
dvander@4096
    73
	~Entry()
dvander@1779
    74
	{
dvander@4096
    75
		free(raw());
dvander@4096
    76
	}
dvander@4096
    77
dvander@4096
    78
	void setCell(cell_t value) {
dvander@4096
    79
		setType(EntryType_Cell);
dvander@4096
    80
		data_ = value;
dvander@4096
    81
	}
dvander@4096
    82
	void setArray(cell_t *cells, size_t length) {
dvander@4096
    83
		ArrayInfo *array = ensureArray(length * sizeof(cell_t));
dvander@4096
    84
		array->length = length;
dvander@4096
    85
		memcpy(array->base(), cells, length * sizeof(cell_t));
dvander@4096
    86
		setTypeAndPointer(EntryType_CellArray, array);
dvander@4096
    87
	}
dvander@4096
    88
	void setString(const char *str) {
dvander@4096
    89
		size_t length = strlen(str);
dvander@4096
    90
		ArrayInfo *array = ensureArray(length + 1);
dvander@4096
    91
		array->length = length;
dvander@4096
    92
		strcpy((char *)array->base(), str);
dvander@4096
    93
		setTypeAndPointer(EntryType_String, array);
dvander@4096
    94
	}
dvander@4096
    95
dvander@4096
    96
	size_t arrayLength() const {
dvander@4096
    97
		assert(isArray());
dvander@4096
    98
		return raw()->length;
dvander@4096
    99
	}
dvander@4096
   100
	cell_t *array() const {
dvander@4096
   101
		assert(isArray());
dvander@4096
   102
		return reinterpret_cast<cell_t *>(raw()->base());
dvander@4096
   103
	}
dvander@4096
   104
	char *chars() const {
dvander@4096
   105
		assert(isString());
dvander@4096
   106
		return reinterpret_cast<char *>(raw()->base());
dvander@4096
   107
	}
dvander@4096
   108
	cell_t cell() const {
dvander@4096
   109
		assert(isCell());
dvander@4096
   110
		return data_;
dvander@4096
   111
	}
dvander@4096
   112
dvander@4096
   113
	bool isCell() const {
dvander@4096
   114
		return type() == EntryType_Cell;
dvander@4096
   115
	}
dvander@4096
   116
	bool isArray() const {
dvander@4096
   117
		return type() == EntryType_CellArray;
dvander@1779
   118
	}
dvander@4096
   119
	bool isString() const {
dvander@4096
   120
		return type() == EntryType_String;
dvander@4096
   121
	}
dvander@4096
   122
dvander@4096
   123
private:
dvander@4096
   124
	Entry(const Entry &other) KE_DELETE;
dvander@4096
   125
dvander@4096
   126
	ArrayInfo *ensureArray(size_t bytes) {
dvander@4096
   127
		ArrayInfo *array = raw();
dvander@4096
   128
		if (array && array->maxbytes >= bytes)
dvander@4096
   129
			return array;
dvander@4096
   130
		array = (ArrayInfo *)realloc(array, bytes + sizeof(ArrayInfo));
dvander@4096
   131
		if (!array)
dvander@4096
   132
		{
dvander@4096
   133
			fprintf(stderr, "Out of memory!\n");
dvander@4096
   134
			abort();
dvander@4096
   135
		}
dvander@4096
   136
		array->maxbytes = bytes;
dvander@4096
   137
		return array;
dvander@1779
   138
	}
dvander@4096
   139
dvander@4096
   140
	// Pointer and type are overlaid, so we have some accessors.
dvander@4096
   141
	ArrayInfo *raw() const {
dvander@4096
   142
		return reinterpret_cast<ArrayInfo *>(control_ & ~uintptr_t(0x3));
dvander@4096
   143
	}
dvander@4096
   144
	void setType(EntryType aType) {
dvander@4096
   145
		control_ = uintptr_t(raw()) | uintptr_t(aType);
dvander@4096
   146
		assert(type() == aType);
dvander@4096
   147
	}
dvander@4096
   148
	void setTypeAndPointer(EntryType aType, ArrayInfo *ptr) {
dvander@4096
   149
		// malloc() should guarantee 8-byte alignment at worst
dvander@4096
   150
		assert((uintptr_t(ptr) & 0x3) == 0);
dvander@4096
   151
		control_ = uintptr_t(ptr) | uintptr_t(aType);
dvander@4096
   152
		assert(type() == aType);
dvander@4096
   153
	}
dvander@4096
   154
	EntryType type() const {
dvander@4096
   155
		return (EntryType)(control_ & 0x3);
dvander@4096
   156
	}
dvander@4096
   157
dvander@4096
   158
private:
dvander@4096
   159
	// Contains the bits for the type, and an array pointer, if one is set.
dvander@4096
   160
	uintptr_t control_;
dvander@4096
   161
dvander@4096
   162
	// Contains data for cell-only entries.
dvander@4096
   163
	cell_t data_;
dvander@1779
   164
};
dvander@1779
   165
dvander@4096
   166
struct CellTrie : public ke::Refcounted<CellTrie>
dvander@4096
   167
{
dvander@4096
   168
	StringHashMap<Entry> map;
dvander@4096
   169
};
dvander@4096
   170
dvander@4096
   171
struct TrieSnapshot
dvander@1779
   172
{
dvander@4096
   173
	TrieSnapshot()
dvander@4096
   174
		: strings(128)
dvander@4096
   175
	{ }
dvander@4096
   176
dvander@4096
   177
	size_t mem_usage()
dvander@4096
   178
	{
dvander@4096
   179
		return length * sizeof(int) + strings.GetMemTable()->GetMemUsage();
dvander@4096
   180
	}
dvander@4096
   181
dvander@4096
   182
	size_t length;
dvander@4096
   183
	ke::AutoArray<int> keys;
dvander@4096
   184
	BaseStringTable strings;
dvander@1779
   185
};
dvander@1779
   186
dvander@1779
   187
class TrieHelpers : 
dvander@1779
   188
	public SMGlobalClass,
dvander@1779
   189
	public IHandleTypeDispatch
dvander@1779
   190
{
dvander@1779
   191
public: //SMGlobalClass
dvander@1779
   192
	void OnSourceModAllInitialized()
dvander@1779
   193
	{
dvander@2728
   194
		htCellTrie = handlesys->CreateType("Trie", this, 0, NULL, NULL, g_pCoreIdent, NULL);
dvander@4096
   195
		htSnapshot = handlesys->CreateType("TrieSnapshot", this, 0, NULL, NULL, g_pCoreIdent, NULL);
dvander@1779
   196
	}
dvander@1779
   197
	void OnSourceModShutdown()
dvander@1779
   198
	{
dvander@4096
   199
		handlesys->RemoveType(htSnapshot, g_pCoreIdent);
dvander@2728
   200
		handlesys->RemoveType(htCellTrie, g_pCoreIdent);
dvander@1779
   201
	}
dvander@1779
   202
public: //IHandleTypeDispatch
dvander@1779
   203
	void OnHandleDestroy(HandleType_t type, void *object)
dvander@1779
   204
	{
dvander@4096
   205
		if (type == htCellTrie)
dvander@4096
   206
		{
dvander@4096
   207
			CellTrie *pTrie = (CellTrie *)object;
dvander@4096
   208
			pTrie->Release();
dvander@4096
   209
		} else {
dvander@4096
   210
			TrieSnapshot *snapshot = (TrieSnapshot *)object;
dvander@4096
   211
			delete snapshot;
dvander@4096
   212
		}
dvander@1779
   213
	}
dvander@1779
   214
	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
dvander@1779
   215
	{
dvander@4096
   216
		if (type == htCellTrie)
dvander@4096
   217
		{
dvander@4096
   218
			CellTrie *pArray = (CellTrie *)object;
dvander@4096
   219
			*pSize = sizeof(CellTrie) + pArray->map.mem_usage();
dvander@4096
   220
		} else {
dvander@4096
   221
			TrieSnapshot *snapshot = (TrieSnapshot *)object;
dvander@4096
   222
			*pSize = sizeof(TrieSnapshot) + snapshot->mem_usage();
dvander@4096
   223
		}
dvander@1779
   224
		return true;
dvander@1779
   225
	}
dvander@1779
   226
} s_CellTrieHelpers;
dvander@1779
   227
dvander@1779
   228
static cell_t CreateTrie(IPluginContext *pContext, const cell_t *params)
dvander@1779
   229
{
dvander@1779
   230
	CellTrie *pTrie = new CellTrie;
dvander@1779
   231
	Handle_t hndl;
dvander@1779
   232
dvander@2728
   233
	if ((hndl = handlesys->CreateHandle(htCellTrie, pTrie, pContext->GetIdentity(), g_pCoreIdent, NULL))
dvander@1779
   234
		== BAD_HANDLE)
dvander@1779
   235
	{
dvander@1779
   236
		delete pTrie;
dvander@1779
   237
		return BAD_HANDLE;
dvander@1779
   238
	}
dvander@1779
   239
dvander@1779
   240
	return hndl;
dvander@1779
   241
}
dvander@1779
   242
dvander@1779
   243
static cell_t SetTrieValue(IPluginContext *pContext, const cell_t *params)
dvander@1779
   244
{
dvander@1779
   245
	CellTrie *pTrie;
dvander@1779
   246
	HandleError err;
dvander@1779
   247
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@1779
   248
dvander@4096
   249
	Handle_t hndl = params[1];
dvander@1779
   250
dvander@2728
   251
	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
dvander@1779
   252
		!= HandleError_None)
dvander@1779
   253
	{
dvander@1779
   254
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@1779
   255
	}
dvander@1779
   256
dvander@1779
   257
	char *key;
dvander@1779
   258
	pContext->LocalToString(params[2], &key);
dvander@1779
   259
dvander@4096
   260
	StringHashMap<Entry>::Insert i = pTrie->map.findForAdd(key);
dvander@4096
   261
	if (!i.found())
dvander@1779
   262
	{
dvander@4096
   263
		if (!pTrie->map.add(i, key))
dvander@4096
   264
			return 0;
dvander@4096
   265
		i->value.setCell(params[3]);
dvander@4096
   266
		return 1;
dvander@1779
   267
	}
dvander@1779
   268
dvander@1779
   269
	if (!params[4])
dvander@1779
   270
		return 0;
dvander@1779
   271
dvander@4096
   272
	i->value.setCell(params[3]);
dvander@1779
   273
	return 1;
dvander@1779
   274
}
dvander@1779
   275
dvander@1779
   276
static cell_t SetTrieArray(IPluginContext *pContext, const cell_t *params)
dvander@1779
   277
{
dvander@1779
   278
	CellTrie *pTrie;
dvander@1779
   279
	HandleError err;
dvander@1779
   280
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@1779
   281
dvander@4096
   282
	Handle_t hndl = params[1];
dvander@1779
   283
dvander@2728
   284
	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
dvander@1779
   285
		!= HandleError_None)
dvander@1779
   286
	{
dvander@1779
   287
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@1779
   288
	}
dvander@1779
   289
dvander@1779
   290
	if (params[4] < 0)
dvander@1779
   291
	{
dvander@1779
   292
		return pContext->ThrowNativeError("Invalid array size: %d", params[4]);
dvander@1779
   293
	}
dvander@1779
   294
dvander@1779
   295
	char *key;
dvander@1779
   296
	cell_t *array;
dvander@1779
   297
	pContext->LocalToString(params[2], &key);
dvander@1779
   298
	pContext->LocalToPhysAddr(params[3], &array);
dvander@1779
   299
dvander@4096
   300
	StringHashMap<Entry>::Insert i = pTrie->map.findForAdd(key);
dvander@4096
   301
	if (!i.found())
dvander@1779
   302
	{
dvander@4096
   303
		if (!pTrie->map.add(i, key))
dvander@1779
   304
			return 0;
dvander@4096
   305
		i->key = key;
dvander@4096
   306
		i->value.setArray(array, params[4]);
dvander@1779
   307
		return 1;
dvander@1779
   308
	}
dvander@1779
   309
skamonkey@4340
   310
	if (!params[5])
dvander@1779
   311
		return 0;
dvander@1779
   312
dvander@4096
   313
	i->value.setArray(array, params[4]);
dvander@1779
   314
	return 1;
dvander@1779
   315
}
dvander@1779
   316
dvander@1779
   317
static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params)
dvander@1779
   318
{
dvander@1779
   319
	CellTrie *pTrie;
dvander@1779
   320
	HandleError err;
dvander@1779
   321
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@1779
   322
dvander@4096
   323
	Handle_t hndl = params[1];
dvander@1779
   324
dvander@2728
   325
	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
dvander@1779
   326
		!= HandleError_None)
dvander@1779
   327
	{
dvander@1779
   328
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@1779
   329
	}
dvander@1779
   330
dvander@1779
   331
	char *key, *val;
dvander@1779
   332
	pContext->LocalToString(params[2], &key);
dvander@1779
   333
	pContext->LocalToString(params[3], &val);
dvander@1779
   334
dvander@4096
   335
	StringHashMap<Entry>::Insert i = pTrie->map.findForAdd(key);
dvander@4096
   336
	if (!i.found())
dvander@1779
   337
	{
dvander@4096
   338
		if (!pTrie->map.add(i, key))
dvander@1779
   339
			return 0;
dvander@4096
   340
		i->value.setString(val);
dvander@1779
   341
		return 1;
dvander@1779
   342
	}
dvander@1779
   343
dvander@1779
   344
	if (!params[4])
dvander@1779
   345
		return 0;
dvander@1779
   346
dvander@4096
   347
	i->value.setString(val);
dvander@1779
   348
	return 1;
dvander@1779
   349
}
dvander@1779
   350
dvander@1779
   351
static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
dvander@1779
   352
{
dvander@1779
   353
	CellTrie *pTrie;
dvander@1779
   354
	HandleError err;
dvander@1779
   355
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@1779
   356
dvander@4096
   357
	Handle_t hndl = params[1];
dvander@1779
   358
dvander@2728
   359
	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
dvander@1779
   360
		!= HandleError_None)
dvander@1779
   361
	{
dvander@1779
   362
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@1779
   363
	}
dvander@1779
   364
dvander@1779
   365
	char *key;
dvander@1779
   366
	pContext->LocalToString(params[2], &key);
dvander@1779
   367
dvander@4096
   368
	StringHashMap<Entry>::Result r = pTrie->map.find(key);
dvander@4096
   369
	if (!r.found())
dvander@1779
   370
		return 0;
dvander@1779
   371
dvander@4096
   372
	pTrie->map.remove(r);
dvander@4096
   373
	return 1;
dvander@1779
   374
}
dvander@1779
   375
dvander@1779
   376
static cell_t ClearTrie(IPluginContext *pContext, const cell_t *params)
dvander@1779
   377
{
dvander@1779
   378
	Handle_t hndl;
dvander@1779
   379
	CellTrie *pTrie;
dvander@1779
   380
	HandleError err;
dvander@1779
   381
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@1779
   382
dvander@1779
   383
	hndl = params[1];
dvander@1779
   384
dvander@2728
   385
	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
dvander@1779
   386
		!= HandleError_None)
dvander@1779
   387
	{
dvander@1779
   388
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@1779
   389
	}
dvander@1779
   390
dvander@4096
   391
	pTrie->map.clear();
dvander@1779
   392
	return 1;
dvander@1779
   393
}
dvander@1779
   394
dvander@1779
   395
static cell_t GetTrieValue(IPluginContext *pContext, const cell_t *params)
dvander@1779
   396
{
dvander@1779
   397
	Handle_t hndl;
dvander@1779
   398
	CellTrie *pTrie;
dvander@1779
   399
	HandleError err;
dvander@1779
   400
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@1779
   401
dvander@1779
   402
	hndl = params[1];
dvander@1779
   403
dvander@2728
   404
	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
dvander@1779
   405
		!= HandleError_None)
dvander@1779
   406
	{
dvander@1779
   407
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@1779
   408
	}
dvander@1779
   409
dvander@1779
   410
	char *key;
dvander@1779
   411
	cell_t *pValue;
dvander@1779
   412
	pContext->LocalToString(params[2], &key);
dvander@1779
   413
	pContext->LocalToPhysAddr(params[3], &pValue);
dvander@1779
   414
dvander@4096
   415
	StringHashMap<Entry>::Result r = pTrie->map.find(key);
dvander@4096
   416
	if (!r.found())
dvander@4096
   417
		return 0;
dvander@4096
   418
dvander@4096
   419
	if (r->value.isCell())
dvander@1779
   420
	{
dvander@4096
   421
		*pValue = r->value.cell();
dvander@4096
   422
		return 1;
dvander@1779
   423
	}
dvander@1779
   424
dvander@4096
   425
	// Maintain compatibility with an old bug. If an array was set with one
dvander@4096
   426
	// cell, it was stored internally as a single cell. We now store as an
dvander@4096
   427
	// actual array, but we make GetTrieValue() still work for this case.
dvander@4096
   428
	if (r->value.isArray() && r->value.arrayLength() == 1)
dvander@1779
   429
	{
dvander@4096
   430
		*pValue = r->value.array()[0];
dvander@1779
   431
		return 1;
dvander@1779
   432
	}
dvander@1779
   433
	
dvander@1779
   434
	return 0;
dvander@1779
   435
}
dvander@1779
   436
dvander@1779
   437
static cell_t GetTrieArray(IPluginContext *pContext, const cell_t *params)
dvander@1779
   438
{
dvander@1779
   439
	Handle_t hndl;
dvander@1779
   440
	CellTrie *pTrie;
dvander@1779
   441
	HandleError err;
dvander@1779
   442
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@1779
   443
dvander@1779
   444
	hndl = params[1];
dvander@1779
   445
dvander@2728
   446
	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
dvander@1779
   447
		!= HandleError_None)
dvander@1779
   448
	{
dvander@1779
   449
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@1779
   450
	}
dvander@1779
   451
dvander@1779
   452
	if (params[4] < 0)
dvander@1779
   453
	{
dvander@1779
   454
		return pContext->ThrowNativeError("Invalid array size: %d", params[4]);
dvander@1779
   455
	}
dvander@1779
   456
dvander@1779
   457
	char *key;
dvander@1779
   458
	cell_t *pValue, *pSize;
dvander@1779
   459
	pContext->LocalToString(params[2], &key);
dvander@1779
   460
	pContext->LocalToPhysAddr(params[3], &pValue);
dvander@1779
   461
	pContext->LocalToPhysAddr(params[5], &pSize);
dvander@1779
   462
dvander@4096
   463
dvander@4096
   464
	StringHashMap<Entry>::Result r = pTrie->map.find(key);
dvander@4096
   465
	if (!r.found() || !r->value.isArray())
dvander@1779
   466
		return 0;
dvander@1779
   467
dvander@4096
   468
	if (!r->value.array())
dvander@1779
   469
	{
dvander@1779
   470
		*pSize = 0;
dvander@1779
   471
		return 1;
dvander@1779
   472
	}
dvander@1779
   473
dvander@4096
   474
	if (!params[4])
dvander@4096
   475
		return 1;
dvander@4096
   476
dvander@4096
   477
	size_t length = r->value.arrayLength();
dvander@4096
   478
	cell_t *base = r->value.array();
dvander@4096
   479
dvander@4096
   480
	if (length > size_t(params[4]))
dvander@1779
   481
		*pSize = params[4];
dvander@1779
   482
	else
dvander@4096
   483
		*pSize = length;
dvander@1779
   484
dvander@4096
   485
	memcpy(pValue, base, sizeof(cell_t) * pSize[0]);
dvander@1779
   486
	return 1;
dvander@1779
   487
}
dvander@1779
   488
dvander@1779
   489
static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params)
dvander@1779
   490
{
dvander@1779
   491
	Handle_t hndl;
dvander@1779
   492
	CellTrie *pTrie;
dvander@1779
   493
	HandleError err;
dvander@1779
   494
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@1779
   495
dvander@1779
   496
	hndl = params[1];
dvander@1779
   497
dvander@2728
   498
	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
dvander@1779
   499
		!= HandleError_None)
dvander@1779
   500
	{
dvander@1779
   501
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@1779
   502
	}
dvander@1779
   503
dvander@1779
   504
	if (params[4] < 0)
dvander@1779
   505
	{
dvander@1779
   506
		return pContext->ThrowNativeError("Invalid buffer size: %d", params[4]);
dvander@1779
   507
	}
dvander@1779
   508
dvander@1779
   509
	char *key;
dvander@1779
   510
	cell_t *pSize;
dvander@1779
   511
	pContext->LocalToString(params[2], &key);
dvander@1779
   512
	pContext->LocalToPhysAddr(params[5], &pSize);
dvander@1779
   513
dvander@4096
   514
	StringHashMap<Entry>::Result r = pTrie->map.find(key);
dvander@4096
   515
	if (!r.found() || !r->value.isString())
dvander@1779
   516
		return 0;
dvander@1779
   517
dvander@1779
   518
	size_t written;
dvander@4096
   519
	pContext->StringToLocalUTF8(params[3], params[4], r->value.chars(), &written);
dvander@1779
   520
dvander@1779
   521
	*pSize = (cell_t)written;
dvander@1779
   522
	return 1;
dvander@1779
   523
}
dvander@1779
   524
dvander@1829
   525
static cell_t GetTrieSize(IPluginContext *pContext, const cell_t *params)
dvander@1829
   526
{
dvander@1829
   527
	Handle_t hndl;
dvander@1829
   528
	CellTrie *pTrie;
dvander@1829
   529
	HandleError err;
dvander@1829
   530
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@1829
   531
dvander@1829
   532
	hndl = params[1];
dvander@1829
   533
dvander@2728
   534
	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
dvander@1829
   535
		!= HandleError_None)
dvander@1829
   536
	{
dvander@1829
   537
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@1829
   538
	}
dvander@1829
   539
dvander@4096
   540
	return pTrie->map.elements();
dvander@4096
   541
}
dvander@4096
   542
dvander@4096
   543
static cell_t CreateTrieSnapshot(IPluginContext *pContext, const cell_t *params)
dvander@4096
   544
{
dvander@4096
   545
	HandleError err;
dvander@4096
   546
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@4096
   547
dvander@4096
   548
	Handle_t hndl = params[1];
dvander@4096
   549
dvander@4096
   550
	CellTrie *pTrie;
dvander@4096
   551
	if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
dvander@4096
   552
		!= HandleError_None)
dvander@4096
   553
	{
dvander@4096
   554
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@4096
   555
	}
dvander@4096
   556
dvander@4096
   557
	TrieSnapshot *snapshot = new TrieSnapshot;
dvander@4096
   558
	snapshot->length = pTrie->map.elements();
dvander@4096
   559
	snapshot->keys = new int[snapshot->length];
dvander@4096
   560
	size_t i = 0;
dvander@4096
   561
	for (StringHashMap<Entry>::iterator iter = pTrie->map.iter(); !iter.empty(); iter.next(), i++)
dvander@4096
   562
		snapshot->keys[i] = snapshot->strings.AddString(iter->key.chars(), iter->key.length());
dvander@4096
   563
	assert(i == snapshot->length);
dvander@4096
   564
dvander@4096
   565
	if ((hndl = handlesys->CreateHandle(htSnapshot, snapshot, pContext->GetIdentity(), g_pCoreIdent, NULL))
dvander@4096
   566
		== BAD_HANDLE)
dvander@4096
   567
	{
dvander@4096
   568
		delete snapshot;
dvander@4096
   569
		return BAD_HANDLE;
dvander@4096
   570
	}
dvander@4096
   571
dvander@4096
   572
	return hndl;
dvander@4096
   573
}
dvander@4096
   574
dvander@4096
   575
static cell_t TrieSnapshotLength(IPluginContext *pContext, const cell_t *params)
dvander@4096
   576
{
dvander@4096
   577
	HandleError err;
dvander@4096
   578
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@4096
   579
dvander@4096
   580
	Handle_t hndl = params[1];
dvander@4096
   581
dvander@4096
   582
	TrieSnapshot *snapshot;
dvander@4096
   583
	if ((err = handlesys->ReadHandle(hndl, htSnapshot, &sec, (void **)&snapshot))
dvander@4096
   584
		!= HandleError_None)
dvander@4096
   585
	{
dvander@4096
   586
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@4096
   587
	}
dvander@4096
   588
dvander@4096
   589
	return snapshot->length;
dvander@4096
   590
}
dvander@4096
   591
dvander@4096
   592
static cell_t TrieSnapshotKeyBufferSize(IPluginContext *pContext, const cell_t *params)
dvander@4096
   593
{
dvander@4096
   594
	HandleError err;
dvander@4096
   595
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@4096
   596
dvander@4096
   597
	Handle_t hndl = params[1];
dvander@4096
   598
dvander@4096
   599
	TrieSnapshot *snapshot;
dvander@4096
   600
	if ((err = handlesys->ReadHandle(hndl, htSnapshot, &sec, (void **)&snapshot))
dvander@4096
   601
		!= HandleError_None)
dvander@4096
   602
	{
dvander@4096
   603
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@4096
   604
	}
dvander@4096
   605
dvander@4096
   606
	unsigned index = params[2];
dvander@4096
   607
	if (index >= snapshot->length)
dvander@4096
   608
		return pContext->ThrowNativeError("Invalid index %d", index);
dvander@4096
   609
dvander@4096
   610
	return strlen(snapshot->strings.GetString(snapshot->keys[index])) + 1;
dvander@4096
   611
}
dvander@4096
   612
dvander@4096
   613
static cell_t GetTrieSnapshotKey(IPluginContext *pContext, const cell_t *params)
dvander@4096
   614
{
dvander@4096
   615
	HandleError err;
dvander@4096
   616
	HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
dvander@4096
   617
dvander@4096
   618
	Handle_t hndl = params[1];
dvander@4096
   619
dvander@4096
   620
	TrieSnapshot *snapshot;
dvander@4096
   621
	if ((err = handlesys->ReadHandle(hndl, htSnapshot, &sec, (void **)&snapshot))
dvander@4096
   622
		!= HandleError_None)
dvander@4096
   623
	{
dvander@4096
   624
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
dvander@4096
   625
	}
dvander@4096
   626
dvander@4096
   627
	unsigned index = params[2];
dvander@4096
   628
	if (index >= snapshot->length)
dvander@4096
   629
		return pContext->ThrowNativeError("Invalid index %d", index);
dvander@4096
   630
dvander@4096
   631
	size_t written;
dvander@4096
   632
	const char *str = snapshot->strings.GetString(snapshot->keys[index]);
dvander@4096
   633
	pContext->StringToLocalUTF8(params[3], params[4], str, &written);
dvander@4096
   634
	return written;
dvander@1829
   635
}
dvander@1829
   636
dvander@1779
   637
REGISTER_NATIVES(trieNatives)
dvander@1779
   638
{
dvander@1779
   639
	{"ClearTrie",				ClearTrie},
dvander@1779
   640
	{"CreateTrie",				CreateTrie},
dvander@1779
   641
	{"GetTrieArray",			GetTrieArray},
dvander@1779
   642
	{"GetTrieString",			GetTrieString},
dvander@1779
   643
	{"GetTrieValue",			GetTrieValue},
dvander@1779
   644
	{"RemoveFromTrie",			RemoveFromTrie},
dvander@1779
   645
	{"SetTrieArray",			SetTrieArray},
dvander@1779
   646
	{"SetTrieString",			SetTrieString},
dvander@1779
   647
	{"SetTrieValue",			SetTrieValue},
dvander@1829
   648
	{"GetTrieSize",				GetTrieSize},
dvander@4096
   649
	{"CreateTrieSnapshot",		CreateTrieSnapshot},
dvander@4096
   650
	{"TrieSnapshotLength",		TrieSnapshotLength},
dvander@4096
   651
	{"TrieSnapshotKeyBufferSize", TrieSnapshotKeyBufferSize},
dvander@4096
   652
	{"GetTrieSnapshotKey",		GetTrieSnapshotKey},
dvander@1779
   653
	{NULL,						NULL},
dvander@1779
   654
};