core/sm_trie.cpp
author David Anderson <dvander@alliedmods.net>
Wed Aug 01 02:12:47 2007 +0000 (2007-08-01)
changeset 1231 17badaf66ce4
parent 1088 9d662430f42b
child 1330 ab94316bb52b
permissions -rw-r--r--
updated more header files (mostly internal now)
     1 /**
     2  * vim: set ts=4 :
     3  * ================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * ================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or 
     9  * modify it under the terms of the GNU General Public License, 
    10  * version 3.0, as published by the Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  * GNU General Public License for more details.
    16  *
    17  * You should have received a copy of the GNU General Public License
    18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to 
    21  * link the code of this program (as well as its derivative works) to 
    22  * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any 
    23  * Game MODs that run on software by the Valve Corporation.  You must 
    24  * obey the GNU General Public License in all respects for all other 
    25  * code used. Additionally, AlliedModders LLC grants this exception 
    26  * to all derivative works. AlliedModders LLC defines further 
    27  * exceptions, found in LICENSE.txt (as of this writing, version 
    28  * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
    29  *
    30  * Version: $Id$
    31  */
    32 
    33 #include <string.h>
    34 #include <stdlib.h>
    35 #include <assert.h>
    36 #include "sm_trie.h"
    37 
    38 /**
    39  * Double Array Trie algorithm, based on:
    40  * An Efficient Implementation of Trie Structures, by
    41  *  Jun-ichi Aoe and Katsushi Maromoto, and Takashi Sato
    42  * from Software - Practice and Experience, Vol. 22(9), 695-721 (September 1992)
    43  *
    44  *  A Trie is a simple data structure which stores strings as DFAs, with each 
    45  * transition state being a string entry.  For example, observe the following strings:
    46  *
    47  * BAILOPAN, BAT, BACON, BACK
    48  *  These transition as the follow production rules:
    49  *  B -> ...                  B
    50  *       A -> ...             BA
    51  *            I -> ...        BAI
    52  *                 LOPAN      BAILOPAN
    53  *            T -> ...        BAT
    54  *            C ->            BAC
    55  *                 O -> ...   BACO
    56  *                      N     BACON
    57  *                 K          BACK
    58  *
    59  *  The standard implementation for this - using lists - gives a slow linear lookup, somewhere between
    60  * O(N+M) or O(log n).  A faster implementation is proposed in the paper above, which is based on compacting
    61  * the transition states into two arrays.  In the paper's implementation, two arrays are used, and thus it is
    62  * called the "Double Array" algorithm.  However, the CHECK array's size is maintained the same as BASE, 
    63  * so they can be combined into one structure.  The array seems complex at first, but is very simple: it is a
    64  * tree structure flattened out into a single vector.  I am calling this implementation the Flat Array Trie.
    65  *
    66  *  BASE[] is an array where each member is a node in the Trie.  The node can either be UNUSED (empty), an ARC
    67  * (containing an offset to the next set of ARCs), or a TERMINATOR (contains the rest of a string).
    68  * Each node has an index which must be interpreted based on the node type.  If the node is a TERMINATOR, then the
    69  * index is an index into a string table, to find the rest of the string.  
    70  *  If the node is an ARC, the index is another index into BASE.  For each possible token that can follow the
    71  * current token, the value of those tokens can be added to the index given in the ARC.  Thus, given a current
    72  * position and the next desired token, the current arc will jump to another arc which can contain either:
    73  *   1) An invalid production (collision, no entry exists)
    74  *   2) An empty production (no entry exists)
    75  *   3) Another arc label (the string ends here or continues into more productions)
    76  *   4) A TERMINATOR (the string ends here and contains an unused set of productions)
    77  * 
    78  *  So, given current offset N (starting at N=1), jumping to token C means the next offset will be:
    79  *      offs = BASE[n] + C
    80  *  Thus, the next node will be at:
    81  *      BASE[BASE[n] + C]
    82  * 
    83  *  This allows each ARC to specify the base offset for any of its ARC children, like a tree.  Each node specifies
    84  * its parent ARC -- so if an invalid offset is specified, the parent will not match, and thus no such derived 
    85  * string exists.
    86  *
    87  *  This means that arrays can be laid out "sparsely," maximizing their usage.  Note that N need not be related to
    88  * 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
    89  * insertion comes with a small deal of complexity.  To insert a new set of tokens T, the algorithm finds a new 
    90  * BASE index N such that BASE[N+T[i]] is unused for each T[i].  Thus, indirection is not necessarily linear; 
    91  * traversing a chain of ARC nodes can _and will_ jump around BASE.
    92  *
    93  *  Of course, given this level of flexibility in the array organization, there are collisions.  This is largely 
    94  * where insertions become slow, as the old chain must be relocated before the new one is used.  Relocation means 
    95  * finding one or more new base indexes, and this means traversing BASE until an acceptable index is found, such 
    96  * that each offset is unused (see description in previous paragraph).
    97  *
    98  *  However, it is not insertion time we are concerned about.  The "trie" name comes from reTRIEval.  We are only
    99  * concerned with lookup and deletion.  Both lookup and deletion are O(k), where k is relative to the length of the 
   100  * input string.  Note that it is best case O(1) and worst case O(k).  Deleting the entire trie is always O(1).
   101  */
   102 
   103 /**
   104  * Optimization ideas for the future:
   105  * 1) Store a reference count for each arc, with the count of sub-children.
   106  *    This could let us break out of "children searches" for case 4 easily.
   107  * 2) Use a 'free list' so we can easily search the trie for free points.
   108  *    This would drastically speed up x_check*
   109  */
   110 
   111 enum NodeType
   112 {
   113 	Node_Unused = 0,		/* Node is not being used (sparse) */
   114 	Node_Arc,				/* Node is part of an arc and does not terminate */
   115 	Node_Term,				/* Node is a terminator */
   116 };
   117 
   118 struct TrieNode
   119 {
   120 	/**
   121 	 * For Node_Arc, this index stores the 'base' offset to the next arc chain.
   122 	 *   I.e. to jump from this arc to character C, it will be at base[idx+C].
   123 	 * For Node_Term, this is an index into the string table.
   124 	 */
   125 	unsigned int idx;
   126 
   127 	/**
   128 	 * This contains the prior arc that we must have come from.
   129 	 * For example, if arc 63 has a base jump of index 12, and we want to see if
   130 	 * there is a valid character C, the parent of 12+C must be 63.
   131 	 */
   132 	unsigned int parent;
   133 
   134 	void *value;			/* Value associated with this node */
   135 	NodeType mode;			/* Current usage type of the node */
   136 	bool valset;			/* Whether or not a value is set */
   137 };
   138 
   139 struct Trie
   140 {
   141 	TrieNode *base;			/* Base array for the sparse tables */
   142 	char *stringtab;		/* String table pointer */
   143 	unsigned int baseSize;	/* Size of the base array, in members */
   144 	unsigned int stSize;	/* Size of the string table, in bytes */
   145 	unsigned int tail;		/* Current unused offset into the string table */
   146 };
   147 
   148 inline unsigned char charval(char c)
   149 {
   150 	return (unsigned char)c;
   151 }
   152 
   153 bool sm_trie_grow(Trie *trie)
   154 {
   155 	/* The current # of nodes in the tree is trie->baseSize + 1 */
   156 	unsigned int curSize = trie->baseSize;
   157 	unsigned int newSize = curSize * 2;
   158 
   159 	//:TODO: Make functions calling this return failure if this fails 
   160 	trie->base = (TrieNode *)realloc(trie->base, (newSize + 1) * sizeof(TrieNode));
   161 	if (!trie->base)
   162 	{
   163 		return false;
   164 	}
   165 
   166 	memset(&trie->base[curSize+1], 0, (newSize - curSize) * sizeof(TrieNode));
   167 	trie->baseSize = newSize;
   168 
   169 	return true;
   170 }
   171 
   172 unsigned int x_check(Trie *trie, char c, unsigned int start=1)
   173 {
   174 	TrieNode *base = trie->base;
   175 	unsigned char _c = charval(c);
   176 	unsigned int to_check = trie->baseSize - _c;
   177 	for (unsigned int i=start; i<=to_check; i++)
   178 	{
   179 		if (base[i+_c].mode == Node_Unused)
   180 		{
   181 			return i;
   182 		}
   183 	}
   184 
   185 	sm_trie_grow(trie);
   186 
   187 	return x_check(trie, c, to_check+1);
   188 }
   189 
   190 unsigned int x_check2(Trie *trie, char c1, char c2, unsigned int start=1)
   191 {
   192 	TrieNode *base = trie->base;
   193 	unsigned char _c1 = charval(c1);
   194 	unsigned char _c2 = charval(c2);
   195 	unsigned int to_check = trie->baseSize - (_c1 > _c2 ? _c1 : _c2);
   196 	for (unsigned int i=start; i<=to_check; i++)
   197 	{
   198 		if (base[i+_c1].mode == Node_Unused
   199 			&& base[i+_c2].mode == Node_Unused)
   200 		{
   201 			return i;
   202 		}
   203 	}
   204 
   205 	sm_trie_grow(trie);
   206 
   207 	return x_check2(trie, c1, c2, to_check+1);
   208 }
   209 
   210 unsigned int x_check_multi(Trie *trie, 
   211 							unsigned int offsets[], 
   212 							unsigned int count,
   213 							unsigned int start=1)
   214 {
   215 	TrieNode *base = trie->base;
   216 	TrieNode *cur;
   217 	unsigned int to_check = trie->baseSize;
   218 	unsigned int highest = 0;
   219 
   220 	for (unsigned int i=0; i<count; i++)
   221 	{
   222 		if (offsets[i] > highest)
   223 		{
   224 			highest = offsets[i];
   225 		}
   226 	}
   227 
   228 	to_check -= highest;
   229 
   230 	for (unsigned int i=start; i<=to_check; i++)
   231 	{
   232 		bool okay = true;
   233 		for (unsigned int j=0; j<count; j++)
   234 		{
   235 			cur = &base[i+offsets[j]];
   236 			if (cur->mode != Node_Unused)
   237 			{
   238 				okay = false;
   239 				break;
   240 			}
   241 		}
   242 		if (okay)
   243 		{
   244 			return i;
   245 		}
   246 	}
   247 
   248 	sm_trie_grow(trie);
   249 
   250 	return x_check_multi(trie, offsets, count, to_check+1);
   251 }
   252 
   253 unsigned int x_addstring(Trie *trie, const char *ptr)
   254 {
   255 	size_t len = strlen(ptr) + 1;
   256 
   257 	if (trie->tail + len >= trie->stSize)
   258 	{		
   259 		while (trie->tail + len >= trie->stSize)
   260 		{
   261 			trie->stSize *= 2;
   262 		}
   263 		trie->stringtab = (char *)realloc(trie->stringtab, trie->stSize);
   264 	}
   265 
   266 	unsigned int tail = trie->tail;
   267 	strcpy(&trie->stringtab[tail], ptr);
   268 	trie->tail += len;
   269 
   270 	return tail;
   271 }
   272 
   273 Trie *sm_trie_create()
   274 {
   275 	Trie *t = new Trie;
   276 
   277 	t->base = (TrieNode *)malloc(sizeof(TrieNode) * (256 + 1));
   278 	t->stringtab = (char *)malloc(sizeof(char) * 256);
   279 	t->baseSize = 256;
   280 	t->stSize = 256;
   281 
   282 	sm_trie_clear(t);
   283 
   284 	return t;
   285 }
   286 
   287 void sm_trie_clear(Trie *trie)
   288 {
   289 	trie->tail = 0;
   290 
   291 	memset(trie->base, 0, sizeof(TrieNode) * (trie->baseSize + 1));
   292 	memset(trie->stringtab, 0, sizeof(char) * trie->stSize);
   293 
   294 	/* Sentinel root node */
   295 	trie->base[1].idx = 1;
   296 	trie->base[1].mode = Node_Arc;
   297 	trie->base[1].parent = 1;
   298 }
   299 
   300 void sm_trie_destroy(Trie *trie)
   301 {
   302 	free(trie->base);
   303 	free(trie->stringtab);
   304 	delete trie;
   305 }
   306 
   307 bool sm_trie_delete(Trie *trie, const char *key)
   308 {
   309 	unsigned int lastidx = 1;		/* the last node index */
   310 	unsigned int curidx;			/* current node index */
   311 	const char *keyptr = key;		/* input stream at current token */
   312 	TrieNode *node = NULL;			/* current node being processed */
   313 	TrieNode *base = trie->base;
   314 
   315 	if (!*key)
   316 	{
   317 		return false;
   318 	}
   319 
   320 	/* Start traversing at the root node */
   321 	do
   322 	{
   323 		/* Find where the next character is, then advance */
   324 		curidx = base[lastidx].idx;
   325 		node = &base[curidx];
   326 		curidx += charval(*keyptr);
   327 		node = &base[curidx];
   328 		keyptr++;
   329 
   330 		/* Check if this slot is supposed to be empty or is a collision */
   331 		if ((curidx > trie->baseSize) || node->mode == Node_Unused || node->parent != lastidx)
   332 		{
   333 			return false;
   334 		} else if (node->mode == Node_Term) {
   335 			char *term = &trie->stringtab[node->idx];
   336 			if (strcmp(keyptr, term) == 0)
   337 			{
   338 				break;
   339 			}
   340 		}
   341 		lastidx = curidx;
   342 	} while (*keyptr != '\0');
   343 
   344 	assert(node != NULL);
   345 
   346 	if (!node->valset)
   347 	{
   348 		return false;
   349 	}
   350 
   351 	node->valset = false;
   352 	node->value = NULL;
   353 
   354 	return true;
   355 }
   356 
   357 bool sm_trie_retrieve(Trie *trie, const char *key, void **value)
   358 {
   359 	unsigned int lastidx = 1;		/* the last node index */
   360 	unsigned int curidx;			/* current node index */
   361 	const char *keyptr = key;		/* input stream at current token */
   362 	TrieNode *node = NULL;			/* current node being processed */
   363 	TrieNode *base = trie->base;
   364 
   365 	if (!*key)
   366 	{
   367 		return false;
   368 	}
   369 
   370 	/* Start traversing at the root node */
   371 	do
   372 	{
   373 		/* Find where the next character is, then advance */
   374 		curidx = base[lastidx].idx;
   375 		node = &base[curidx];
   376 		curidx += charval(*keyptr);
   377 		node = &base[curidx];
   378 		keyptr++;
   379 
   380 		/* Check if this slot is supposed to be empty or is a collision */
   381 		if ((curidx > trie->baseSize) || node->mode == Node_Unused || node->parent != lastidx)
   382 		{
   383 			return false;
   384 		} else if (node->mode == Node_Term) {
   385 			char *term = &trie->stringtab[node->idx];
   386 			if (strcmp(keyptr, term) == 0)
   387 			{
   388 				break;
   389 			}
   390 		}
   391 		lastidx = curidx;
   392 	} while (*keyptr != '\0');
   393 
   394 	assert(node != NULL);
   395 
   396 	if (!node->valset)
   397 	{
   398 		return false;
   399 	}
   400 
   401 	if (value)
   402 	{
   403 		*value = node->value;
   404 	}
   405 
   406 	return true;
   407 }
   408 
   409 bool sm_trie_add(Trie *trie, const char *key, void *value, bool replace_allowed)
   410 {
   411 	unsigned int lastidx = 1;		/* the last node index */
   412 	unsigned int curidx;			/* current node index */
   413 	const char *keyptr = key;		/* input stream at current token */
   414 	TrieNode *node = NULL;			/* current node being processed */
   415 	TrieNode *basenode = NULL;		/* current base node being processed */
   416 	unsigned int q;					/* temporary var for x_check results */
   417 	TrieNode *base = trie->base;
   418 	unsigned int curoffs;			/* current offset */
   419 
   420 	/* Do not handle empty strings for simplicity */
   421 	if (!*key)
   422 	{
   423 		return false;
   424 	}
   425 
   426 	/* Start traversing at the root node (1) */
   427 	do
   428 	{
   429 		/* Find where the next character is, then advance */
   430 		curidx = base[lastidx].idx;
   431 		basenode = &base[curidx];
   432 		curoffs = charval(*keyptr);
   433 		curidx += curoffs;
   434 		node = &base[curidx];
   435 		keyptr++;
   436 
   437 		/* Check if this slot is supposed to be empty.  If so, we need to handle CASES 1/2:
   438 		 * Insertion without collisions
   439 		 */
   440 		if ( (curidx > trie->baseSize) || (node->mode == Node_Unused) )
   441 		{
   442 			if (curidx > trie->baseSize)
   443 			{
   444 				if (!sm_trie_grow(trie))
   445 				{
   446 					return false;
   447 				}
   448 				node = &trie->base[curidx];
   449 			}
   450 			node->parent = lastidx;
   451 			if (*keyptr == '\0')
   452 			{
   453 				node->mode = Node_Arc;
   454 			} else {
   455 				node->idx = x_addstring(trie, keyptr);
   456 				node->mode = Node_Term;
   457 			}
   458 			node->valset = true;
   459 			node->value = value;
   460 			
   461 			return true;
   462 		} else if (node->parent != lastidx) {
   463 			/* Collision! We have to split up the tree here.  CASE 4:
   464 			 * Insertion when a new word is inserted with a collision.
   465 			 * NOTE: This is the hardest case to handle.  All below examples are based on:
   466 			 * BACHELOR, BADGE, inserting BABY.
   467 			 * The problematic production here is A -> B, where B is already being used.
   468 			 *
   469 			 * This process has to rotate one half of the 'A' arc.  We generate two lists:
   470 			 *  Outgoing Arcs - Anything leaving this 'A'
   471 			 *  Incoming Arcs - Anything going to this 'A'
   472 			 * Whichever list is smaller will be moved.  Note that this works because the intersection
   473 			 * affects both arc chains, and moving one will make the slot available to either.
   474 			 */
   475 			TrieNode *cur;
   476 			
   477 			/* Find every node arcing from the last node.
   478 			 * I.e. for BACHELOR, BADGE, BABY,
   479 			 * The arcs leaving A will be C and D, but our current node is B -> *.
   480 			 * Thus, we use the last index (A) to find the base for arcs leaving A.
   481 			 */
   482 			unsigned int outgoing_base = base[lastidx].idx;
   483 			unsigned int outgoing_list[256];
   484 			unsigned int outgoing_count = 0;	/* count the current index here */
   485 			cur = &base[outgoing_base] + 1;
   486 			unsigned int outgoing_limit = 255;
   487 
   488 			if (outgoing_base + outgoing_limit > trie->baseSize)
   489 			{
   490 				outgoing_limit = trie->baseSize - outgoing_base;
   491 			}
   492 
   493 			for (unsigned int i=1; i<=outgoing_limit; i++,cur++)
   494 			{
   495 				if (cur->mode == Node_Unused || cur->parent != lastidx)
   496 				{
   497 					continue;
   498 				}
   499 				outgoing_list[outgoing_count++] = i;
   500 			}
   501 			outgoing_list[outgoing_count++] = curidx - outgoing_base;
   502 
   503 			/* Now we need to find all the arcs leaving our parent...
   504 			 * Note: the inconsistency is the base of our parent.  
   505 			 */
   506 			assert(base[node->parent].mode == Node_Arc);
   507 			unsigned int incoming_list[256];
   508 			unsigned int incoming_base = base[node->parent].idx;
   509 			unsigned int incoming_count = 0;
   510 			unsigned int incoming_limit = 255;
   511 			cur = &base[incoming_base] + 1;
   512 
   513 			if (incoming_base + incoming_limit > trie->baseSize)
   514 			{
   515 				incoming_limit = trie->baseSize - incoming_base;
   516 			}
   517 
   518 			assert(incoming_limit > 0 && incoming_limit <= 255);
   519 
   520 			for (unsigned int i=1; i<=incoming_limit; i++,cur++)
   521 			{
   522 				if (cur->mode == Node_Arc || cur->mode == Node_Term)
   523 				{
   524 					if (cur->parent == node->parent)
   525 					{
   526 						incoming_list[incoming_count++] = i;
   527 					}
   528 				}
   529 			}
   530 
   531 			if (incoming_count < outgoing_count + 1)
   532 			{
   533 				unsigned int q = x_check_multi(trie, incoming_list, incoming_count);
   534 
   535 				base = trie->base;
   536 				node = &base[curidx];
   537 
   538 				/* If we're incoming, we need to modify our parent */
   539 				base[node->parent].idx = q;
   540 
   541 				/* For each node in the "to move" list,
   542 				 * Relocate the node's info to the new position.
   543 				 */
   544 				unsigned int idx, newidx, oldidx;
   545 				for (unsigned int i=0; i<incoming_count; i++)
   546 				{
   547 					idx = incoming_list[i];
   548 					newidx = q + idx;
   549 					oldidx = incoming_base + idx;
   550 					if (oldidx == lastidx)
   551 					{
   552 						/* Important! Make sure we're not invalidating our sacred lastidx */
   553 						lastidx = newidx;
   554 					}
   555 					base[newidx] = base[oldidx];
   556 					assert(base[base[newidx].parent].mode == Node_Arc);
   557 					memset(&base[oldidx], 0, sizeof(TrieNode));
   558 					/* If we are not a terminator, we have children we must take care of */
   559 					if (base[newidx].mode == Node_Arc)
   560 					{
   561 						TrieNode *check_base = &base[base[newidx].idx] + 1;
   562 						for (unsigned int j=1; j<=255; j++, check_base++)
   563 						{
   564 							if (check_base->parent == oldidx)
   565 							{
   566 								check_base->parent = newidx;
   567 							}
   568 						}
   569 					}
   570 				}
   571 			} else {
   572 				unsigned int q = x_check_multi(trie, outgoing_list, outgoing_count);
   573 
   574 				base = trie->base;
   575 				node = &base[curidx];
   576 
   577 				/* If we're outgoing, we need to modify our own base */
   578 				base[lastidx].idx = q;
   579 
   580 				/* Take the last index (curidx) out of the list.  Technically we are not moving this,
   581 				 * since it's already being used by something else.  
   582 				 */
   583 				outgoing_count--;
   584 
   585 				/* For each node in the "to move" list,
   586 				 * Relocate the node's info to the new position.
   587 				 */
   588 				unsigned int idx, newidx, oldidx;
   589 				for (unsigned int i=0; i<outgoing_count; i++)
   590 				{
   591 					idx = outgoing_list[i];
   592 					newidx = q + idx;
   593 					oldidx = outgoing_base + idx;
   594 					if (oldidx == lastidx)
   595 					{
   596 						/* Important! Make sure we're not invalidating our sacred lastidx */
   597 						lastidx = newidx;
   598 					}
   599 					base[newidx] = base[oldidx];
   600 					assert(base[base[newidx].parent].mode == Node_Arc);
   601 					memset(&base[oldidx], 0, sizeof(TrieNode));
   602 					/* If we are not a terminator, we have children we must take care of */
   603 					if (base[newidx].mode == Node_Arc)
   604 					{
   605 						TrieNode *check_base = &base[base[newidx].idx] + 1;
   606 						for (unsigned int j=1; j<=255; j++, check_base++)
   607 						{
   608 							if (check_base->parent == oldidx)
   609 							{
   610 								check_base->parent = newidx;
   611 							}
   612 						}
   613 					}
   614 				}
   615 
   616 				/* Take the invisible node and use it as our new node */
   617 				node = &base[q + outgoing_list[outgoing_count]];
   618 			}
   619 
   620 			/* We're finally done! */
   621 			node->parent = lastidx;
   622 			if (*keyptr == '\0')
   623 			{
   624 				node->mode = Node_Arc;
   625 			} else {
   626 				node->idx = x_addstring(trie, keyptr);
   627 				node->mode = Node_Term;
   628 			}
   629 			node->valset = true;
   630 			node->value = value;
   631 
   632 			return true;
   633 		} else {
   634 			/* See what's in the next node - special case if terminator! */
   635 			if (node->mode == Node_Term)
   636 			{
   637 				/* If we're a terminator, we need to handle CASE 3:
   638 				 * Insertion when a terminating collision occurs
   639 				 */
   640 				char *term = &trie->stringtab[node->idx];
   641 				/* Do an initial browsing to make sure they're not the same string */
   642 				if (strcmp(keyptr, term) == 0)
   643 				{
   644 					if (!node->valset || replace_allowed)
   645 					{
   646 						node->valset = true;
   647 						node->value = value;
   648 						return true;
   649 					}
   650 					/* Same string.  We can't insert. */
   651 					return false;
   652 				}
   653 				/* For each matching character pair, we need to disband the terminator.
   654 				 * This splits the similar prefix into a single arc path.
   655 				 * First, save the old values so we can move them to a new node.
   656 				 * Next, for each loop:
   657 				 *  Take the current (invalid) node, and point it to the next arc base.
   658 				 *  Set the current node to the node at the next arc.
   659 				 */
   660 				void *oldvalue = node->value;
   661 				bool oldvalset = node->valset;
   662 				if (*term == *keyptr)
   663 				{
   664 				while (*term == *keyptr)
   665 				{
   666 					/* Find the next free slot in the check array.
   667 					 * This is the "vector base" essentially
   668 					 */
   669 					q = x_check(trie, *term);
   670 						base = trie->base;
   671 						node = &base[curidx];
   672 					/* Point the node to the next new base */
   673 					node->idx = q;
   674 					node->mode = Node_Arc;
   675 					node->valset = false;
   676 					/* Advance the input stream and local variables */
   677 					lastidx = curidx;
   678 					curidx = q + charval(*term);
   679 					node = &base[curidx];
   680 					/* Make sure the new current node has its parent set. */
   681 					node->parent = lastidx;
   682 					node->mode = Node_Arc;	/* Just in case we run x_check again */
   683 					*term = '\0';	/* Unmark the string table here */
   684 					term++;
   685 					keyptr++;
   686 					}
   687 				} else {
   688 					node->valset = false;
   689 				}
   690 				/* We're done inserting new pairs.  If one of them is exhausted,
   691 				 * we take special shortcuts.
   692 				 */
   693 				if (*term == '\0')				//EX: BADGERHOUSE added over B -> ADGER.  
   694 				{
   695 					/* First backpatch the current node - it ends the newly split terminator.
   696 					 * In the example, this would mean the node is the production from R -> ?
   697 					 * This node ends the old BADGER, so we set it here.
   698 					 */
   699 					node->valset = oldvalset;
   700 					node->value = oldvalue;
   701 
   702 					/* The terminator was split up, but pieces of keyptr remain.
   703 					 * We need to generate a new production, in this example, R -> H,
   704 					 * with H being a terminator to OUSE.  Thus we get:
   705 					 * B,A,D,G,E,R*,H*->OUSE (* = value set).
   706 					 * NOTE: parent was last set at the end of the while loop.
   707 					 */
   708 					/* Get the new base and apply re-basing */
   709 					q = x_check(trie, *keyptr);
   710 					base = trie->base;
   711 					node = &base[curidx];
   712 
   713 					node->idx = q;
   714 					node->mode = Node_Arc;
   715 					lastidx = curidx;
   716 					/* Finish the final node */
   717 					curidx = q + charval(*keyptr);
   718 					node = &trie->base[curidx];
   719 					keyptr++;
   720 					/* Optimize - don't add to string table if there's nothing more to eat */
   721 					if (*keyptr == '\0')
   722 					{
   723 						node->mode = Node_Arc;
   724 					} else {
   725 						node->idx = x_addstring(trie, keyptr);
   726 						node->mode = Node_Term;
   727 					}
   728 					node->parent = lastidx;
   729 					node->valset = true;
   730 					node->value = value;
   731 				} else if (*keyptr == '\0') {	//EX: BADGER added over B -> ADGERHOUSE
   732 					/* First backpatch the current node - it ends newly split input string.
   733 					 * This is the exact opposite of the above procedure.
   734 					 */
   735 					node->valset = true;
   736 					node->value = value;
   737 
   738 					/* Get the new base and apply re-basing */
   739 					q = x_check(trie, *term);
   740 					base = trie->base;
   741 					node = &base[curidx];
   742 
   743 					node->idx = q;
   744 					node->mode = Node_Arc;
   745 					lastidx = curidx;
   746 					/* Finish the final node */
   747 					curidx = q + charval(*term);
   748 					node = &trie->base[curidx];
   749 					term++;
   750 					/* Optimize - don't add to string table if there's nothing more to eat */
   751 					if (*term == '\0')
   752 					{
   753 						node->mode = Node_Arc;
   754 					} else {
   755 						node->idx = (term - trie->stringtab); /* Already in the string table! */
   756 						node->mode = Node_Term;
   757 					}
   758 					node->parent = lastidx;
   759 					node->valset = oldvalset;
   760 					node->value = oldvalue;
   761 				} else {
   762 					/* Finally, we have to create two new nodes instead of just one. */
   763 					node->mode = Node_Arc;
   764 					
   765 					/* Get the new base and apply re-basing */
   766 					q = x_check2(trie, *keyptr, *term);
   767 					base = trie->base;
   768 					node = &base[curidx];
   769 
   770 					node->idx = q;
   771 					lastidx = curidx;
   772 
   773 					/* Re-create the old terminated node */
   774 					curidx = q + charval(*term);
   775 					node = &trie->base[curidx];
   776 					term++;
   777 					node->valset = oldvalset;
   778 					node->value = oldvalue;
   779 					node->parent = lastidx;
   780 					if (*term == '\0')
   781 					{
   782 						node->mode = Node_Arc;
   783 					} else {
   784 						node->mode = Node_Term;
   785 						node->idx = (term - trie->stringtab); /* Already in the string table! */
   786 					}
   787 
   788 					/* Create the new keyed input node */
   789 					curidx = q + charval(*keyptr);
   790 					node = &trie->base[curidx];
   791 					keyptr++;
   792 					node->valset = true;
   793 					node->value = value;
   794 					node->parent = lastidx;
   795 					if (*keyptr == '\0')
   796 					{
   797 						node->mode = Node_Arc;
   798 					} else {
   799 						node->mode = Node_Term;
   800 						node->idx = x_addstring(trie, keyptr);
   801 					}
   802 				}
   803 
   804 				/* Phew! */
   805 				return true;
   806 			} else {
   807 				assert(node->mode == Node_Arc);
   808 			}
   809 		}
   810 		lastidx = curidx;
   811 	} while (*keyptr != '\0');
   812 
   813 	assert(node);
   814 
   815 	/* If we've exhausted the string and we have a valid reached node,
   816 	 * the production rule already existed.  Make sure it's valid to set first.
   817 	 */
   818 
   819 	/* We have to be an Arc.  If the last result was anything else, we would have returned a new 
   820 	 * production earlier.
   821 	 */
   822 	assert(node->mode == Node_Arc);
   823 
   824 	if (!node->valset || replace_allowed)
   825 	{
   826 		/* Insert is only possible if we have no production */
   827 		node->valset = true;
   828 		node->value = value;
   829 		return true;
   830 	}
   831 
   832 	return false;
   833 }
   834 
   835 bool sm_trie_insert(Trie *trie, const char *key, void *value)
   836 {
   837 	return sm_trie_add(trie, key, value, false);
   838 }
   839 
   840 bool sm_trie_replace(Trie *trie, const char *key, void *value)
   841 {
   842 	return sm_trie_add(trie, key, value, true);
   843 }