moved trie to public so extensions can use it easier
authorDavid Anderson <dvander@alliedmods.net>
Wed Aug 29 05:22:47 2007 +0000 (2007-08-29)
changeset 1390287480a3f664
parent 1389 6a1fbf893f83
child 1391 ae2ae57ccccf
moved trie to public so extensions can use it easier
core/sm_trie.cpp
core/sm_trie_tpl.h
public/sm_trie_tpl.h
     1.1 --- a/core/sm_trie.cpp	Wed Aug 29 05:20:48 2007 +0000
     1.2 +++ b/core/sm_trie.cpp	Wed Aug 29 05:22:47 2007 +0000
     1.3 @@ -31,8 +31,8 @@
     1.4  
     1.5  #include <string.h>
     1.6  #include <assert.h>
     1.7 +#include <sm_trie_tpl.h>
     1.8  #include "sm_trie.h"
     1.9 -#include "sm_trie_tpl.h"
    1.10  
    1.11  struct Trie
    1.12  {
     2.1 --- a/core/sm_trie_tpl.h	Wed Aug 29 05:20:48 2007 +0000
     2.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.3 @@ -1,898 +0,0 @@
     2.4 -/**
     2.5 - * vim: set ts=4 :
     2.6 - * =============================================================================
     2.7 - * SourceMod
     2.8 - * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     2.9 - * =============================================================================
    2.10 - *
    2.11 - * This program is free software; you can redistribute it and/or modify it under
    2.12 - * the terms of the GNU General Public License, version 3.0, as published by the
    2.13 - * Free Software Foundation.
    2.14 - * 
    2.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
    2.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    2.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    2.18 - * details.
    2.19 - *
    2.20 - * You should have received a copy of the GNU General Public License along with
    2.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
    2.22 - *
    2.23 - * As a special exception, AlliedModders LLC gives you permission to link the
    2.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
    2.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    2.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
    2.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
    2.28 - * this exception to all derivative works.  AlliedModders LLC defines further
    2.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    2.30 - * or <http://www.sourcemod.net/license.php>.
    2.31 - *
    2.32 - * Version: $Id$
    2.33 - */
    2.34 -
    2.35 -#ifndef _INCLUDE_SOURCEMOD_TEMPLATED_TRIE_H_
    2.36 -#define _INCLUDE_SOURCEMOD_TEMPLATED_TRIE_H_
    2.37 -
    2.38 -#include <new>
    2.39 -#include <string.h>
    2.40 -#include <malloc.h>
    2.41 -#include <assert.h>
    2.42 -
    2.43 -enum NodeType
    2.44 -{
    2.45 -	Node_Unused = 0,		/* Node is not being used (sparse) */
    2.46 -	Node_Arc,				/* Node is part of an arc and does not terminate */
    2.47 -	Node_Term,				/* Node is a terminator */
    2.48 -};
    2.49 -
    2.50 -/**
    2.51 - * @brief Trie algorithm based on "Double Array Trie" algorith.
    2.52 - * @file sm_trie_tpl.h
    2.53 - *
    2.54 - * For full works cited and implementation overview, there is a big comment 
    2.55 - * block at the bottom of this file.
    2.56 - */
    2.57 -
    2.58 -template <typename K>
    2.59 -class KTrie
    2.60 -{
    2.61 -	class KTrieNode;
    2.62 -public:
    2.63 -	/**
    2.64 -	 * @brief Clears all set objects in the trie.
    2.65 -	 */
    2.66 -	void clear()
    2.67 -	{
    2.68 -		run_destructors();
    2.69 -		internal_clear();
    2.70 -	}
    2.71 -
    2.72 -	/**
    2.73 -	 * @brief Removes a key from the trie.
    2.74 -	 *
    2.75 -	 * @param key		Key to remove.
    2.76 -	 * @return			True on success, false if key was never set.
    2.77 -	 */
    2.78 -	bool remove(const char *key)
    2.79 -	{
    2.80 -		KTrieNode *node = internal_retrieve(key);
    2.81 -		if (!node || !node->valset)
    2.82 -		{
    2.83 -			return false;
    2.84 -		}
    2.85 -
    2.86 -		node->value.~K();
    2.87 -		node->valset = false;
    2.88 -
    2.89 -		return true;
    2.90 -	}
    2.91 -
    2.92 -	/**
    2.93 -	 * @brief Retrieves a pointer to the object stored at a given key.
    2.94 -	 *
    2.95 -	 * @param key		Key to retrieve.
    2.96 -	 * @return			Pointer to object, or NULL if key was not found or not set.
    2.97 -	 */
    2.98 -	K * retrieve(const char *key)
    2.99 -	{
   2.100 -		KTrieNode *node = internal_retrieve(key);
   2.101 -		if (!node || !node->valset)
   2.102 -		{
   2.103 -			return NULL;
   2.104 -		}
   2.105 -		return &node->value;
   2.106 -	}
   2.107 -
   2.108 -	/**
   2.109 -	 * @brief Inserts or updates the object stored at a key.
   2.110 -	 *
   2.111 -	 * @param key		Key to update or insert.
   2.112 -	 * @param obj		Object to store at the key.
   2.113 -	 * @return			True on success, false on failure.
   2.114 -	 */
   2.115 -	bool replace(const char *key, const K & obj)
   2.116 -	{
   2.117 -		KTrieNode *prev_node = internal_retrieve(key);
   2.118 -		if (!prev_node)
   2.119 -		{
   2.120 -			return insert(key, obj);
   2.121 -		}
   2.122 -
   2.123 -		if (prev_node->valset)
   2.124 -		{
   2.125 -			prev_node->value.~K();
   2.126 -		}
   2.127 -
   2.128 -		new (&prev_node->value) K(obj);
   2.129 -
   2.130 -		return true;
   2.131 -	}
   2.132 -
   2.133 -	/**
   2.134 -	 * @brief Inserts an object at a key.
   2.135 -	 *
   2.136 -	 * @param key		Key to insert at.
   2.137 -	 * @param obj		Object to store at the key.
   2.138 -	 * @return			True on success, false if the key is already set or 
   2.139 -	 *					insertion otherwise failed.
   2.140 -	 */
   2.141 -	bool insert(const char *key, const K & obj)
   2.142 -	{
   2.143 -		unsigned int lastidx = 1;		/* the last node index */
   2.144 -		unsigned int curidx;			/* current node index */
   2.145 -		const char *keyptr = key;		/* input stream at current token */
   2.146 -		KTrieNode *node = NULL;			/* current node being processed */
   2.147 -		KTrieNode *basenode = NULL;		/* current base node being processed */
   2.148 -		unsigned int q;					/* temporary var for x_check results */
   2.149 -		unsigned int curoffs;			/* current offset */
   2.150 -
   2.151 -		/* Do not handle empty strings for simplicity */
   2.152 -		if (!*key)
   2.153 -		{
   2.154 -			return false;
   2.155 -		}
   2.156 -
   2.157 -		/* Start traversing at the root node (1) */
   2.158 -		do
   2.159 -		{
   2.160 -			/* Find where the next character is, then advance */
   2.161 -			curidx = m_base[lastidx].idx;
   2.162 -			basenode = &m_base[curidx];
   2.163 -			curoffs = charval(*keyptr);
   2.164 -			curidx += curoffs;
   2.165 -			node = &m_base[curidx];
   2.166 -			keyptr++;
   2.167 -
   2.168 -			/* Check if this slot is supposed to be empty.  If so, we need to handle CASES 1/2:
   2.169 -			 * Insertion without collisions
   2.170 -			 */
   2.171 -			if ( (curidx > m_baseSize) || (node->mode == Node_Unused) )
   2.172 -			{
   2.173 -				if (curidx > m_baseSize)
   2.174 -				{
   2.175 -					if (!grow())
   2.176 -					{
   2.177 -						return false;
   2.178 -					}
   2.179 -					node = &m_base[curidx];
   2.180 -				}
   2.181 -				node->parent = lastidx;
   2.182 -				if (*keyptr == '\0')
   2.183 -				{
   2.184 -					node->mode = Node_Arc;
   2.185 -				} else {
   2.186 -					node->idx = x_addstring(keyptr);
   2.187 -					node->mode = Node_Term;
   2.188 -				}
   2.189 -				node->valset = true;
   2.190 -				new (&node->value) K(obj);
   2.191 -
   2.192 -				return true;
   2.193 -			} else if (node->parent != lastidx) {
   2.194 -				/* Collision! We have to split up the tree here.  CASE 4:
   2.195 -				 * Insertion when a new word is inserted with a collision.
   2.196 -				 * NOTE: This is the hardest case to handle.  All below examples are based on:
   2.197 -				 * BACHELOR, BADGE, inserting BABY.
   2.198 -				 * The problematic production here is A -> B, where B is already being used.
   2.199 -			     *
   2.200 -				 * This process has to rotate one half of the 'A' arc.  We generate two lists:
   2.201 -				 *  Outgoing Arcs - Anything leaving this 'A'
   2.202 -				 *  Incoming Arcs - Anything going to this 'A'
   2.203 -				 * Whichever list is smaller will be moved.  Note that this works because the intersection
   2.204 -				 * affects both arc chains, and moving one will make the slot available to either.
   2.205 -				 */
   2.206 -				KTrieNode *cur;
   2.207 -
   2.208 -				/* Find every node arcing from the last node.
   2.209 -				 * I.e. for BACHELOR, BADGE, BABY,
   2.210 -				 * The arcs leaving A will be C and D, but our current node is B -> *.
   2.211 -				 * Thus, we use the last index (A) to find the base for arcs leaving A.
   2.212 -				 */
   2.213 -				unsigned int outgoing_base = m_base[lastidx].idx;
   2.214 -				unsigned int outgoing_list[256];
   2.215 -				unsigned int outgoing_count = 0;	/* count the current index here */
   2.216 -				cur = &m_base[outgoing_base] + 1;
   2.217 -				unsigned int outgoing_limit = 255;
   2.218 -
   2.219 -				if (outgoing_base + outgoing_limit > m_baseSize)
   2.220 -				{
   2.221 -					outgoing_limit = m_baseSize - outgoing_base;
   2.222 -				}
   2.223 -
   2.224 -				for (unsigned int i=1; i<=outgoing_limit; i++,cur++)
   2.225 -				{
   2.226 -					if (cur->mode == Node_Unused || cur->parent != lastidx)
   2.227 -					{
   2.228 -						continue;
   2.229 -					}
   2.230 -					outgoing_list[outgoing_count++] = i;
   2.231 -				}
   2.232 -				outgoing_list[outgoing_count++] = curidx - outgoing_base;
   2.233 -
   2.234 -				/* Now we need to find all the arcs leaving our parent...
   2.235 -				 * Note: the inconsistency is the base of our parent.  
   2.236 -				 */
   2.237 -				assert(m_base[node->parent].mode == Node_Arc);
   2.238 -				unsigned int incoming_list[256];
   2.239 -				unsigned int incoming_base = m_base[node->parent].idx;
   2.240 -				unsigned int incoming_count = 0;
   2.241 -				unsigned int incoming_limit = 255;
   2.242 -				cur = &m_base[incoming_base] + 1;
   2.243 -
   2.244 -				if (incoming_base + incoming_limit > m_baseSize)
   2.245 -				{
   2.246 -					incoming_limit = m_baseSize - incoming_base;
   2.247 -				}
   2.248 -
   2.249 -				assert(incoming_limit > 0 && incoming_limit <= 255);
   2.250 -
   2.251 -				for (unsigned int i=1; i<=incoming_limit; i++,cur++)
   2.252 -				{
   2.253 -					if (cur->mode == Node_Arc || cur->mode == Node_Term)
   2.254 -					{
   2.255 -						if (cur->parent == node->parent)
   2.256 -						{
   2.257 -							incoming_list[incoming_count++] = i;
   2.258 -						}
   2.259 -					}
   2.260 -				}
   2.261 -
   2.262 -				if (incoming_count < outgoing_count + 1)
   2.263 -				{
   2.264 -					unsigned int q = x_check_multi(incoming_list, incoming_count);
   2.265 -
   2.266 -					node = &m_base[curidx];
   2.267 -
   2.268 -					/* If we're incoming, we need to modify our parent */
   2.269 -					m_base[node->parent].idx = q;
   2.270 -
   2.271 -					/* For each node in the "to move" list,
   2.272 -					 * Relocate the node's info to the new position.
   2.273 -					 */
   2.274 -					unsigned int idx, newidx, oldidx;
   2.275 -					for (unsigned int i=0; i<incoming_count; i++)
   2.276 -					{
   2.277 -						idx = incoming_list[i];
   2.278 -						newidx = q + idx;
   2.279 -						oldidx = incoming_base + idx;
   2.280 -						if (oldidx == lastidx)
   2.281 -						{
   2.282 -							/* Important! Make sure we're not invalidating our sacred lastidx */
   2.283 -							lastidx = newidx;
   2.284 -						}
   2.285 -						/* Fully copy the node */
   2.286 -						memcpy(&m_base[newidx], &m_base[oldidx], sizeof(KTrieNode));
   2.287 -						if (m_base[oldidx].valset)
   2.288 -						{
   2.289 -							new (&m_base[newidx].value) K(m_base[oldidx].value);
   2.290 -							m_base[oldidx].value.~K();
   2.291 -						}
   2.292 -						assert(m_base[m_base[newidx].parent].mode == Node_Arc);
   2.293 -						/* Erase old data */
   2.294 -						memset(&m_base[oldidx], 0, sizeof(KTrieNode));
   2.295 -						/* If we are not a terminator, we have children we must take care of */
   2.296 -						if (m_base[newidx].mode == Node_Arc)
   2.297 -						{
   2.298 -							KTrieNode *check_base = &m_base[m_base[newidx].idx] + 1;
   2.299 -							outgoing_limit = (m_base + m_baseSize + 1) - check_base;
   2.300 -							if (outgoing_limit > 255)
   2.301 -							{
   2.302 -								outgoing_limit = 255;
   2.303 -							}
   2.304 -							for (unsigned int j=1; j<=outgoing_limit; j++, check_base++)
   2.305 -							{
   2.306 -								if (check_base->parent == oldidx)
   2.307 -								{
   2.308 -									check_base->parent = newidx;
   2.309 -								}
   2.310 -							}
   2.311 -						}
   2.312 -					}
   2.313 -				} else {
   2.314 -					unsigned int q = x_check_multi(outgoing_list, outgoing_count);
   2.315 -
   2.316 -					node = &m_base[curidx];
   2.317 -
   2.318 -					/* If we're outgoing, we need to modify our own base */
   2.319 -					m_base[lastidx].idx = q;
   2.320 -
   2.321 -					/* Take the last index (curidx) out of the list.  Technically we are not moving this,
   2.322 -					 * since it's already being used by something else.  
   2.323 -					 */
   2.324 -					outgoing_count--;
   2.325 -
   2.326 -					/* For each node in the "to move" list,
   2.327 -					 * Relocate the node's info to the new position.
   2.328 -					 */
   2.329 -					unsigned int idx, newidx, oldidx;
   2.330 -					for (unsigned int i=0; i<outgoing_count; i++)
   2.331 -					{
   2.332 -						idx = outgoing_list[i];
   2.333 -						newidx = q + idx;
   2.334 -						oldidx = outgoing_base + idx;
   2.335 -						if (oldidx == lastidx)
   2.336 -						{
   2.337 -							/* Important! Make sure we're not invalidating our sacred lastidx */
   2.338 -							lastidx = newidx;
   2.339 -						}
   2.340 -						/* Fully copy the node */
   2.341 -						memcpy(&m_base[newidx], &m_base[oldidx], sizeof(KTrieNode));
   2.342 -						if (m_base[oldidx].valset)
   2.343 -						{
   2.344 -							new (&m_base[newidx].value) K(m_base[oldidx].value);
   2.345 -							m_base[oldidx].value.~K();
   2.346 -						}
   2.347 -						assert(m_base[m_base[newidx].parent].mode == Node_Arc);
   2.348 -						/* Erase old data */
   2.349 -						memset(&m_base[oldidx], 0, sizeof(KTrieNode));
   2.350 -						/* If we are not a terminator, we have children we must take care of */
   2.351 -						if (m_base[newidx].mode == Node_Arc)
   2.352 -						{
   2.353 -							KTrieNode *check_base = &m_base[m_base[newidx].idx] + 1;
   2.354 -							outgoing_limit = (m_base + m_baseSize + 1) - check_base;
   2.355 -							if (outgoing_limit > 255)
   2.356 -							{
   2.357 -								outgoing_limit = 255;
   2.358 -							}
   2.359 -							for (unsigned int j=1; j<=outgoing_limit; j++, check_base++)
   2.360 -							{
   2.361 -								if (check_base->parent == oldidx)
   2.362 -								{
   2.363 -									check_base->parent = newidx;
   2.364 -								}
   2.365 -							}
   2.366 -						}
   2.367 -					}
   2.368 -
   2.369 -					/* Take the invisible node and use it as our new node */
   2.370 -					node = &m_base[q + outgoing_list[outgoing_count]];
   2.371 -				}
   2.372 -
   2.373 -				/* We're finally done! */
   2.374 -				node->parent = lastidx;
   2.375 -				if (*keyptr == '\0')
   2.376 -				{
   2.377 -					node->mode = Node_Arc;
   2.378 -				} else {
   2.379 -					node->idx = x_addstring(keyptr);
   2.380 -					node->mode = Node_Term;
   2.381 -				}
   2.382 -				node->valset = true;
   2.383 -				new (&node->value) K(obj);
   2.384 -
   2.385 -				return true;
   2.386 -			} else {
   2.387 -				/* See what's in the next node - special case if terminator! */
   2.388 -				if (node->mode == Node_Term)
   2.389 -				{
   2.390 -					/* If we're a terminator, we need to handle CASE 3:
   2.391 -					 * Insertion when a terminating collision occurs
   2.392 -					 */
   2.393 -					char *term = &m_stringtab[node->idx];
   2.394 -					/* Do an initial browsing to make sure they're not the same string */
   2.395 -					if (strcmp(keyptr, term) == 0)
   2.396 -					{
   2.397 -						if (!node->valset)
   2.398 -						{
   2.399 -							node->valset = true;
   2.400 -							new (&node->value) K(obj);
   2.401 -							return true;
   2.402 -						}
   2.403 -						/* Same string.  We can't insert. */
   2.404 -						return false;
   2.405 -					}
   2.406 -					/* For each matching character pair, we need to disband the terminator.
   2.407 -					 * This splits the similar prefix into a single arc path.
   2.408 -					 * First, save the old values so we can move them to a new node.
   2.409 -					 * Next, for each loop:
   2.410 -					 *  Take the current (invalid) node, and point it to the next arc base.
   2.411 -					 *  Set the current node to the node at the next arc.
   2.412 -					 */
   2.413 -					K oldvalue;
   2.414 -					bool oldvalset = node->valset;
   2.415 -					if (oldvalset)
   2.416 -					{
   2.417 -						oldvalue = node->value;
   2.418 -					}
   2.419 -					if (*term == *keyptr)
   2.420 -					{
   2.421 -						while (*term == *keyptr)
   2.422 -						{
   2.423 -							/* Find the next free slot in the check array.
   2.424 -							 * This is the "vector base" essentially
   2.425 -							 */
   2.426 -							q = x_check(*term);
   2.427 -							node = &m_base[curidx];
   2.428 -							/* Point the node to the next new base */
   2.429 -							node->idx = q;
   2.430 -							node->mode = Node_Arc;
   2.431 -							if (node->valset == true)
   2.432 -							{
   2.433 -								node->value.~K();
   2.434 -								node->valset = false;
   2.435 -							}
   2.436 -							/* Advance the input stream and local variables */
   2.437 -							lastidx = curidx;
   2.438 -							curidx = q + charval(*term);
   2.439 -							node = &m_base[curidx];
   2.440 -							/* Make sure the new current node has its parent set. */
   2.441 -							node->parent = lastidx;
   2.442 -							node->mode = Node_Arc;	/* Just in case we run x_check again */
   2.443 -							*term = '\0';	/* Unmark the string table here */
   2.444 -							term++;
   2.445 -							keyptr++;
   2.446 -						}
   2.447 -					} else if (node->valset) {
   2.448 -						node->valset = false;
   2.449 -						node->value.~K();
   2.450 -					}
   2.451 -					/* We're done inserting new pairs.  If one of them is exhausted,
   2.452 -					 * we take special shortcuts.
   2.453 -					 */
   2.454 -					if (*term == '\0')				//EX: BADGERHOUSE added over B -> ADGER.  
   2.455 -					{
   2.456 -						/* First backpatch the current node - it ends the newly split terminator.
   2.457 -						 * In the example, this would mean the node is the production from R -> ?
   2.458 -						 * This node ends the old BADGER, so we set it here.
   2.459 -						 */
   2.460 -						node->valset = oldvalset;
   2.461 -						if (node->valset)
   2.462 -						{
   2.463 -							new (&node->value) K(oldvalue);
   2.464 -						}
   2.465 -
   2.466 -						/* The terminator was split up, but pieces of keyptr remain.
   2.467 -						 * We need to generate a new production, in this example, R -> H,
   2.468 -						 * with H being a terminator to OUSE.  Thus we get:
   2.469 -						 * B,A,D,G,E,R*,H*->OUSE (* = value set).
   2.470 -						 * NOTE: parent was last set at the end of the while loop.
   2.471 -						 */
   2.472 -						/* Get the new base and apply re-basing */
   2.473 -						q = x_check(*keyptr);
   2.474 -						node = &m_base[curidx];
   2.475 -
   2.476 -						node->idx = q;
   2.477 -						node->mode = Node_Arc;
   2.478 -						lastidx = curidx;
   2.479 -						/* Finish the final node */
   2.480 -						curidx = q + charval(*keyptr);
   2.481 -						node = &m_base[curidx];
   2.482 -						keyptr++;
   2.483 -						/* Optimize - don't add to string table if there's nothing more to eat */
   2.484 -						if (*keyptr == '\0')
   2.485 -						{
   2.486 -							node->mode = Node_Arc;
   2.487 -						} else {
   2.488 -							node->idx = x_addstring(keyptr);
   2.489 -							node->mode = Node_Term;
   2.490 -						}
   2.491 -						node->parent = lastidx;
   2.492 -						node->valset = true;
   2.493 -						new (&node->value) K(obj);
   2.494 -					} else if (*keyptr == '\0') {	//EX: BADGER added over B -> ADGERHOUSE
   2.495 -						/* First backpatch the current node - it ends newly split input string.
   2.496 -						 * This is the exact opposite of the above procedure.
   2.497 -						 */
   2.498 -						node->valset = true;
   2.499 -						new (&node->value) K(obj);
   2.500 -
   2.501 -						/* Get the new base and apply re-basing */
   2.502 -						q = x_check(*term);
   2.503 -						node = &m_base[curidx];
   2.504 -
   2.505 -						node->idx = q;
   2.506 -						node->mode = Node_Arc;
   2.507 -						lastidx = curidx;
   2.508 -						/* Finish the final node */
   2.509 -						curidx = q + charval(*term);
   2.510 -						node = &m_base[curidx];
   2.511 -						term++;
   2.512 -						/* Optimize - don't add to string table if there's nothing more to eat */
   2.513 -						if (*term == '\0')
   2.514 -						{
   2.515 -							node->mode = Node_Arc;
   2.516 -						} else {
   2.517 -							node->idx = (term - m_stringtab); /* Already in the string table! */
   2.518 -							node->mode = Node_Term;
   2.519 -						}
   2.520 -						node->parent = lastidx;
   2.521 -						node->valset = oldvalset;
   2.522 -						if (node->valset)
   2.523 -						{
   2.524 -							new (&node->value) K(oldvalue);
   2.525 -						}
   2.526 -					} else {
   2.527 -						/* Finally, we have to create two new nodes instead of just one. */
   2.528 -						node->mode = Node_Arc;
   2.529 -
   2.530 -						/* Get the new base and apply re-basing */
   2.531 -						q = x_check2(*keyptr, *term);
   2.532 -						node = &m_base[curidx];
   2.533 -
   2.534 -						node->idx = q;
   2.535 -						lastidx = curidx;
   2.536 -
   2.537 -						/* Re-create the old terminated node */
   2.538 -						curidx = q + charval(*term);
   2.539 -						node = &m_base[curidx];
   2.540 -						term++;
   2.541 -						node->valset = oldvalset;
   2.542 -						if (node->valset)
   2.543 -						{
   2.544 -							new (&node->value) K(oldvalue);
   2.545 -						}
   2.546 -						node->parent = lastidx;
   2.547 -						if (*term == '\0')
   2.548 -						{
   2.549 -							node->mode = Node_Arc;
   2.550 -						} else {
   2.551 -							node->mode = Node_Term;
   2.552 -							node->idx = (term - m_stringtab); /* Already in the string table! */
   2.553 -						}
   2.554 -
   2.555 -						/* Create the new keyed input node */
   2.556 -						curidx = q + charval(*keyptr);
   2.557 -						node = &m_base[curidx];
   2.558 -						keyptr++;
   2.559 -						node->valset = true;
   2.560 -						new (&node->value) K(obj);
   2.561 -						node->parent = lastidx;
   2.562 -						if (*keyptr == '\0')
   2.563 -						{
   2.564 -							node->mode = Node_Arc;
   2.565 -						} else {
   2.566 -							node->mode = Node_Term;
   2.567 -							node->idx = x_addstring(keyptr);
   2.568 -						}
   2.569 -					}
   2.570 -
   2.571 -					/* Phew! */
   2.572 -					return true;
   2.573 -				} else {
   2.574 -					assert(node->mode == Node_Arc);
   2.575 -				}
   2.576 -			}
   2.577 -			lastidx = curidx;
   2.578 -		} while (*keyptr != '\0');
   2.579 -
   2.580 -		assert(node);
   2.581 -
   2.582 -		/* If we've exhausted the string and we have a valid reached node,
   2.583 -		 * the production rule already existed.  Make sure it's valid to set first.
   2.584 -		 */
   2.585 -
   2.586 -		/* We have to be an Arc.  If the last result was anything else, we would have returned a new 
   2.587 -		 * production earlier.
   2.588 -		 */
   2.589 -		assert(node->mode == Node_Arc);
   2.590 -
   2.591 -		if (!node->valset)
   2.592 -		{
   2.593 -			node->valset = true;
   2.594 -			new (&node->value) K(obj);
   2.595 -			return true;
   2.596 -		}
   2.597 -
   2.598 -		return false;
   2.599 -	}
   2.600 -public:
   2.601 -	KTrie()
   2.602 -	{
   2.603 -		m_base = (KTrieNode *)malloc(sizeof(KTrieNode) * (256 + 1));
   2.604 -		m_stringtab = (char *)malloc(sizeof(char) * 256);
   2.605 -		m_baseSize = 256;
   2.606 -		m_stSize = 256;
   2.607 -
   2.608 -		internal_clear();
   2.609 -	}
   2.610 -	~KTrie()
   2.611 -	{
   2.612 -		run_destructors();
   2.613 -		free(m_base);
   2.614 -		free(m_stringtab);
   2.615 -	}
   2.616 -private:
   2.617 -	class KTrieNode
   2.618 -	{
   2.619 -		friend class KTrie;
   2.620 -	private:
   2.621 -		/**
   2.622 -		 * For Node_Arc, this index stores the 'base' offset to the next arc chain.
   2.623 -		 *   I.e. to jump from this arc to character C, it will be at base[idx+C].
   2.624 -		 * For Node_Term, this is an index into the string table.
   2.625 -		 */
   2.626 -		unsigned int idx;	
   2.627 -
   2.628 -		/**
   2.629 -		 * This contains the prior arc that we must have come from.
   2.630 -		 * For example, if arc 63 has a base jump of index 12, and we want to see if
   2.631 -		 * there is a valid character C, the parent of 12+C must be 63.
   2.632 -		 */
   2.633 -		unsigned int parent;
   2.634 -		K value;				/* Value associated with this node */
   2.635 -		NodeType mode;			/* Current usage type of the node */
   2.636 -		bool valset;			/* Whether or not a value is set */
   2.637 -	};
   2.638 -private:
   2.639 -	KTrieNode *internal_retrieve(const char *key)
   2.640 -	{
   2.641 -		unsigned int lastidx = 1;		/* the last node index */
   2.642 -		unsigned int curidx;			/* current node index */
   2.643 -		const char *keyptr = key;		/* input stream at current token */
   2.644 -		KTrieNode *node = NULL;			/* current node being processed */
   2.645 -
   2.646 -		if (!*key)
   2.647 -		{
   2.648 -			return NULL;
   2.649 -		}
   2.650 -
   2.651 -		/* Start traversing at the root node */
   2.652 -		do
   2.653 -		{
   2.654 -			/* Find where the next character is, then advance */
   2.655 -			curidx = m_base[lastidx].idx;
   2.656 -			node = &m_base[curidx];
   2.657 -			curidx += charval(*keyptr);
   2.658 -			node = &m_base[curidx];
   2.659 -			keyptr++;
   2.660 -
   2.661 -			/* Check if this slot is supposed to be empty or is a collision */
   2.662 -			if ((curidx > m_baseSize) || node->mode == Node_Unused || node->parent != lastidx)
   2.663 -			{
   2.664 -				return NULL;
   2.665 -			} else if (node->mode == Node_Term) {
   2.666 -				char *term = &m_stringtab[node->idx];
   2.667 -				if (strcmp(keyptr, term) == 0)
   2.668 -				{
   2.669 -					break;
   2.670 -				}
   2.671 -			}
   2.672 -			lastidx = curidx;
   2.673 -		} while (*keyptr != '\0');
   2.674 -
   2.675 -		return node;
   2.676 -	}
   2.677 -	bool grow()
   2.678 -	{
   2.679 -		/* The current # of nodes in the tree is trie->baseSize + 1 */
   2.680 -		unsigned int cur_size = m_baseSize;
   2.681 -		unsigned int new_size = cur_size * 2;
   2.682 -
   2.683 -		KTrieNode *new_base = (KTrieNode *)malloc((new_size + 1) * sizeof(KTrieNode));
   2.684 -		if (!new_base)
   2.685 -		{
   2.686 -			return false;
   2.687 -		}
   2.688 -
   2.689 -		memcpy(new_base, m_base, sizeof(KTrieNode) * (m_baseSize + 1));
   2.690 -		memset(&new_base[cur_size + 1], 0, (new_size - cur_size) * sizeof(KTrieNode));
   2.691 -
   2.692 -		for (size_t i = 0; i <= m_baseSize; i++)
   2.693 -		{
   2.694 -			if (m_base[i].valset)
   2.695 -			{
   2.696 -				/* Placement construct+copy the object, then placement destroy the old. */
   2.697 -				new (&new_base[i].value) K(m_base[i].value);
   2.698 -				m_base[i].value.~K();
   2.699 -			}
   2.700 -		}
   2.701 -
   2.702 -		free(m_base);
   2.703 -		m_base = new_base;
   2.704 -		m_baseSize = new_size;
   2.705 -
   2.706 -		return true;
   2.707 -	}
   2.708 -	inline unsigned char charval(char c)
   2.709 -	{
   2.710 -		return (unsigned char)c;
   2.711 -	}
   2.712 -	void internal_clear()
   2.713 -	{
   2.714 -		m_tail = 0;
   2.715 -
   2.716 -		memset(m_base, 0, sizeof(KTrieNode) * (m_baseSize + 1));
   2.717 -		memset(m_stringtab, 0, sizeof(char) * m_stSize);
   2.718 -
   2.719 -		/* Sentinel root node */
   2.720 -		m_base[1].idx = 1;
   2.721 -		m_base[1].mode = Node_Arc;
   2.722 -		m_base[1].parent = 1;
   2.723 -	}
   2.724 -	void run_destructors()
   2.725 -	{
   2.726 -		for (size_t i = 0; i <= m_baseSize; i++)
   2.727 -		{
   2.728 -			if (m_base[i].valset)
   2.729 -			{
   2.730 -				m_base[i].value.~K();
   2.731 -			}
   2.732 -		}
   2.733 -	}
   2.734 -	unsigned int x_addstring(const char *ptr)
   2.735 -	{
   2.736 -		size_t len = strlen(ptr) + 1;
   2.737 -
   2.738 -		if (m_tail + len >= m_stSize)
   2.739 -		{		
   2.740 -			while (m_tail + len >= m_stSize)
   2.741 -			{
   2.742 -				m_stSize *= 2;
   2.743 -			}
   2.744 -			m_stringtab = (char *)realloc(m_stringtab,m_stSize);
   2.745 -		}
   2.746 -
   2.747 -		unsigned int tail = m_tail;
   2.748 -		strcpy(&m_stringtab[tail], ptr);
   2.749 -		m_tail += len;
   2.750 -
   2.751 -		return tail;
   2.752 -	}
   2.753 -	unsigned int x_check(char c, unsigned int start=1)
   2.754 -	{
   2.755 -		unsigned char _c = charval(c);
   2.756 -		unsigned int to_check = m_baseSize - _c;
   2.757 -		for (unsigned int i=start; i<=to_check; i++)
   2.758 -		{
   2.759 -			if (m_base[i+_c].mode == Node_Unused)
   2.760 -			{
   2.761 -				return i;
   2.762 -			}
   2.763 -		}
   2.764 -
   2.765 -		grow();
   2.766 -
   2.767 -		return x_check(c, to_check+1);
   2.768 -	}
   2.769 -	unsigned int x_check2(char c1, char c2, unsigned int start=1)
   2.770 -	{
   2.771 -		unsigned char _c1 = charval(c1);
   2.772 -		unsigned char _c2 = charval(c2);
   2.773 -		unsigned int to_check = m_baseSize - (_c1 > _c2 ? _c1 : _c2);
   2.774 -		for (unsigned int i=start; i<=to_check; i++)
   2.775 -		{
   2.776 -			if (m_base[i+_c1].mode == Node_Unused
   2.777 -				&& m_base[i+_c2].mode == Node_Unused)
   2.778 -			{
   2.779 -				return i;
   2.780 -			}
   2.781 -		}
   2.782 -
   2.783 -		grow();
   2.784 -
   2.785 -		return x_check2(c1, c2, to_check+1);
   2.786 -	}
   2.787 -	unsigned int x_check_multi(
   2.788 -		unsigned int offsets[], 
   2.789 -		unsigned int count,
   2.790 -		unsigned int start=1)
   2.791 -	{
   2.792 -		KTrieNode *cur;
   2.793 -		unsigned int to_check = m_baseSize;
   2.794 -		unsigned int highest = 0;
   2.795 -
   2.796 -		for (unsigned int i=0; i<count; i++)
   2.797 -		{
   2.798 -			if (offsets[i] > highest)
   2.799 -			{
   2.800 -				highest = offsets[i];
   2.801 -			}
   2.802 -		}
   2.803 -
   2.804 -		to_check -= highest;
   2.805 -
   2.806 -		for (unsigned int i=start; i<=to_check; i++)
   2.807 -		{
   2.808 -			bool okay = true;
   2.809 -			for (unsigned int j=0; j<count; j++)
   2.810 -			{
   2.811 -				cur = &m_base[i+offsets[j]];
   2.812 -				if (cur->mode != Node_Unused)
   2.813 -				{
   2.814 -					okay = false;
   2.815 -					break;
   2.816 -				}
   2.817 -			}
   2.818 -			if (okay)
   2.819 -			{
   2.820 -				return i;
   2.821 -			}
   2.822 -		}
   2.823 -
   2.824 -		grow();
   2.825 -
   2.826 -		return x_check_multi(offsets, count, to_check+1);
   2.827 -	}
   2.828 -private:
   2.829 -	KTrieNode *m_base;			/* Base array for the sparse tables */
   2.830 -	char *m_stringtab;			/* String table pointer */
   2.831 -	unsigned int m_baseSize;	/* Size of the base array, in members */
   2.832 -	unsigned int m_stSize;		/* Size of the string table, in bytes */
   2.833 -	unsigned int m_tail;		/* Current unused offset into the string table */
   2.834 -};
   2.835 -
   2.836 -/**
   2.837 - * Double Array Trie algorithm, based on:
   2.838 - * An Efficient Implementation of Trie Structures, by
   2.839 - *  Jun-ichi Aoe and Katsushi Maromoto, and Takashi Sato
   2.840 - * from Software - Practice and Experience, Vol. 22(9), 695-721 (September 1992)
   2.841 - *
   2.842 - *  A Trie is a simple data structure which stores strings as DFAs, with each 
   2.843 - * transition state being a string entry.  For example, observe the following strings:
   2.844 - *
   2.845 - * BAILOPAN, BAT, BACON, BACK
   2.846 - *  These transition as the follow production rules:
   2.847 - *  B -> ...                  B
   2.848 - *       A -> ...             BA
   2.849 - *            I -> ...        BAI
   2.850 - *                 LOPAN      BAILOPAN
   2.851 - *            T -> ...        BAT
   2.852 - *            C ->            BAC
   2.853 - *                 O -> ...   BACO
   2.854 - *                      N     BACON
   2.855 - *                 K          BACK
   2.856 - *
   2.857 - *  The standard implementation for this - using lists - gives a slow linear lookup, somewhere between
   2.858 - * O(N+M) or O(log n).  A faster implementation is proposed in the paper above, which is based on compacting
   2.859 - * the transition states into two arrays.  In the paper's implementation, two arrays are used, and thus it is
   2.860 - * called the "Double Array" algorithm.  However, the CHECK array's size is maintained the same as BASE, 
   2.861 - * so they can be combined into one structure.  The array seems complex at first, but is very simple: it is a
   2.862 - * tree structure flattened out into a single vector.  I am calling this implementation the Flat Array Trie.
   2.863 - *
   2.864 - *  BASE[] is an array where each member is a node in the Trie.  The node can either be UNUSED (empty), an ARC
   2.865 - * (containing an offset to the next set of ARCs), or a TERMINATOR (contains the rest of a string).
   2.866 - * Each node has an index which must be interpreted based on the node type.  If the node is a TERMINATOR, then the
   2.867 - * index is an index into a string table, to find the rest of the string.  
   2.868 - *  If the node is an ARC, the index is another index into BASE.  For each possible token that can follow the
   2.869 - * current token, the value of those tokens can be added to the index given in the ARC.  Thus, given a current
   2.870 - * position and the next desired token, the current arc will jump to another arc which can contain either:
   2.871 - *   1) An invalid production (collision, no entry exists)
   2.872 - *   2) An empty production (no entry exists)
   2.873 - *   3) Another arc label (the string ends here or continues into more productions)
   2.874 - *   4) A TERMINATOR (the string ends here and contains an unused set of productions)
   2.875 - * 
   2.876 - *  So, given current offset N (starting at N=1), jumping to token C means the next offset will be:
   2.877 - *      offs = BASE[n] + C
   2.878 - *  Thus, the next node will be at:
   2.879 - *      BASE[BASE[n] + C]
   2.880 - * 
   2.881 - *  This allows each ARC to specify the base offset for any of its ARC children, like a tree.  Each node specifies
   2.882 - * its parent ARC -- so if an invalid offset is specified, the parent will not match, and thus no such derived 
   2.883 - * string exists.
   2.884 - *
   2.885 - *  This means that arrays can be laid out "sparsely," maximizing their usage.  Note that N need not be related to
   2.886 - * the range of tokens (1-256).  I.e., a base index does not have to be at 1, 256, 512, et cetera.  This is because
   2.887 - * insertion comes with a small deal of complexity.  To insert a new set of tokens T, the algorithm finds a new 
   2.888 - * BASE index N such that BASE[N+T[i]] is unused for each T[i].  Thus, indirection is not necessarily linear; 
   2.889 - * traversing a chain of ARC nodes can _and will_ jump around BASE.
   2.890 - *
   2.891 - *  Of course, given this level of flexibility in the array organization, there are collisions.  This is largely 
   2.892 - * where insertions become slow, as the old chain must be relocated before the new one is used.  Relocation means 
   2.893 - * finding one or more new base indexes, and this means traversing BASE until an acceptable index is found, such 
   2.894 - * that each offset is unused (see description in previous paragraph).
   2.895 - *
   2.896 - *  However, it is not insertion time we are concerned about.  The "trie" name comes from reTRIEval.  We are only
   2.897 - * concerned with lookup and deletion.  Both lookup and deletion are O(k), where k is relative to the length of the 
   2.898 - * input string.  Note that it is best case O(1) and worst case O(k).  Deleting the entire trie is always O(1).
   2.899 - */
   2.900 -
   2.901 -#endif //_INCLUDE_SOURCEMOD_TEMPLATED_TRIE_H_
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/public/sm_trie_tpl.h	Wed Aug 29 05:22:47 2007 +0000
     3.3 @@ -0,0 +1,898 @@
     3.4 +/**
     3.5 + * vim: set ts=4 :
     3.6 + * =============================================================================
     3.7 + * SourceMod
     3.8 + * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     3.9 + * =============================================================================
    3.10 + *
    3.11 + * This program is free software; you can redistribute it and/or modify it under
    3.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    3.13 + * Free Software Foundation.
    3.14 + * 
    3.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    3.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    3.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    3.18 + * details.
    3.19 + *
    3.20 + * You should have received a copy of the GNU General Public License along with
    3.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    3.22 + *
    3.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    3.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    3.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    3.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    3.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    3.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    3.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    3.30 + * or <http://www.sourcemod.net/license.php>.
    3.31 + *
    3.32 + * Version: $Id$
    3.33 + */
    3.34 +
    3.35 +#ifndef _INCLUDE_SOURCEMOD_TEMPLATED_TRIE_H_
    3.36 +#define _INCLUDE_SOURCEMOD_TEMPLATED_TRIE_H_
    3.37 +
    3.38 +#include <new>
    3.39 +#include <string.h>
    3.40 +#include <malloc.h>
    3.41 +#include <assert.h>
    3.42 +
    3.43 +enum NodeType
    3.44 +{
    3.45 +	Node_Unused = 0,		/* Node is not being used (sparse) */
    3.46 +	Node_Arc,				/* Node is part of an arc and does not terminate */
    3.47 +	Node_Term,				/* Node is a terminator */
    3.48 +};
    3.49 +
    3.50 +/**
    3.51 + * @brief Trie algorithm based on "Double Array Trie" algorith.
    3.52 + * @file sm_trie_tpl.h
    3.53 + *
    3.54 + * For full works cited and implementation overview, there is a big comment 
    3.55 + * block at the bottom of this file.
    3.56 + */
    3.57 +
    3.58 +template <typename K>
    3.59 +class KTrie
    3.60 +{
    3.61 +	class KTrieNode;
    3.62 +public:
    3.63 +	/**
    3.64 +	 * @brief Clears all set objects in the trie.
    3.65 +	 */
    3.66 +	void clear()
    3.67 +	{
    3.68 +		run_destructors();
    3.69 +		internal_clear();
    3.70 +	}
    3.71 +
    3.72 +	/**
    3.73 +	 * @brief Removes a key from the trie.
    3.74 +	 *
    3.75 +	 * @param key		Key to remove.
    3.76 +	 * @return			True on success, false if key was never set.
    3.77 +	 */
    3.78 +	bool remove(const char *key)
    3.79 +	{
    3.80 +		KTrieNode *node = internal_retrieve(key);
    3.81 +		if (!node || !node->valset)
    3.82 +		{
    3.83 +			return false;
    3.84 +		}
    3.85 +
    3.86 +		node->value.~K();
    3.87 +		node->valset = false;
    3.88 +
    3.89 +		return true;
    3.90 +	}
    3.91 +
    3.92 +	/**
    3.93 +	 * @brief Retrieves a pointer to the object stored at a given key.
    3.94 +	 *
    3.95 +	 * @param key		Key to retrieve.
    3.96 +	 * @return			Pointer to object, or NULL if key was not found or not set.
    3.97 +	 */
    3.98 +	K * retrieve(const char *key)
    3.99 +	{
   3.100 +		KTrieNode *node = internal_retrieve(key);
   3.101 +		if (!node || !node->valset)
   3.102 +		{
   3.103 +			return NULL;
   3.104 +		}
   3.105 +		return &node->value;
   3.106 +	}
   3.107 +
   3.108 +	/**
   3.109 +	 * @brief Inserts or updates the object stored at a key.
   3.110 +	 *
   3.111 +	 * @param key		Key to update or insert.
   3.112 +	 * @param obj		Object to store at the key.
   3.113 +	 * @return			True on success, false on failure.
   3.114 +	 */
   3.115 +	bool replace(const char *key, const K & obj)
   3.116 +	{
   3.117 +		KTrieNode *prev_node = internal_retrieve(key);
   3.118 +		if (!prev_node)
   3.119 +		{
   3.120 +			return insert(key, obj);
   3.121 +		}
   3.122 +
   3.123 +		if (prev_node->valset)
   3.124 +		{
   3.125 +			prev_node->value.~K();
   3.126 +		}
   3.127 +
   3.128 +		new (&prev_node->value) K(obj);
   3.129 +
   3.130 +		return true;
   3.131 +	}
   3.132 +
   3.133 +	/**
   3.134 +	 * @brief Inserts an object at a key.
   3.135 +	 *
   3.136 +	 * @param key		Key to insert at.
   3.137 +	 * @param obj		Object to store at the key.
   3.138 +	 * @return			True on success, false if the key is already set or 
   3.139 +	 *					insertion otherwise failed.
   3.140 +	 */
   3.141 +	bool insert(const char *key, const K & obj)
   3.142 +	{
   3.143 +		unsigned int lastidx = 1;		/* the last node index */
   3.144 +		unsigned int curidx;			/* current node index */
   3.145 +		const char *keyptr = key;		/* input stream at current token */
   3.146 +		KTrieNode *node = NULL;			/* current node being processed */
   3.147 +		KTrieNode *basenode = NULL;		/* current base node being processed */
   3.148 +		unsigned int q;					/* temporary var for x_check results */
   3.149 +		unsigned int curoffs;			/* current offset */
   3.150 +
   3.151 +		/* Do not handle empty strings for simplicity */
   3.152 +		if (!*key)
   3.153 +		{
   3.154 +			return false;
   3.155 +		}
   3.156 +
   3.157 +		/* Start traversing at the root node (1) */
   3.158 +		do
   3.159 +		{
   3.160 +			/* Find where the next character is, then advance */
   3.161 +			curidx = m_base[lastidx].idx;
   3.162 +			basenode = &m_base[curidx];
   3.163 +			curoffs = charval(*keyptr);
   3.164 +			curidx += curoffs;
   3.165 +			node = &m_base[curidx];
   3.166 +			keyptr++;
   3.167 +
   3.168 +			/* Check if this slot is supposed to be empty.  If so, we need to handle CASES 1/2:
   3.169 +			 * Insertion without collisions
   3.170 +			 */
   3.171 +			if ( (curidx > m_baseSize) || (node->mode == Node_Unused) )
   3.172 +			{
   3.173 +				if (curidx > m_baseSize)
   3.174 +				{
   3.175 +					if (!grow())
   3.176 +					{
   3.177 +						return false;
   3.178 +					}
   3.179 +					node = &m_base[curidx];
   3.180 +				}
   3.181 +				node->parent = lastidx;
   3.182 +				if (*keyptr == '\0')
   3.183 +				{
   3.184 +					node->mode = Node_Arc;
   3.185 +				} else {
   3.186 +					node->idx = x_addstring(keyptr);
   3.187 +					node->mode = Node_Term;
   3.188 +				}
   3.189 +				node->valset = true;
   3.190 +				new (&node->value) K(obj);
   3.191 +
   3.192 +				return true;
   3.193 +			} else if (node->parent != lastidx) {
   3.194 +				/* Collision! We have to split up the tree here.  CASE 4:
   3.195 +				 * Insertion when a new word is inserted with a collision.
   3.196 +				 * NOTE: This is the hardest case to handle.  All below examples are based on:
   3.197 +				 * BACHELOR, BADGE, inserting BABY.
   3.198 +				 * The problematic production here is A -> B, where B is already being used.
   3.199 +			     *
   3.200 +				 * This process has to rotate one half of the 'A' arc.  We generate two lists:
   3.201 +				 *  Outgoing Arcs - Anything leaving this 'A'
   3.202 +				 *  Incoming Arcs - Anything going to this 'A'
   3.203 +				 * Whichever list is smaller will be moved.  Note that this works because the intersection
   3.204 +				 * affects both arc chains, and moving one will make the slot available to either.
   3.205 +				 */
   3.206 +				KTrieNode *cur;
   3.207 +
   3.208 +				/* Find every node arcing from the last node.
   3.209 +				 * I.e. for BACHELOR, BADGE, BABY,
   3.210 +				 * The arcs leaving A will be C and D, but our current node is B -> *.
   3.211 +				 * Thus, we use the last index (A) to find the base for arcs leaving A.
   3.212 +				 */
   3.213 +				unsigned int outgoing_base = m_base[lastidx].idx;
   3.214 +				unsigned int outgoing_list[256];
   3.215 +				unsigned int outgoing_count = 0;	/* count the current index here */
   3.216 +				cur = &m_base[outgoing_base] + 1;
   3.217 +				unsigned int outgoing_limit = 255;
   3.218 +
   3.219 +				if (outgoing_base + outgoing_limit > m_baseSize)
   3.220 +				{
   3.221 +					outgoing_limit = m_baseSize - outgoing_base;
   3.222 +				}
   3.223 +
   3.224 +				for (unsigned int i=1; i<=outgoing_limit; i++,cur++)
   3.225 +				{
   3.226 +					if (cur->mode == Node_Unused || cur->parent != lastidx)
   3.227 +					{
   3.228 +						continue;
   3.229 +					}
   3.230 +					outgoing_list[outgoing_count++] = i;
   3.231 +				}
   3.232 +				outgoing_list[outgoing_count++] = curidx - outgoing_base;
   3.233 +
   3.234 +				/* Now we need to find all the arcs leaving our parent...
   3.235 +				 * Note: the inconsistency is the base of our parent.  
   3.236 +				 */
   3.237 +				assert(m_base[node->parent].mode == Node_Arc);
   3.238 +				unsigned int incoming_list[256];
   3.239 +				unsigned int incoming_base = m_base[node->parent].idx;
   3.240 +				unsigned int incoming_count = 0;
   3.241 +				unsigned int incoming_limit = 255;
   3.242 +				cur = &m_base[incoming_base] + 1;
   3.243 +
   3.244 +				if (incoming_base + incoming_limit > m_baseSize)
   3.245 +				{
   3.246 +					incoming_limit = m_baseSize - incoming_base;
   3.247 +				}
   3.248 +
   3.249 +				assert(incoming_limit > 0 && incoming_limit <= 255);
   3.250 +
   3.251 +				for (unsigned int i=1; i<=incoming_limit; i++,cur++)
   3.252 +				{
   3.253 +					if (cur->mode == Node_Arc || cur->mode == Node_Term)
   3.254 +					{
   3.255 +						if (cur->parent == node->parent)
   3.256 +						{
   3.257 +							incoming_list[incoming_count++] = i;
   3.258 +						}
   3.259 +					}
   3.260 +				}
   3.261 +
   3.262 +				if (incoming_count < outgoing_count + 1)
   3.263 +				{
   3.264 +					unsigned int q = x_check_multi(incoming_list, incoming_count);
   3.265 +
   3.266 +					node = &m_base[curidx];
   3.267 +
   3.268 +					/* If we're incoming, we need to modify our parent */
   3.269 +					m_base[node->parent].idx = q;
   3.270 +
   3.271 +					/* For each node in the "to move" list,
   3.272 +					 * Relocate the node's info to the new position.
   3.273 +					 */
   3.274 +					unsigned int idx, newidx, oldidx;
   3.275 +					for (unsigned int i=0; i<incoming_count; i++)
   3.276 +					{
   3.277 +						idx = incoming_list[i];
   3.278 +						newidx = q + idx;
   3.279 +						oldidx = incoming_base + idx;
   3.280 +						if (oldidx == lastidx)
   3.281 +						{
   3.282 +							/* Important! Make sure we're not invalidating our sacred lastidx */
   3.283 +							lastidx = newidx;
   3.284 +						}
   3.285 +						/* Fully copy the node */
   3.286 +						memcpy(&m_base[newidx], &m_base[oldidx], sizeof(KTrieNode));
   3.287 +						if (m_base[oldidx].valset)
   3.288 +						{
   3.289 +							new (&m_base[newidx].value) K(m_base[oldidx].value);
   3.290 +							m_base[oldidx].value.~K();
   3.291 +						}
   3.292 +						assert(m_base[m_base[newidx].parent].mode == Node_Arc);
   3.293 +						/* Erase old data */
   3.294 +						memset(&m_base[oldidx], 0, sizeof(KTrieNode));
   3.295 +						/* If we are not a terminator, we have children we must take care of */
   3.296 +						if (m_base[newidx].mode == Node_Arc)
   3.297 +						{
   3.298 +							KTrieNode *check_base = &m_base[m_base[newidx].idx] + 1;
   3.299 +							outgoing_limit = (m_base + m_baseSize + 1) - check_base;
   3.300 +							if (outgoing_limit > 255)
   3.301 +							{
   3.302 +								outgoing_limit = 255;
   3.303 +							}
   3.304 +							for (unsigned int j=1; j<=outgoing_limit; j++, check_base++)
   3.305 +							{
   3.306 +								if (check_base->parent == oldidx)
   3.307 +								{
   3.308 +									check_base->parent = newidx;
   3.309 +								}
   3.310 +							}
   3.311 +						}
   3.312 +					}
   3.313 +				} else {
   3.314 +					unsigned int q = x_check_multi(outgoing_list, outgoing_count);
   3.315 +
   3.316 +					node = &m_base[curidx];
   3.317 +
   3.318 +					/* If we're outgoing, we need to modify our own base */
   3.319 +					m_base[lastidx].idx = q;
   3.320 +
   3.321 +					/* Take the last index (curidx) out of the list.  Technically we are not moving this,
   3.322 +					 * since it's already being used by something else.  
   3.323 +					 */
   3.324 +					outgoing_count--;
   3.325 +
   3.326 +					/* For each node in the "to move" list,
   3.327 +					 * Relocate the node's info to the new position.
   3.328 +					 */
   3.329 +					unsigned int idx, newidx, oldidx;
   3.330 +					for (unsigned int i=0; i<outgoing_count; i++)
   3.331 +					{
   3.332 +						idx = outgoing_list[i];
   3.333 +						newidx = q + idx;
   3.334 +						oldidx = outgoing_base + idx;
   3.335 +						if (oldidx == lastidx)
   3.336 +						{
   3.337 +							/* Important! Make sure we're not invalidating our sacred lastidx */
   3.338 +							lastidx = newidx;
   3.339 +						}
   3.340 +						/* Fully copy the node */
   3.341 +						memcpy(&m_base[newidx], &m_base[oldidx], sizeof(KTrieNode));
   3.342 +						if (m_base[oldidx].valset)
   3.343 +						{
   3.344 +							new (&m_base[newidx].value) K(m_base[oldidx].value);
   3.345 +							m_base[oldidx].value.~K();
   3.346 +						}
   3.347 +						assert(m_base[m_base[newidx].parent].mode == Node_Arc);
   3.348 +						/* Erase old data */
   3.349 +						memset(&m_base[oldidx], 0, sizeof(KTrieNode));
   3.350 +						/* If we are not a terminator, we have children we must take care of */
   3.351 +						if (m_base[newidx].mode == Node_Arc)
   3.352 +						{
   3.353 +							KTrieNode *check_base = &m_base[m_base[newidx].idx] + 1;
   3.354 +							outgoing_limit = (m_base + m_baseSize + 1) - check_base;
   3.355 +							if (outgoing_limit > 255)
   3.356 +							{
   3.357 +								outgoing_limit = 255;
   3.358 +							}
   3.359 +							for (unsigned int j=1; j<=outgoing_limit; j++, check_base++)
   3.360 +							{
   3.361 +								if (check_base->parent == oldidx)
   3.362 +								{
   3.363 +									check_base->parent = newidx;
   3.364 +								}
   3.365 +							}
   3.366 +						}
   3.367 +					}
   3.368 +
   3.369 +					/* Take the invisible node and use it as our new node */
   3.370 +					node = &m_base[q + outgoing_list[outgoing_count]];
   3.371 +				}
   3.372 +
   3.373 +				/* We're finally done! */
   3.374 +				node->parent = lastidx;
   3.375 +				if (*keyptr == '\0')
   3.376 +				{
   3.377 +					node->mode = Node_Arc;
   3.378 +				} else {
   3.379 +					node->idx = x_addstring(keyptr);
   3.380 +					node->mode = Node_Term;
   3.381 +				}
   3.382 +				node->valset = true;
   3.383 +				new (&node->value) K(obj);
   3.384 +
   3.385 +				return true;
   3.386 +			} else {
   3.387 +				/* See what's in the next node - special case if terminator! */
   3.388 +				if (node->mode == Node_Term)
   3.389 +				{
   3.390 +					/* If we're a terminator, we need to handle CASE 3:
   3.391 +					 * Insertion when a terminating collision occurs
   3.392 +					 */
   3.393 +					char *term = &m_stringtab[node->idx];
   3.394 +					/* Do an initial browsing to make sure they're not the same string */
   3.395 +					if (strcmp(keyptr, term) == 0)
   3.396 +					{
   3.397 +						if (!node->valset)
   3.398 +						{
   3.399 +							node->valset = true;
   3.400 +							new (&node->value) K(obj);
   3.401 +							return true;
   3.402 +						}
   3.403 +						/* Same string.  We can't insert. */
   3.404 +						return false;
   3.405 +					}
   3.406 +					/* For each matching character pair, we need to disband the terminator.
   3.407 +					 * This splits the similar prefix into a single arc path.
   3.408 +					 * First, save the old values so we can move them to a new node.
   3.409 +					 * Next, for each loop:
   3.410 +					 *  Take the current (invalid) node, and point it to the next arc base.
   3.411 +					 *  Set the current node to the node at the next arc.
   3.412 +					 */
   3.413 +					K oldvalue;
   3.414 +					bool oldvalset = node->valset;
   3.415 +					if (oldvalset)
   3.416 +					{
   3.417 +						oldvalue = node->value;
   3.418 +					}
   3.419 +					if (*term == *keyptr)
   3.420 +					{
   3.421 +						while (*term == *keyptr)
   3.422 +						{
   3.423 +							/* Find the next free slot in the check array.
   3.424 +							 * This is the "vector base" essentially
   3.425 +							 */
   3.426 +							q = x_check(*term);
   3.427 +							node = &m_base[curidx];
   3.428 +							/* Point the node to the next new base */
   3.429 +							node->idx = q;
   3.430 +							node->mode = Node_Arc;
   3.431 +							if (node->valset == true)
   3.432 +							{
   3.433 +								node->value.~K();
   3.434 +								node->valset = false;
   3.435 +							}
   3.436 +							/* Advance the input stream and local variables */
   3.437 +							lastidx = curidx;
   3.438 +							curidx = q + charval(*term);
   3.439 +							node = &m_base[curidx];
   3.440 +							/* Make sure the new current node has its parent set. */
   3.441 +							node->parent = lastidx;
   3.442 +							node->mode = Node_Arc;	/* Just in case we run x_check again */
   3.443 +							*term = '\0';	/* Unmark the string table here */
   3.444 +							term++;
   3.445 +							keyptr++;
   3.446 +						}
   3.447 +					} else if (node->valset) {
   3.448 +						node->valset = false;
   3.449 +						node->value.~K();
   3.450 +					}
   3.451 +					/* We're done inserting new pairs.  If one of them is exhausted,
   3.452 +					 * we take special shortcuts.
   3.453 +					 */
   3.454 +					if (*term == '\0')				//EX: BADGERHOUSE added over B -> ADGER.  
   3.455 +					{
   3.456 +						/* First backpatch the current node - it ends the newly split terminator.
   3.457 +						 * In the example, this would mean the node is the production from R -> ?
   3.458 +						 * This node ends the old BADGER, so we set it here.
   3.459 +						 */
   3.460 +						node->valset = oldvalset;
   3.461 +						if (node->valset)
   3.462 +						{
   3.463 +							new (&node->value) K(oldvalue);
   3.464 +						}
   3.465 +
   3.466 +						/* The terminator was split up, but pieces of keyptr remain.
   3.467 +						 * We need to generate a new production, in this example, R -> H,
   3.468 +						 * with H being a terminator to OUSE.  Thus we get:
   3.469 +						 * B,A,D,G,E,R*,H*->OUSE (* = value set).
   3.470 +						 * NOTE: parent was last set at the end of the while loop.
   3.471 +						 */
   3.472 +						/* Get the new base and apply re-basing */
   3.473 +						q = x_check(*keyptr);
   3.474 +						node = &m_base[curidx];
   3.475 +
   3.476 +						node->idx = q;
   3.477 +						node->mode = Node_Arc;
   3.478 +						lastidx = curidx;
   3.479 +						/* Finish the final node */
   3.480 +						curidx = q + charval(*keyptr);
   3.481 +						node = &m_base[curidx];
   3.482 +						keyptr++;
   3.483 +						/* Optimize - don't add to string table if there's nothing more to eat */
   3.484 +						if (*keyptr == '\0')
   3.485 +						{
   3.486 +							node->mode = Node_Arc;
   3.487 +						} else {
   3.488 +							node->idx = x_addstring(keyptr);
   3.489 +							node->mode = Node_Term;
   3.490 +						}
   3.491 +						node->parent = lastidx;
   3.492 +						node->valset = true;
   3.493 +						new (&node->value) K(obj);
   3.494 +					} else if (*keyptr == '\0') {	//EX: BADGER added over B -> ADGERHOUSE
   3.495 +						/* First backpatch the current node - it ends newly split input string.
   3.496 +						 * This is the exact opposite of the above procedure.
   3.497 +						 */
   3.498 +						node->valset = true;
   3.499 +						new (&node->value) K(obj);
   3.500 +
   3.501 +						/* Get the new base and apply re-basing */
   3.502 +						q = x_check(*term);
   3.503 +						node = &m_base[curidx];
   3.504 +
   3.505 +						node->idx = q;
   3.506 +						node->mode = Node_Arc;
   3.507 +						lastidx = curidx;
   3.508 +						/* Finish the final node */
   3.509 +						curidx = q + charval(*term);
   3.510 +						node = &m_base[curidx];
   3.511 +						term++;
   3.512 +						/* Optimize - don't add to string table if there's nothing more to eat */
   3.513 +						if (*term == '\0')
   3.514 +						{
   3.515 +							node->mode = Node_Arc;
   3.516 +						} else {
   3.517 +							node->idx = (term - m_stringtab); /* Already in the string table! */
   3.518 +							node->mode = Node_Term;
   3.519 +						}
   3.520 +						node->parent = lastidx;
   3.521 +						node->valset = oldvalset;
   3.522 +						if (node->valset)
   3.523 +						{
   3.524 +							new (&node->value) K(oldvalue);
   3.525 +						}
   3.526 +					} else {
   3.527 +						/* Finally, we have to create two new nodes instead of just one. */
   3.528 +						node->mode = Node_Arc;
   3.529 +
   3.530 +						/* Get the new base and apply re-basing */
   3.531 +						q = x_check2(*keyptr, *term);
   3.532 +						node = &m_base[curidx];
   3.533 +
   3.534 +						node->idx = q;
   3.535 +						lastidx = curidx;
   3.536 +
   3.537 +						/* Re-create the old terminated node */
   3.538 +						curidx = q + charval(*term);
   3.539 +						node = &m_base[curidx];
   3.540 +						term++;
   3.541 +						node->valset = oldvalset;
   3.542 +						if (node->valset)
   3.543 +						{
   3.544 +							new (&node->value) K(oldvalue);
   3.545 +						}
   3.546 +						node->parent = lastidx;
   3.547 +						if (*term == '\0')
   3.548 +						{
   3.549 +							node->mode = Node_Arc;
   3.550 +						} else {
   3.551 +							node->mode = Node_Term;
   3.552 +							node->idx = (term - m_stringtab); /* Already in the string table! */
   3.553 +						}
   3.554 +
   3.555 +						/* Create the new keyed input node */
   3.556 +						curidx = q + charval(*keyptr);
   3.557 +						node = &m_base[curidx];
   3.558 +						keyptr++;
   3.559 +						node->valset = true;
   3.560 +						new (&node->value) K(obj);
   3.561 +						node->parent = lastidx;
   3.562 +						if (*keyptr == '\0')
   3.563 +						{
   3.564 +							node->mode = Node_Arc;
   3.565 +						} else {
   3.566 +							node->mode = Node_Term;
   3.567 +							node->idx = x_addstring(keyptr);
   3.568 +						}
   3.569 +					}
   3.570 +
   3.571 +					/* Phew! */
   3.572 +					return true;
   3.573 +				} else {
   3.574 +					assert(node->mode == Node_Arc);
   3.575 +				}
   3.576 +			}
   3.577 +			lastidx = curidx;
   3.578 +		} while (*keyptr != '\0');
   3.579 +
   3.580 +		assert(node);
   3.581 +
   3.582 +		/* If we've exhausted the string and we have a valid reached node,
   3.583 +		 * the production rule already existed.  Make sure it's valid to set first.
   3.584 +		 */
   3.585 +
   3.586 +		/* We have to be an Arc.  If the last result was anything else, we would have returned a new 
   3.587 +		 * production earlier.
   3.588 +		 */
   3.589 +		assert(node->mode == Node_Arc);
   3.590 +
   3.591 +		if (!node->valset)
   3.592 +		{
   3.593 +			node->valset = true;
   3.594 +			new (&node->value) K(obj);
   3.595 +			return true;
   3.596 +		}
   3.597 +
   3.598 +		return false;
   3.599 +	}
   3.600 +public:
   3.601 +	KTrie()
   3.602 +	{
   3.603 +		m_base = (KTrieNode *)malloc(sizeof(KTrieNode) * (256 + 1));
   3.604 +		m_stringtab = (char *)malloc(sizeof(char) * 256);
   3.605 +		m_baseSize = 256;
   3.606 +		m_stSize = 256;
   3.607 +
   3.608 +		internal_clear();
   3.609 +	}
   3.610 +	~KTrie()
   3.611 +	{
   3.612 +		run_destructors();
   3.613 +		free(m_base);
   3.614 +		free(m_stringtab);
   3.615 +	}
   3.616 +private:
   3.617 +	class KTrieNode
   3.618 +	{
   3.619 +		friend class KTrie;
   3.620 +	private:
   3.621 +		/**
   3.622 +		 * For Node_Arc, this index stores the 'base' offset to the next arc chain.
   3.623 +		 *   I.e. to jump from this arc to character C, it will be at base[idx+C].
   3.624 +		 * For Node_Term, this is an index into the string table.
   3.625 +		 */
   3.626 +		unsigned int idx;	
   3.627 +
   3.628 +		/**
   3.629 +		 * This contains the prior arc that we must have come from.
   3.630 +		 * For example, if arc 63 has a base jump of index 12, and we want to see if
   3.631 +		 * there is a valid character C, the parent of 12+C must be 63.
   3.632 +		 */
   3.633 +		unsigned int parent;
   3.634 +		K value;				/* Value associated with this node */
   3.635 +		NodeType mode;			/* Current usage type of the node */
   3.636 +		bool valset;			/* Whether or not a value is set */
   3.637 +	};
   3.638 +private:
   3.639 +	KTrieNode *internal_retrieve(const char *key)
   3.640 +	{
   3.641 +		unsigned int lastidx = 1;		/* the last node index */
   3.642 +		unsigned int curidx;			/* current node index */
   3.643 +		const char *keyptr = key;		/* input stream at current token */
   3.644 +		KTrieNode *node = NULL;			/* current node being processed */
   3.645 +
   3.646 +		if (!*key)
   3.647 +		{
   3.648 +			return NULL;
   3.649 +		}
   3.650 +
   3.651 +		/* Start traversing at the root node */
   3.652 +		do
   3.653 +		{
   3.654 +			/* Find where the next character is, then advance */
   3.655 +			curidx = m_base[lastidx].idx;
   3.656 +			node = &m_base[curidx];
   3.657 +			curidx += charval(*keyptr);
   3.658 +			node = &m_base[curidx];
   3.659 +			keyptr++;
   3.660 +
   3.661 +			/* Check if this slot is supposed to be empty or is a collision */
   3.662 +			if ((curidx > m_baseSize) || node->mode == Node_Unused || node->parent != lastidx)
   3.663 +			{
   3.664 +				return NULL;
   3.665 +			} else if (node->mode == Node_Term) {
   3.666 +				char *term = &m_stringtab[node->idx];
   3.667 +				if (strcmp(keyptr, term) == 0)
   3.668 +				{
   3.669 +					break;
   3.670 +				}
   3.671 +			}
   3.672 +			lastidx = curidx;
   3.673 +		} while (*keyptr != '\0');
   3.674 +
   3.675 +		return node;
   3.676 +	}
   3.677 +	bool grow()
   3.678 +	{
   3.679 +		/* The current # of nodes in the tree is trie->baseSize + 1 */
   3.680 +		unsigned int cur_size = m_baseSize;
   3.681 +		unsigned int new_size = cur_size * 2;
   3.682 +
   3.683 +		KTrieNode *new_base = (KTrieNode *)malloc((new_size + 1) * sizeof(KTrieNode));
   3.684 +		if (!new_base)
   3.685 +		{
   3.686 +			return false;
   3.687 +		}
   3.688 +
   3.689 +		memcpy(new_base, m_base, sizeof(KTrieNode) * (m_baseSize + 1));
   3.690 +		memset(&new_base[cur_size + 1], 0, (new_size - cur_size) * sizeof(KTrieNode));
   3.691 +
   3.692 +		for (size_t i = 0; i <= m_baseSize; i++)
   3.693 +		{
   3.694 +			if (m_base[i].valset)
   3.695 +			{
   3.696 +				/* Placement construct+copy the object, then placement destroy the old. */
   3.697 +				new (&new_base[i].value) K(m_base[i].value);
   3.698 +				m_base[i].value.~K();
   3.699 +			}
   3.700 +		}
   3.701 +
   3.702 +		free(m_base);
   3.703 +		m_base = new_base;
   3.704 +		m_baseSize = new_size;
   3.705 +
   3.706 +		return true;
   3.707 +	}
   3.708 +	inline unsigned char charval(char c)
   3.709 +	{
   3.710 +		return (unsigned char)c;
   3.711 +	}
   3.712 +	void internal_clear()
   3.713 +	{
   3.714 +		m_tail = 0;
   3.715 +
   3.716 +		memset(m_base, 0, sizeof(KTrieNode) * (m_baseSize + 1));
   3.717 +		memset(m_stringtab, 0, sizeof(char) * m_stSize);
   3.718 +
   3.719 +		/* Sentinel root node */
   3.720 +		m_base[1].idx = 1;
   3.721 +		m_base[1].mode = Node_Arc;
   3.722 +		m_base[1].parent = 1;
   3.723 +	}
   3.724 +	void run_destructors()
   3.725 +	{
   3.726 +		for (size_t i = 0; i <= m_baseSize; i++)
   3.727 +		{
   3.728 +			if (m_base[i].valset)
   3.729 +			{
   3.730 +				m_base[i].value.~K();
   3.731 +			}
   3.732 +		}
   3.733 +	}
   3.734 +	unsigned int x_addstring(const char *ptr)
   3.735 +	{
   3.736 +		size_t len = strlen(ptr) + 1;
   3.737 +
   3.738 +		if (m_tail + len >= m_stSize)
   3.739 +		{		
   3.740 +			while (m_tail + len >= m_stSize)
   3.741 +			{
   3.742 +				m_stSize *= 2;
   3.743 +			}
   3.744 +			m_stringtab = (char *)realloc(m_stringtab,m_stSize);
   3.745 +		}
   3.746 +
   3.747 +		unsigned int tail = m_tail;
   3.748 +		strcpy(&m_stringtab[tail], ptr);
   3.749 +		m_tail += len;
   3.750 +
   3.751 +		return tail;
   3.752 +	}
   3.753 +	unsigned int x_check(char c, unsigned int start=1)
   3.754 +	{
   3.755 +		unsigned char _c = charval(c);
   3.756 +		unsigned int to_check = m_baseSize - _c;
   3.757 +		for (unsigned int i=start; i<=to_check; i++)
   3.758 +		{
   3.759 +			if (m_base[i+_c].mode == Node_Unused)
   3.760 +			{
   3.761 +				return i;
   3.762 +			}
   3.763 +		}
   3.764 +
   3.765 +		grow();
   3.766 +
   3.767 +		return x_check(c, to_check+1);
   3.768 +	}
   3.769 +	unsigned int x_check2(char c1, char c2, unsigned int start=1)
   3.770 +	{
   3.771 +		unsigned char _c1 = charval(c1);
   3.772 +		unsigned char _c2 = charval(c2);
   3.773 +		unsigned int to_check = m_baseSize - (_c1 > _c2 ? _c1 : _c2);
   3.774 +		for (unsigned int i=start; i<=to_check; i++)
   3.775 +		{
   3.776 +			if (m_base[i+_c1].mode == Node_Unused
   3.777 +				&& m_base[i+_c2].mode == Node_Unused)
   3.778 +			{
   3.779 +				return i;
   3.780 +			}
   3.781 +		}
   3.782 +
   3.783 +		grow();
   3.784 +
   3.785 +		return x_check2(c1, c2, to_check+1);
   3.786 +	}
   3.787 +	unsigned int x_check_multi(
   3.788 +		unsigned int offsets[], 
   3.789 +		unsigned int count,
   3.790 +		unsigned int start=1)
   3.791 +	{
   3.792 +		KTrieNode *cur;
   3.793 +		unsigned int to_check = m_baseSize;
   3.794 +		unsigned int highest = 0;
   3.795 +
   3.796 +		for (unsigned int i=0; i<count; i++)
   3.797 +		{
   3.798 +			if (offsets[i] > highest)
   3.799 +			{
   3.800 +				highest = offsets[i];
   3.801 +			}
   3.802 +		}
   3.803 +
   3.804 +		to_check -= highest;
   3.805 +
   3.806 +		for (unsigned int i=start; i<=to_check; i++)
   3.807 +		{
   3.808 +			bool okay = true;
   3.809 +			for (unsigned int j=0; j<count; j++)
   3.810 +			{
   3.811 +				cur = &m_base[i+offsets[j]];
   3.812 +				if (cur->mode != Node_Unused)
   3.813 +				{
   3.814 +					okay = false;
   3.815 +					break;
   3.816 +				}
   3.817 +			}
   3.818 +			if (okay)
   3.819 +			{
   3.820 +				return i;
   3.821 +			}
   3.822 +		}
   3.823 +
   3.824 +		grow();
   3.825 +
   3.826 +		return x_check_multi(offsets, count, to_check+1);
   3.827 +	}
   3.828 +private:
   3.829 +	KTrieNode *m_base;			/* Base array for the sparse tables */
   3.830 +	char *m_stringtab;			/* String table pointer */
   3.831 +	unsigned int m_baseSize;	/* Size of the base array, in members */
   3.832 +	unsigned int m_stSize;		/* Size of the string table, in bytes */
   3.833 +	unsigned int m_tail;		/* Current unused offset into the string table */
   3.834 +};
   3.835 +
   3.836 +/**
   3.837 + * Double Array Trie algorithm, based on:
   3.838 + * An Efficient Implementation of Trie Structures, by
   3.839 + *  Jun-ichi Aoe and Katsushi Maromoto, and Takashi Sato
   3.840 + * from Software - Practice and Experience, Vol. 22(9), 695-721 (September 1992)
   3.841 + *
   3.842 + *  A Trie is a simple data structure which stores strings as DFAs, with each 
   3.843 + * transition state being a string entry.  For example, observe the following strings:
   3.844 + *
   3.845 + * BAILOPAN, BAT, BACON, BACK
   3.846 + *  These transition as the follow production rules:
   3.847 + *  B -> ...                  B
   3.848 + *       A -> ...             BA
   3.849 + *            I -> ...        BAI
   3.850 + *                 LOPAN      BAILOPAN
   3.851 + *            T -> ...        BAT
   3.852 + *            C ->            BAC
   3.853 + *                 O -> ...   BACO
   3.854 + *                      N     BACON
   3.855 + *                 K          BACK
   3.856 + *
   3.857 + *  The standard implementation for this - using lists - gives a slow linear lookup, somewhere between
   3.858 + * O(N+M) or O(log n).  A faster implementation is proposed in the paper above, which is based on compacting
   3.859 + * the transition states into two arrays.  In the paper's implementation, two arrays are used, and thus it is
   3.860 + * called the "Double Array" algorithm.  However, the CHECK array's size is maintained the same as BASE, 
   3.861 + * so they can be combined into one structure.  The array seems complex at first, but is very simple: it is a
   3.862 + * tree structure flattened out into a single vector.  I am calling this implementation the Flat Array Trie.
   3.863 + *
   3.864 + *  BASE[] is an array where each member is a node in the Trie.  The node can either be UNUSED (empty), an ARC
   3.865 + * (containing an offset to the next set of ARCs), or a TERMINATOR (contains the rest of a string).
   3.866 + * Each node has an index which must be interpreted based on the node type.  If the node is a TERMINATOR, then the
   3.867 + * index is an index into a string table, to find the rest of the string.  
   3.868 + *  If the node is an ARC, the index is another index into BASE.  For each possible token that can follow the
   3.869 + * current token, the value of those tokens can be added to the index given in the ARC.  Thus, given a current
   3.870 + * position and the next desired token, the current arc will jump to another arc which can contain either:
   3.871 + *   1) An invalid production (collision, no entry exists)
   3.872 + *   2) An empty production (no entry exists)
   3.873 + *   3) Another arc label (the string ends here or continues into more productions)
   3.874 + *   4) A TERMINATOR (the string ends here and contains an unused set of productions)
   3.875 + * 
   3.876 + *  So, given current offset N (starting at N=1), jumping to token C means the next offset will be:
   3.877 + *      offs = BASE[n] + C
   3.878 + *  Thus, the next node will be at:
   3.879 + *      BASE[BASE[n] + C]
   3.880 + * 
   3.881 + *  This allows each ARC to specify the base offset for any of its ARC children, like a tree.  Each node specifies
   3.882 + * its parent ARC -- so if an invalid offset is specified, the parent will not match, and thus no such derived 
   3.883 + * string exists.
   3.884 + *
   3.885 + *  This means that arrays can be laid out "sparsely," maximizing their usage.  Note that N need not be related to
   3.886 + * the range of tokens (1-256).  I.e., a base index does not have to be at 1, 256, 512, et cetera.  This is because
   3.887 + * insertion comes with a small deal of complexity.  To insert a new set of tokens T, the algorithm finds a new 
   3.888 + * BASE index N such that BASE[N+T[i]] is unused for each T[i].  Thus, indirection is not necessarily linear; 
   3.889 + * traversing a chain of ARC nodes can _and will_ jump around BASE.
   3.890 + *
   3.891 + *  Of course, given this level of flexibility in the array organization, there are collisions.  This is largely 
   3.892 + * where insertions become slow, as the old chain must be relocated before the new one is used.  Relocation means 
   3.893 + * finding one or more new base indexes, and this means traversing BASE until an acceptable index is found, such 
   3.894 + * that each offset is unused (see description in previous paragraph).
   3.895 + *
   3.896 + *  However, it is not insertion time we are concerned about.  The "trie" name comes from reTRIEval.  We are only
   3.897 + * concerned with lookup and deletion.  Both lookup and deletion are O(k), where k is relative to the length of the 
   3.898 + * input string.  Note that it is best case O(1) and worst case O(k).  Deleting the entire trie is always O(1).
   3.899 + */
   3.900 +
   3.901 +#endif //_INCLUDE_SOURCEMOD_TEMPLATED_TRIE_H_