Dictionary implementation in HOC

Particularly useful chunks of hoc and/or NMODL code. May be pedestrian or stunningly brilliant, may make you gasp or bring tears to your eyes, but always makes you think "I wish I had written that; I'm sure going to steal it."
Post Reply
Eelke Spaak
Posts: 10
Joined: Tue Oct 21, 2008 4:43 am

Dictionary implementation in HOC

Post by Eelke Spaak »

Since I could not find an implementation of a dictionary (or map, or ...) in HOC, I decided to write my own. I thought it would be nice to share it, so here it is. It supports both object references and strings as keys; a feature I myself find very useful. By the way, if anyone already knows of a built-in Dictionary class or something like that that I have missed completely, don't hesitate to let me know... :)

Usage example:

Code: Select all

objref dic
dic = new Dictionary()
dic.put("aKey", new String("theValue"))
dic.put("anotherOne", new Vector())
print dic.get("aKey").s
// etc., pretty straight-forward
And the class:

Code: Select all

// this ensures the String class is available
load_file("stdlib.hoc")

/**
 * An implementation of a dictionary. Only object references can be used as
 * values, but both object references and strings can be used as keys. Note that
 * the implementation might not be super-fast, but it works :) .
 *
 * Author: Eelke Spaak, Nijmegen, NL
 * Date: 12 nov 2008
 */
begintemplate Dictionary

    objref null // null reference
    objref keys, values, stringTable
    
    public put, get, remove, containsKey, size, keyList
    
    proc init() {
        keys = new List()
        values = new List()
        stringTable = new List()
    }
    
    /**
     * Stores the given key/value pair in the dictionary. If key is already
     * present, changes the stored value to the specified one.
     *
     * $o1 or $s1 = the key
     * $o2 = the value
     */
    proc put() { \
        localobj key, value
        
        if (argtype(1) == 2) {
            key = getString($s1)
        } else {
            key = $o1
        }
        
        putImpl(key, $o2)
    }
    
    /**
     * Returns the value for the given key, or a reference to NULLObject if the
     * key does not occur in the dictionary.
     *
     * $s1 or $o1 = the key
     */
    obfunc get() { \
        localobj key
        
        if (argtype(1) == 2) {
            key = getString($s1)
        } else {
            key = $o1
        }
        
        return getImpl(key)
    }
    
    /**
     * Removes the key/value pair associated with the given key from the
     * dictionary.
     *
     * $s1 or $o1 = the key
     */
    proc remove() { \
        localobj key
        
        if (argtype(1) == 2) {
            key = getString($s1)
        } else {
            key = $o1
        }
        
        removeImpl(key)
    }
    
    /**
     * Returns 1 if the specified key is present in the dictionary, 0 otherwise.
     *
     * $s1 or $o1 = the key
     */
    func containsKey() { \
        localobj key
        
        if (argtype(1) == 2) {
            key = getString($s1)
        } else {
            key = $o1
        }
        
        return (getImpl(key) != null)
    }
    
    /**
     * Returns the number of key/value pairs in the dictionary.
     */
    func size() {
        return keys.count()
    }
    
    /**
     * Returns a List of all the keys stored in the dictionary.
     */
    obfunc keyList() {
        return keys
    }
    
    // private: returns the appropriate String instance from stringTable
    obfunc getString() { \
        local i \
        localobj s
        
        for i = 0, stringTable.count() - 1 {
            s = stringTable.object(i)
            if (strcmp(s.s, $s1) == 0) {
                return s
            }
        }
        
        s = new String($s1)
        stringTable.append(s)
        return s
    }
    
    proc putImpl() { \
        local ind
       
        ind = keys.index($o1)
        
        if (ind > -1) {
            values.remove(ind)
            values.insrt(ind, $o2)
        } else {
            keys.append($o1)
            values.append($o2)
        }
    }
    
    obfunc getImpl() { \
        local ind \
       
        ind = keys.index($o1)
        
        if (ind < 0) {
            return null
        } else {
            return values.object(ind)
        }
    }
    
    proc removeImpl() { \
        local ind
        
        ind = keys.index($o1)
        
        if (ind > -1) {
            keys.remove(ind)
            values.remove(ind)
        }
        
        // clean up stringTable, not necessary but good for tidiness
        ind = stringTable.index($o1)
        if (ind > -1) {
            stringTable.remove(ind)
        }
    }

endtemplate Dictionary
Post Reply