001    // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 
002    // The Molly framework is freely distributable under the terms of an
003    // MIT-style license. For details, see the molly pages web site at:
004    // http://www.mollypages.org/. Use, modify, have fun !
005    
006    package fc.util;
007    
008    import java.util.*;
009    
010    /** 
011    Implements a simple table data structure. Like a 2D array
012    but uses nested hash tables to get (row, col) based on a 
013    (name, name) pair. The table grows automatically as needed.
014    <p>
015    Differs from a 2D Object[][] in that names can be used 
016    instead of indices.
017    <p>
018    All indexes are internally strings. When adding or retrieving
019    values, either numerical and string indices can be specified
020    for either row or col when retrieving a (row,col) value. <i>A
021    numerical index is converted into a string value</i> so if one puts
022    a value at (3, 5), that can later be retrieved as ("3", "5")
023    if desired.
024    <p>
025    Thread safety: This data structure is fully thread safe.
026    
027    @author hursh jain
028    **/
029    public final class Table
030    {
031    private static final boolean dbg = false;
032    
033    int row_default_size;
034    int col_default_size;
035    
036    /*    
037             A     B    C
038    rows  1:   x     y    z
039          2:   a     e    n
040          3:   c     d    m
041    
042    rows(1) => hashtable (A->x, B->y, C->z)
043    rows(2) => hashtable (A->a, B->e, C->n)
044    ..
045    */
046    Map table;
047    
048    /** 
049    Constructs a new table.
050    **/
051    public Table() {
052      this(32, 32);
053      }
054    
055    /** 
056    Constructs a new table of the specified initial size.
057    **/
058    public Table(int rows, int cols) {
059      this.row_default_size = rows;
060      this.col_default_size = cols;
061      this.table = new Hashtable(rows);
062      }
063    
064    /** 
065    Returns the object at row, col or <tt>null</tt> if the
066    specified row or col do not exist.
067    */
068    public Object get(String row, String col) 
069      {
070      Object val = null;
071      
072      Map cols = (Map) table.get(row);
073      
074      if (cols != null) 
075        val = cols.get(col);
076        
077      return val;
078      }
079    
080    
081    /**
082    Returns the object at row, col or <tt>null</tt> if the
083    specified row or col do not exist.
084    */
085    public Object get(int row, String col) 
086      {
087      return get(String.valueOf(row), col);
088      }
089    
090    /**
091    Returns the object at row, col or <tt>null</tt> if the
092    specified row or col do not exist.
093    */
094    public Object get(String row, int col) 
095      {
096      return get(row, String.valueOf(col));
097      }
098    
099    /**
100    Returns the object at row, col or <tt>null</tt> if the
101    specified row or col do not exist.
102    */
103    public Object get(int row, int col) 
104      {
105      return get(String.valueOf(row), String.valueOf(col));
106      }
107    
108    /**
109    Returns the object at row, col or <tt>null</tt> if the
110    specified row or col do not exist.
111    
112    @return the old object at that (row, col) if it exists
113    */
114    public Object put(String row, String col, Object obj) 
115      {
116      Object val = null;
117      
118      Map c = (Map) table.get(row);
119      if (c == null) {
120        c = new Hashtable(col_default_size);
121        table.put(row, c);
122        }
123      
124      val = c.put(col, obj);  
125      return val;
126      }
127    
128    
129    public Object put(int row, String col, Object obj) 
130      {
131      return put(String.valueOf(row), col, obj);
132      }
133    
134    public Object put(String row, int col, Object obj) 
135      {
136      return put(row, String.valueOf(col), obj);
137      }
138    
139    public Object put(int row, int col, Object obj) 
140      {
141      return put(String.valueOf(row), String.valueOf(col), obj);
142      }
143    
144    
145    public String toString() {
146      return "Table: [" + table.size() + " rows]";
147      }
148      
149    public static void main (String args[])
150      {
151      Table t = new Table();
152      System.out.println("t.get(1,1)="+t.get(1,1));
153      System.out.println("t.put(1,1,\"hello\")="+t.put(1,1, "hello"));
154      System.out.println("t.get(\"1\",\"1\")="+t.get("1","1"));
155      System.out.println("t.get(1,\"1\")="+t.get(1,"1"));
156      System.out.println("t.get(1,0)="+t.get(1,0));
157      System.out.println("t.put(1,1,\"hello\")="+t.put(1,1, "world"));
158      System.out.println("t.get(\"1\",1)="+t.get("1",1));
159    
160      for (int n = 0; n < 10; n++) {
161        t.put(n, n, n);
162        }
163    
164      for (int n = 0; n < 10; n++) {
165        System.out.println("table["+n+","+n+"]:"+t.get(n, n));
166        }
167      
168      Watch w = new Watch().start();
169      t.get(5,5);
170      w.stop();
171      System.out.println("time for one t.get() op: " + w.time() + " ms");
172      }
173    }   //~class Table