home *** CD-ROM | disk | FTP | other *** search
- /***
- * Dict.prg
- * Keyed dictionary utility.
- * Copyright (c) 1991 Nantucket Corp. All rights reserved.
- *
- *
- * Uses an array to contain list of "dictionary" entries.
- * Each entry consists of a character key and a value of any type.
- * New keys and values can be entered, and existing values can be
- * retrieved based on their key.
- *
- *
- * DictNew() <-- <aDictionary>
- *
- * Creates and returns an empty dictionary.
- *
- *
- * DictAt( <aDictionary>, <cKey> ) <-- <xValue>
- *
- * Returns the value associated with <xKey> in dictionary,
- * NIL if <xKey> is not present in dictionary.
- *
- *
- * DictPut( <aDictionary>, <cKey>, <xValue> ) <-- <xValue>
- *
- * Associates <cKey> to <cValue> in <aDictionary>. Returns
- * <xValue>.
- *
- *
- * DictPutPair( <aDictionary>, <aPair> ) <-- <aPair>
- *
- * Adds <aPair> to <aDictionary>. Returns <aPair>.
- * <aPair> is a key/value pair: { <cKey>, <xValue> }.
- *
- *
- * DictRemove( <aDictionary>, <cKey> ) <-- <aDictionary>
- *
- * Removes the key/value pair for <cKey>.
- * Returns <aDictionary>.
- *
- *
- * DictEval( <aDictionary>, <bBlock> ) <-- <aDictionary>
- *
- * Evaluates <bBlock> against each <cKey>/<xValue> pair in
- * dictionary. Pair is passed to block as { <cKey>, <xValue> }
- * (pair array indexes defined in "dict.ch").
- * Returns <aDictionary>.
- *
- *
- * Notes:
- * Compile with /n/w/a/m
- *
- * Key values must all be type 'C', case is significant.
- *
- * These dictionaries are useful if you want to keep a list
- * of keyed values without using a database. Since they're
- * arrays, you can hange onto them with any variable or
- * array element (handy for keeping track of multiple "cargo"
- * items, for example). If you have lots of values, though,
- * a database/index is usually more appropriate.
- *
- */
-
-
- #include "dict.ch"
-
-
- // hash machinery
- #define KEY_HASH(key) ( Bin2W(key) + Bin2W( SubStr(Trim(key), -2) ) )
- #define HASH_VAL(key, size) ( ( KEY_HASH(key) % size ) + 1 )
-
- #define DEFAULT_HASH_SIZE 31
- #define MAX_ARRAY_LEN 4096
-
-
-
- /***
- * DictNew()
- */
-
- FUNCTION DictNew()
-
- LOCAL i
- LOCAL dict
-
- dict := Array(DEFAULT_HASH_SIZE)
-
- FOR i := 1 to DEFAULT_HASH_SIZE
- dict[i] := {}
- NEXT
-
- RETURN ( dict )
-
-
-
- /***
- * DictAt()
- * Return the value for a particular key.
- */
-
- FUNCTION DictAt( dict, key )
-
- LOCAL bucket
- LOCAL i
-
- bucket := dict[ HASH_VAL(key, Len(dict)) ]
- i := AScan( bucket, { |assoc| assoc[ DI_KEY ] == key } )
-
- if ( i == 0 )
- RETURN (NIL)
- end
-
- RETURN ( bucket[i][DI_VAL] )
-
-
-
- /***
- * DictPut()
- * Add or replace the value for a particular key.
- * Returns the value being added.
- */
-
- FUNCTION DictPut( dict, key, val )
-
- DictPutPair( dict, {key, val} )
-
- RETURN (val)
-
-
-
- /***
- * DictPutPair()
- * Add or replace key/value pair for a particular key.
- * Returns the pair being added.
- */
-
- FUNCTION DictPutPair( dict, pair )
-
- LOCAL bucket
- LOCAL key
- LOCAL i
-
- key := pair[ DI_KEY ]
-
- bucket := dict[ HASH_VAL(key, Len(dict)) ]
- i := AScan( bucket, { |assoc| assoc[ DI_KEY ] == key } )
-
- if ( i == 0 )
- AAdd( bucket, pair )
- i := Len( bucket )
- else
- bucket[i] := pair
- end
-
- if ( i > 3 .and. Len(dict) < MAX_ARRAY_LEN )
- // this bucket is big, grow dict
- DictResize(dict)
- end
-
- RETURN ( pair )
-
-
-
- /***
- * DictRemove()
- * Remove the key/value pair for a particular key.
- * Returns a reference to the dictionary.
- */
-
- FUNCTION DictRemove( dict, key )
-
- LOCAL bucket
- LOCAL i
-
- bucket := dict[ HASH_VAL(key, Len(dict)) ]
- i := AScan( bucket, { |assoc| assoc[ DI_KEY ] == key } )
-
- if ( i <> 0 )
- ADel( bucket, i )
- ASize( bucket, Len(bucket) - 1 )
- end
-
- RETURN ( dict )
-
-
-
- /***
- * DictEval()
- * Evaluate block against each pair in dictionary. Pair is passed to
- * block.
- * Returns reference to dict.
- */
-
- FUNCTION DictEval( dict, block )
-
- AEval( dict, ;
- { |bucket| AEval( bucket, { |assoc| Eval(block, assoc) } ) } )
-
- RETURN ( dict )
-
-
-
- /***
- * DictResize()
- *
- * Service. Grows dict hash table.
- *
- * NOTE: rehashes, invalidating any direct indexes into dict held
- * by caller across this call.
- */
-
- STATIC FUNCTION DictResize( dict )
-
- LOCAL old
- LOCAL size
- LOCAL i
-
- // make copy of old dict
- old := Array( Len(dict) )
- ACopy( dict, old )
-
- // resize and clear dict
- size := Min( Len(dict) * 4 - 1, MAX_ARRAY_LEN )
- ASize( dict, size )
-
- FOR i := 1 to size
- dict[i] := {}
- NEXT
-
- // rehash pairs into dict
- AEval( old, ;
- { |bucket| AEval( bucket, ;
- { |assoc| DictPutPair( dict, assoc ) } ) } )
-
- RETURN ( dict )
-