3 * =============================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
33 #include "sm_globals.h"
34 #include "sm_stringutil.h"
35 #include "HandleSys.h"
36 #include "sm_trie_tpl.h"
38 HandleType_t htCellTrie;
54 SmartTrieNode(const SmartTrieNode &obj)
59 data_len = obj.data_len;
61 SmartTrieNode & operator =(const SmartTrieNode &src)
66 data_len = src.data_len;
77 KTrie<SmartTrieNode> trie;
83 public IHandleTypeDispatch
85 public: //SMGlobalClass
86 void OnSourceModAllInitialized()
88 htCellTrie = g_HandleSys.CreateType("Trie", this, 0, NULL, NULL, g_pCoreIdent, NULL);
90 void OnSourceModShutdown()
92 g_HandleSys.RemoveType(htCellTrie, g_pCoreIdent);
94 public: //IHandleTypeDispatch
95 static void DestroySmartTrieNode(SmartTrieNode *pNode)
99 void OnHandleDestroy(HandleType_t type, void *object)
101 CellTrie *pTrie = (CellTrie *)object;
103 pTrie->trie.run_destructor(DestroySmartTrieNode);
107 bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
109 CellTrie *pArray = (CellTrie *)object;
110 *pSize = sizeof(CellTrie) + pArray->mem_usage + pArray->trie.mem_usage();
115 static cell_t CreateTrie(IPluginContext *pContext, const cell_t *params)
117 CellTrie *pTrie = new CellTrie;
120 pTrie->mem_usage = 0;
122 if ((hndl = g_HandleSys.CreateHandle(htCellTrie, pTrie, pContext->GetIdentity(), g_pCoreIdent, NULL))
132 static void UpdateNodeCells(CellTrie *pTrie, SmartTrieNode *pData, const cell_t *cells, cell_t num_cells)
136 pData->data = *cells;
137 pData->type = TrieNode_Cell;
141 pData->type = TrieNode_CellArray;
142 if (pData->ptr == NULL)
144 pData->ptr = (cell_t *)malloc(num_cells * sizeof(cell_t));
145 pData->data_len = num_cells;
146 pTrie->mem_usage += (pData->data_len * sizeof(cell_t));
148 else if (pData->data_len < num_cells)
150 pData->ptr = (cell_t *)realloc(pData->ptr, num_cells * sizeof(cell_t));
151 pTrie->mem_usage += (num_cells - pData->data_len) * sizeof(cell_t);
152 pData->data_len = num_cells;
156 memcpy(pData->ptr, cells, sizeof(cell_t) * num_cells);
158 pData->data = num_cells;
162 static void UpdateNodeString(CellTrie *pTrie, SmartTrieNode *pData, const char *str)
164 size_t len = strlen(str);
165 cell_t num_cells = (len + sizeof(cell_t)) / sizeof(cell_t);
167 if (pData->ptr == NULL)
169 pData->ptr = (cell_t *)malloc(num_cells * sizeof(cell_t));
170 pData->data_len = num_cells;
171 pTrie->mem_usage += (pData->data_len * sizeof(cell_t));
173 else if (pData->data_len < num_cells)
175 pData->ptr = (cell_t *)realloc(pData->ptr, num_cells * sizeof(cell_t));
176 pTrie->mem_usage += (num_cells - pData->data_len) * sizeof(cell_t);
177 pData->data_len = num_cells;
180 strcpy((char *)pData->ptr, str);
182 pData->type = TrieNode_String;
185 static cell_t SetTrieValue(IPluginContext *pContext, const cell_t *params)
190 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
194 if ((err = g_HandleSys.ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
197 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
201 pContext->LocalToString(params[2], &key);
203 SmartTrieNode *pNode;
204 if ((pNode = pTrie->trie.retrieve(key)) == NULL)
207 UpdateNodeCells(pTrie, &node, ¶ms[3], 1);
208 return pTrie->trie.insert(key, node) ? 1 : 0;
216 UpdateNodeCells(pTrie, pNode, ¶ms[3], 1);
221 static cell_t SetTrieArray(IPluginContext *pContext, const cell_t *params)
226 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
230 if ((err = g_HandleSys.ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
233 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
238 return pContext->ThrowNativeError("Invalid array size: %d", params[4]);
243 pContext->LocalToString(params[2], &key);
244 pContext->LocalToPhysAddr(params[3], &array);
246 SmartTrieNode *pNode;
247 if ((pNode = pTrie->trie.retrieve(key)) == NULL)
250 UpdateNodeCells(pTrie, &node, array, params[4]);
251 if (!pTrie->trie.insert(key, node))
264 UpdateNodeCells(pTrie, pNode, array, params[4]);
269 static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params)
274 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
278 if ((err = g_HandleSys.ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
281 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
285 pContext->LocalToString(params[2], &key);
286 pContext->LocalToString(params[3], &val);
288 SmartTrieNode *pNode;
289 if ((pNode = pTrie->trie.retrieve(key)) == NULL)
292 UpdateNodeString(pTrie, &node, val);
293 if (!pTrie->trie.insert(key, node))
306 UpdateNodeString(pTrie, pNode, val);
311 static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
316 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
320 if ((err = g_HandleSys.ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
323 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
327 pContext->LocalToString(params[2], &key);
329 SmartTrieNode *pNode;
330 if ((pNode = pTrie->trie.retrieve(key)) == NULL)
338 return pTrie->trie.remove(key) ? 1 : 0;
341 static cell_t ClearTrie(IPluginContext *pContext, const cell_t *params)
346 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
350 if ((err = g_HandleSys.ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
353 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
356 pTrie->trie.run_destructor(TrieHelpers::DestroySmartTrieNode);
362 static cell_t GetTrieValue(IPluginContext *pContext, const cell_t *params)
367 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
371 if ((err = g_HandleSys.ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
374 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
379 pContext->LocalToString(params[2], &key);
380 pContext->LocalToPhysAddr(params[3], &pValue);
382 SmartTrieNode *pNode;
383 if ((pNode = pTrie->trie.retrieve(key)) == NULL)
388 if (pNode->type == TrieNode_Cell)
390 *pValue = pNode->data;
397 static cell_t GetTrieArray(IPluginContext *pContext, const cell_t *params)
402 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
406 if ((err = g_HandleSys.ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
409 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
414 return pContext->ThrowNativeError("Invalid array size: %d", params[4]);
418 cell_t *pValue, *pSize;
419 pContext->LocalToString(params[2], &key);
420 pContext->LocalToPhysAddr(params[3], &pValue);
421 pContext->LocalToPhysAddr(params[5], &pSize);
423 SmartTrieNode *pNode;
424 if ((pNode = pTrie->trie.retrieve(key)) == NULL
425 || pNode->type != TrieNode_CellArray)
430 if (pNode->ptr == NULL)
436 if (pNode->data > params[4])
440 else if (params[4] != 0)
442 *pSize = pNode->data;
449 memcpy(pValue, pNode->ptr, sizeof(cell_t) * pSize[0]);
454 static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params)
459 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
463 if ((err = g_HandleSys.ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
466 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
471 return pContext->ThrowNativeError("Invalid buffer size: %d", params[4]);
476 pContext->LocalToString(params[2], &key);
477 pContext->LocalToPhysAddr(params[5], &pSize);
479 SmartTrieNode *pNode;
480 if ((pNode = pTrie->trie.retrieve(key)) == NULL
481 || pNode->type != TrieNode_String)
486 if (pNode->ptr == NULL)
489 pContext->StringToLocal(params[3], params[4], "");
494 pContext->StringToLocalUTF8(params[3], params[4], (char *)pNode->ptr, &written);
496 *pSize = (cell_t)written;
501 REGISTER_NATIVES(trieNatives)
503 {"ClearTrie", ClearTrie},
504 {"CreateTrie", CreateTrie},
505 {"GetTrieArray", GetTrieArray},
506 {"GetTrieString", GetTrieString},
507 {"GetTrieValue", GetTrieValue},
508 {"RemoveFromTrie", RemoveFromTrie},
509 {"SetTrieArray", SetTrieArray},
510 {"SetTrieString", SetTrieString},
511 {"SetTrieValue", SetTrieValue},