3 * =============================================================================
5 * Copyright (C) 2004-2008 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 "common_logic.h"
34 #include <sm_trie_tpl.h>
36 HandleType_t htCellTrie;
52 SmartTrieNode(const SmartTrieNode &obj)
57 data_len = obj.data_len;
59 SmartTrieNode & operator =(const SmartTrieNode &src)
64 data_len = src.data_len;
75 KTrie<SmartTrieNode> trie;
81 public IHandleTypeDispatch
83 public: //SMGlobalClass
84 void OnSourceModAllInitialized()
86 htCellTrie = handlesys->CreateType("Trie", this, 0, NULL, NULL, g_pCoreIdent, NULL);
88 void OnSourceModShutdown()
90 handlesys->RemoveType(htCellTrie, g_pCoreIdent);
92 public: //IHandleTypeDispatch
93 static void DestroySmartTrieNode(SmartTrieNode *pNode)
97 void OnHandleDestroy(HandleType_t type, void *object)
99 CellTrie *pTrie = (CellTrie *)object;
101 pTrie->trie.run_destructor(DestroySmartTrieNode);
105 bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
107 CellTrie *pArray = (CellTrie *)object;
108 *pSize = sizeof(CellTrie) + pArray->mem_usage + pArray->trie.mem_usage();
113 static cell_t CreateTrie(IPluginContext *pContext, const cell_t *params)
115 CellTrie *pTrie = new CellTrie;
118 pTrie->mem_usage = 0;
120 if ((hndl = handlesys->CreateHandle(htCellTrie, pTrie, pContext->GetIdentity(), g_pCoreIdent, NULL))
130 static void UpdateNodeCells(CellTrie *pTrie, SmartTrieNode *pData, const cell_t *cells, cell_t num_cells)
134 pData->data = *cells;
135 pData->type = TrieNode_Cell;
139 pData->type = TrieNode_CellArray;
140 if (pData->ptr == NULL)
142 pData->ptr = (cell_t *)malloc(num_cells * sizeof(cell_t));
143 pData->data_len = num_cells;
144 pTrie->mem_usage += (pData->data_len * sizeof(cell_t));
146 else if (pData->data_len < num_cells)
148 pData->ptr = (cell_t *)realloc(pData->ptr, num_cells * sizeof(cell_t));
149 pTrie->mem_usage += (num_cells - pData->data_len) * sizeof(cell_t);
150 pData->data_len = num_cells;
154 memcpy(pData->ptr, cells, sizeof(cell_t) * num_cells);
156 pData->data = num_cells;
160 static void UpdateNodeString(CellTrie *pTrie, SmartTrieNode *pData, const char *str)
162 size_t len = strlen(str);
163 cell_t num_cells = (len + sizeof(cell_t)) / sizeof(cell_t);
165 if (pData->ptr == NULL)
167 pData->ptr = (cell_t *)malloc(num_cells * sizeof(cell_t));
168 pData->data_len = num_cells;
169 pTrie->mem_usage += (pData->data_len * sizeof(cell_t));
171 else if (pData->data_len < num_cells)
173 pData->ptr = (cell_t *)realloc(pData->ptr, num_cells * sizeof(cell_t));
174 pTrie->mem_usage += (num_cells - pData->data_len) * sizeof(cell_t);
175 pData->data_len = num_cells;
178 strcpy((char *)pData->ptr, str);
180 pData->type = TrieNode_String;
183 static cell_t SetTrieValue(IPluginContext *pContext, const cell_t *params)
188 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
192 if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
195 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
199 pContext->LocalToString(params[2], &key);
201 SmartTrieNode *pNode;
202 if ((pNode = pTrie->trie.retrieve(key)) == NULL)
205 UpdateNodeCells(pTrie, &node, ¶ms[3], 1);
206 return pTrie->trie.insert(key, node) ? 1 : 0;
214 UpdateNodeCells(pTrie, pNode, ¶ms[3], 1);
219 static cell_t SetTrieArray(IPluginContext *pContext, const cell_t *params)
224 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
228 if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
231 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
236 return pContext->ThrowNativeError("Invalid array size: %d", params[4]);
241 pContext->LocalToString(params[2], &key);
242 pContext->LocalToPhysAddr(params[3], &array);
244 SmartTrieNode *pNode;
245 if ((pNode = pTrie->trie.retrieve(key)) == NULL)
248 UpdateNodeCells(pTrie, &node, array, params[4]);
249 if (!pTrie->trie.insert(key, node))
262 UpdateNodeCells(pTrie, pNode, array, params[4]);
267 static cell_t SetTrieString(IPluginContext *pContext, const cell_t *params)
272 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
276 if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
279 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
283 pContext->LocalToString(params[2], &key);
284 pContext->LocalToString(params[3], &val);
286 SmartTrieNode *pNode;
287 if ((pNode = pTrie->trie.retrieve(key)) == NULL)
290 UpdateNodeString(pTrie, &node, val);
291 if (!pTrie->trie.insert(key, node))
304 UpdateNodeString(pTrie, pNode, val);
309 static cell_t RemoveFromTrie(IPluginContext *pContext, const cell_t *params)
314 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
318 if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
321 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
325 pContext->LocalToString(params[2], &key);
327 SmartTrieNode *pNode;
328 if ((pNode = pTrie->trie.retrieve(key)) == NULL)
336 return pTrie->trie.remove(key) ? 1 : 0;
339 static cell_t ClearTrie(IPluginContext *pContext, const cell_t *params)
344 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
348 if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
351 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
354 pTrie->trie.run_destructor(TrieHelpers::DestroySmartTrieNode);
360 static cell_t GetTrieValue(IPluginContext *pContext, const cell_t *params)
365 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
369 if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
372 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
377 pContext->LocalToString(params[2], &key);
378 pContext->LocalToPhysAddr(params[3], &pValue);
380 SmartTrieNode *pNode;
381 if ((pNode = pTrie->trie.retrieve(key)) == NULL)
386 if (pNode->type == TrieNode_Cell)
388 *pValue = pNode->data;
395 static cell_t GetTrieArray(IPluginContext *pContext, const cell_t *params)
400 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
404 if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
407 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
412 return pContext->ThrowNativeError("Invalid array size: %d", params[4]);
416 cell_t *pValue, *pSize;
417 pContext->LocalToString(params[2], &key);
418 pContext->LocalToPhysAddr(params[3], &pValue);
419 pContext->LocalToPhysAddr(params[5], &pSize);
421 SmartTrieNode *pNode;
422 if ((pNode = pTrie->trie.retrieve(key)) == NULL
423 || pNode->type != TrieNode_CellArray)
428 if (pNode->ptr == NULL)
434 if (pNode->data > params[4])
438 else if (params[4] != 0)
440 *pSize = pNode->data;
447 memcpy(pValue, pNode->ptr, sizeof(cell_t) * pSize[0]);
452 static cell_t GetTrieString(IPluginContext *pContext, const cell_t *params)
457 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
461 if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
464 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
469 return pContext->ThrowNativeError("Invalid buffer size: %d", params[4]);
474 pContext->LocalToString(params[2], &key);
475 pContext->LocalToPhysAddr(params[5], &pSize);
477 SmartTrieNode *pNode;
478 if ((pNode = pTrie->trie.retrieve(key)) == NULL
479 || pNode->type != TrieNode_String)
484 if (pNode->ptr == NULL)
487 pContext->StringToLocal(params[3], params[4], "");
492 pContext->StringToLocalUTF8(params[3], params[4], (char *)pNode->ptr, &written);
494 *pSize = (cell_t)written;
499 static cell_t GetTrieSize(IPluginContext *pContext, const cell_t *params)
504 HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent);
508 if ((err = handlesys->ReadHandle(hndl, htCellTrie, &sec, (void **)&pTrie))
511 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", hndl, err);
514 return pTrie->trie.size();
517 REGISTER_NATIVES(trieNatives)
519 {"ClearTrie", ClearTrie},
520 {"CreateTrie", CreateTrie},
521 {"GetTrieArray", GetTrieArray},
522 {"GetTrieString", GetTrieString},
523 {"GetTrieValue", GetTrieValue},
524 {"RemoveFromTrie", RemoveFromTrie},
525 {"SetTrieArray", SetTrieArray},
526 {"SetTrieString", SetTrieString},
527 {"SetTrieValue", SetTrieValue},
528 {"GetTrieSize", GetTrieSize},