/* Example which creates a dictionary using the "trie" datastructure */ class trieClass { var conts; const STRIDE = 4; // The conts are an array of [n*STRIDE] quads // These are the offsets of the subcomponents of each triple. const CHAR = 0, CHILD = 1, NEXT = 2, VAL = 3; const INITSIZE = 128; // Pick a reasonable size // Allocate the initial conts array with an optional first argument size public proc create() { var size = INITSIZE; if (oadl::nargs()) size = oadl::arg(0); conts = new Array(size, STRIDE); conts[0,CHAR] = "TRIE"; // Just for debugging conts[0,NEXT] = 1; // Allocate first slot to track # used } // Allocate a node. Extents conts if needed. proc alloc() { var used = conts[0,NEXT]; var len = conts.length(); var res = used; // Extend the array if needed if (used >= len) { conts = conts.reshape(len*2, STRIDE); } // Increment and store the used count used++; conts[0,NEXT] = used; // Initialize and return the next available slot conts[res,[CHAR,VAL,CHILD,NEXT]] = nil; return res; } proc insert(key, val) { var used = conts[0,NEXT]; var keyLen = key.length(); var curr = (used == 1) ? nil : 1; var ch = keyLen ? key[0] : nil; while (keyLen) { // Find the current char in the linked list at this level var prev = nil; while ((curr != nil) && (conts[curr,CHAR] != ch)) { prev = curr; curr = conts[curr,NEXT]; } if (curr == nil) { // Not found. Create a new entry. curr = alloc(); conts[curr,CHAR] = ch; if (prev != nil) conts[prev,NEXT] = curr; } // We now have a node with ch in it if (keyLen == 1) { // We are done! Insert the value at this position conts[curr,VAL] = val; return; } // Get the suffix of the key and continue key = key[1:]; ch = key[0]; keyLen--; // Descend one level var level = conts[curr,CHILD]; if (!level) { // Need to create a new level so we can descend level = alloc(); conts[curr,CHILD] = level; conts[level,CHAR] = ch; } // Start iterating at this lower level curr = level; } } proc lookup(key) { var used = conts[0,NEXT]; var keyLen = key.length(); var curr = (used == 1) ? nil : 1; var ch = keyLen ? key[0] : nil; while (keyLen) { // Find the current char in the linked list at this level while ((curr != nil) && (conts[curr,CHAR] != ch)) { curr = conts[curr,NEXT]; } if (curr == nil) return nil; // Not found. Not in trie. // We now have a node with ch in it if (keyLen == 1) { // End of string. See if there is a value. var val = conts[curr,VAL]; if (val != nil) return val; // Check to see if there is a unique suffix curr = conts[curr,CHILD]; while (curr) { if (conts[curr,NEXT]) return nil; // Not unique var child = conts[curr,CHILD]; val = conts[curr,VAL]; if (val != nil) { // Found a value at this level. If there are no // children, then this was a unique suffix. return (child == nil) ? val : nil; } // Descend one level curr = child; } // This should not happen... return nil; } // Get the suffix of the key and continue key = key[1:]; ch = key[0]; keyLen--; // Descend one level curr = conts[curr,CHILD]; if (!curr) return nil; // Badness. Not found. } } // Overload array index assignment as "insert", just like a Dict operator [=] (key, val) { insert(key, val); } // Overload array index fetch as "lookup", just like a dict operator [] (key) { return lookup(key); } public proc print() { var used = conts[0,NEXT]; // SL - left adjust; / - advance to next line after format ::print("SL,4V6,V,/", // The header row {"#", "CH","CHLD","NEXT","VAL"}, // The number column [used,1].iterate(), // The chars WideChar(conts[0:used-1,0]), // The contents conts[0:used-1,1:]); } } proc main() { var trie = new trieClass(); trie["fred"] = 1; trie["foo"] = 2; trie["bar"] = 3; "fred = ", trie["fred"], '\n'; "foo = ", trie["foo" ], '\n'; "bar = ", trie["bar" ], '\n'; "fr = ", trie["fr" ], '\n'; trie.print(); }