diff --git a/core/sm_trie.cpp b/core/sm_trie.cpp index 899ccd60..fcc9dd5c 100644 --- a/core/sm_trie.cpp +++ b/core/sm_trie.cpp @@ -90,3 +90,32 @@ size_t sm_trie_mem_usage(Trie *trie) { return trie->k.mem_usage(); } + +struct trie_iter_data +{ + SM_TRIE_BAD_ITERATOR iter; + void *ptr; + Trie *pTrie; +}; + +void our_trie_iterator(KTrie *pTrie, const char *name, void *& obj, void *data) +{ + trie_iter_data *our_iter; + + our_iter = (trie_iter_data *)data; + our_iter->iter(our_iter->pTrie, name, &obj, our_iter->ptr); +} + +void sm_trie_bad_iterator(Trie *trie, + char *buffer, + size_t maxlength, + SM_TRIE_BAD_ITERATOR iter, + void *data) +{ + trie_iter_data our_iter; + + our_iter.iter = iter; + our_iter.ptr = data; + our_iter.pTrie = trie; + trie->k.bad_iterator(buffer, maxlength, &our_iter, our_trie_iterator); +} diff --git a/core/sm_trie.h b/core/sm_trie.h index 6e25fbd1..263bef94 100644 --- a/core/sm_trie.h +++ b/core/sm_trie.h @@ -34,6 +34,8 @@ struct Trie; +typedef void (*SM_TRIE_BAD_ITERATOR)(Trie *pTrie, const char *key, void **value, void *data); + Trie *sm_trie_create(); void sm_trie_destroy(Trie *trie); bool sm_trie_insert(Trie *trie, const char *key, void *value); @@ -42,5 +44,10 @@ bool sm_trie_retrieve(Trie *trie, const char *key, void **value); bool sm_trie_delete(Trie *trie, const char *key); void sm_trie_clear(Trie *trie); size_t sm_trie_mem_usage(Trie *trie); +void sm_trie_bad_iterator(Trie *trie, + char *buffer, + size_t maxlength, + SM_TRIE_BAD_ITERATOR iter, + void *data); #endif //_INCLUDE_SOURCEMOD_SIMPLE_TRIE_H_ diff --git a/public/sm_trie_tpl.h b/public/sm_trie_tpl.h index 5018c8a2..ee2ef183 100644 --- a/public/sm_trie_tpl.h +++ b/public/sm_trie_tpl.h @@ -648,6 +648,117 @@ public: return false; } + + /** + * @brief Iterates over the trie returning all known values. + * + * Note: This function is for debugging. Do not use it as a + * production iterator since it's inefficient. Iteration is + * guaranteed to be sorted ascendingly. + * + * The callback function takes: + * (KTrie) - Pointer to this Trie + * (const char *) - String containing key name. + * (K &) - By-reference object at the key. + * (data) - User pointer. + * + * @param buffer Buffer to use as a key name cache. + * @param maxlength Maximum length of the key name buffer. + * @param data User pointer for passing to the iterator. + * @param func Iterator callback function. + */ + void bad_iterator(char *buffer, + size_t maxlength, + void *data, + void (*func)(KTrie *, const char *, K & obj, void *data)) + { + bad_iterator_r(buffer, maxlength, 0, data, func, 1); + } + +private: + void bad_iterator_r(char *buffer, + size_t maxlength, + size_t buf_pos, + void *data, + void (*func)(KTrie *, const char *, K & obj, void *data), + unsigned int root) + { + char *term; + unsigned int idx, limit, start; + + limit = 255; + start = m_base[root].idx; + + /* Bound our limits */ + if (start + limit > m_baseSize) + { + limit = m_baseSize - start; + } + + /* Search for strings */ + for (unsigned int i = 1; i <= limit; i++) + { + idx = start + i; + if (m_base[idx].mode == Node_Unused + || m_base[idx].parent != root) + { + continue; + } + + if (m_base[idx].mode == Node_Arc) + { + if (buf_pos < maxlength - 1) + { + buffer[buf_pos++] = (char)i; + } + + if (m_base[idx].valset) + { + buffer[buf_pos] = '\0'; + func(this, buffer, m_base[idx].value, data); + } + + bad_iterator_r(buffer, + maxlength, + buf_pos, + data, + func, + idx); + + buf_pos--; + } + else if (m_base[idx].mode == Node_Term + && m_base[idx].valset == true) + { + size_t save_buf_pos; + + save_buf_pos = buf_pos; + if (buf_pos < maxlength - 1) + { + buffer[buf_pos++] = (char)i; + } + if (buf_pos < maxlength - 1) + { + size_t destlen, j; + + term = &m_stringtab[m_base[idx].idx]; + destlen = strlen(term); + for (j = 0; + j < destlen && j + buf_pos < maxlength - 1; + j++) + { + buffer[buf_pos + j] = term[j]; + } + buf_pos += j; + } + buffer[buf_pos] = '\0'; + + func(this, buffer, m_base[idx].value, data); + + buf_pos = save_buf_pos; + } + } + } public: KTrie() {