diff --git a/core/logic/smn_adt_trie.cpp b/core/logic/smn_adt_trie.cpp index e936f6f2..1b0e7b41 100644 --- a/core/logic/smn_adt_trie.cpp +++ b/core/logic/smn_adt_trie.cpp @@ -636,6 +636,56 @@ static cell_t GetTrieSnapshotKey(IPluginContext *pContext, const cell_t *params) return written; } +static cell_t CloneTrie(IPluginContext *pContext, const cell_t *params) +{ + HandleError err; + HandleSecurity sec = HandleSecurity(pContext->GetIdentity(), g_pCoreIdent); + + CellTrie *pOldTrie; + if ((err = handlesys->ReadHandle(params[1], htCellTrie, &sec, (void **)&pOldTrie)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err); + } + + CellTrie *pNewTrie = new CellTrie; + Handle_t hndl = handlesys->CreateHandle(htCellTrie, pNewTrie, pContext->GetIdentity(), g_pCoreIdent, NULL); + if (!hndl) + { + delete pNewTrie; + return hndl; + } + + for (StringHashMap::iterator it = pOldTrie->map.iter(); !it.empty(); it.next()) + { + const char *key = it->key.c_str(); + StringHashMap::Insert insert = pNewTrie->map.findForAdd(key); + if (pNewTrie->map.add(insert, key)) + { + StringHashMap::Result result = pOldTrie->map.find(key); + if (result->value.isCell()) + { + insert->value.setCell(result->value.cell()); + } + else if (result->value.isString()) + { + insert->value.setString(result->value.c_str()); + } + else if (result->value.isArray()) + { + insert->value.setArray(result->value.array(), result->value.arrayLength()); + } + else + { + handlesys->FreeHandle(hndl, NULL); + return pContext->ThrowNativeError("Unhandled data type encountered, file a bug and reference pr #852"); + } + } + } + + return hndl; +} + REGISTER_NATIVES(trieNatives) { {"ClearTrie", ClearTrie}, @@ -666,6 +716,7 @@ REGISTER_NATIVES(trieNatives) {"StringMap.SetValue", SetTrieValue}, {"StringMap.Size.get", GetTrieSize}, {"StringMap.Snapshot", CreateTrieSnapshot}, + {"StringMap.Clone", CloneTrie}, {"StringMapSnapshot.Length.get", TrieSnapshotLength}, {"StringMapSnapshot.KeyBufferSize", TrieSnapshotKeyBufferSize}, diff --git a/plugins/include/adt_trie.inc b/plugins/include/adt_trie.inc index 43164acc..9de455d8 100644 --- a/plugins/include/adt_trie.inc +++ b/plugins/include/adt_trie.inc @@ -52,6 +52,14 @@ methodmap StringMap < Handle // The StringMap must be freed via delete or CloseHandle(). public native StringMap(); + // Clones a string map, returning a new handle with the same size and data. + // This should NOT be confused with CloneHandle. This is a completely new + // handle with the same data but no relation to the original. It should be + // closed when no longer needed with delete or CloseHandle(). + // + // @return New handle to the cloned string map + public native StringMap Clone(); + // Sets a value in a hash map, either inserting a new entry or replacing an old one. // // @param key Key string. diff --git a/public/sm_trie_tpl.h b/public/sm_trie_tpl.h index 37f4ce4e..79098e9c 100644 --- a/public/sm_trie_tpl.h +++ b/public/sm_trie_tpl.h @@ -48,7 +48,7 @@ enum NodeType * @brief DEPRECATED. This class scales extremely poorly; insertion scales * quadratic (O(n^2)) with respect to the number of elements in the table. * Only use this class if you have less than 200 elements or so. Otherwise, - * use StringHashMap in sm_hashtable.h which scales linearly and has comparable + * use StringHashMap in sm_stringhashmap.h which scales linearly and has comparable * retrievable performance. * * See bug 5878 for more detail.