KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > mapping > Namespace


1 // Copyright (c) 1996-2000, 2001, 2002, 2004 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.mapping;
5 import java.util.Hashtable JavaDoc;
6 import java.io.*;
7
8 /** A mapping from strings ("print names") to <code>Symbol</code>s.
9  * Namespaces are normally named and can be accessed from a global table.
10  * They correspond to Common Lisp "packages" (which are implemented
11  * using <code>gnu.kawa.lispexpr.LispPackage</code>,
12  * which extends <code>Namespace</code>).
13  * A <code>Namespace</code> is a "weak" mapping in the sense that a
14  * <code>Symbol</code> can be garbage collected even though it is
15  * referenced from a <code>Namespace</code>.
16  * @author Per Bothner
17  */

18
19 public class Namespace
20   implements Externalizable, HasNamedParts
21 {
22   /** Map namepsace names (and nick-names) to Namespaces. */
23   protected static final Hashtable JavaDoc nsTable = new Hashtable JavaDoc(50);
24
25   /** The Namespace with the empty name. */
26   public static final Namespace EmptyNamespace = getInstance("");
27
28   /** Should be interned. */
29   String JavaDoc name;
30
31   protected String JavaDoc prefix = "";
32
33   /** Get the name of this Namespace. */
34   public final String JavaDoc getName () { return name; }
35   /** Set the name of this Namespace. */
36   public final void setName (String JavaDoc name) { this.name = name; }
37
38   public Namespace ()
39   {
40     this(64);
41   }
42
43   public Namespace (int capacity)
44   {
45     log2Size = 4;
46     while (capacity > (1 << log2Size))
47       log2Size++;
48     capacity = 1 << log2Size;
49     table = new SymbolRef[capacity];
50     mask = capacity - 1;
51   }
52
53   public static Namespace getDefault ()
54   {
55     return EmptyNamespace;
56   }
57
58   public static Symbol getDefaultSymbol (String JavaDoc name)
59   {
60     return EmptyNamespace.getSymbol(name);
61   }
62
63   public static Namespace make(String JavaDoc name) // Needed for Literals.
64
{
65     return getInstance(name);
66   }
67
68   public static Namespace getInstance(String JavaDoc name)
69   {
70     if (name == null)
71       name = "";
72     synchronized (nsTable)
73       {
74     Namespace ns = (Namespace) nsTable.get(name);
75     if (ns != null)
76       return ns;
77     ns = new Namespace ();
78     ns.setName(name.intern());
79     nsTable.put(name, ns);
80     return ns;
81       }
82   }
83
84   public static Namespace make (String JavaDoc uri, String JavaDoc prefix)
85   {
86     if (prefix == null || prefix.length() == 0)
87       return getInstance(uri);
88     String JavaDoc xname = prefix + " -> "+ uri;
89     synchronized (nsTable)
90       {
91     Object JavaDoc old = nsTable.get(xname);
92     if (old instanceof Namespace)
93       return (Namespace) old;
94     Namespace ns = new Namespace();
95         ns.setName(uri);
96         ns.prefix = prefix;
97     nsTable.put(xname, ns);
98     return ns;
99       }
100   }
101
102   /** Create a "placeholder" for a namespace with a known prefix
103    * but unknown uri.
104    * @see Symbol#makeWithUnknownNamespace
105    */

106   public static Namespace makeUnknownNamespace (String JavaDoc prefix)
107   {
108     String JavaDoc uri;
109     if (prefix == null || prefix == "")
110       uri = "";
111     else
112       uri = "http://kawa.gnu.org/unknown-namespace/"+prefix;
113     return Namespace.make(uri, prefix);
114   }
115
116   public Object JavaDoc get (String JavaDoc name)
117   {
118     return Environment.getCurrent().get(getSymbol(getName()));
119   }
120
121   public boolean isConstant (String JavaDoc key)
122   {
123     return false;
124   }
125
126   /** Get a Symbol matching the given name.
127    * Creates a new Symbol if one is not found.
128    * Equivalent to Common Lisp's "intern" function.
129    */

130   public Symbol getSymbol (String JavaDoc key)
131   {
132     return lookup(key, key.hashCode(), true);
133   }
134
135   /** Get a Symbol matching the given name.
136    * Returns null if one is not found.
137    */

138   public Symbol lookup(String JavaDoc key)
139   {
140     return lookup(key, key.hashCode(), false);
141   }
142
143   protected final Symbol lookupInternal(String JavaDoc key, int hash)
144   {
145     int index = hash & mask;
146     SymbolRef prev = null;
147     for (SymbolRef ref = table[index]; ref != null; )
148       {
149     SymbolRef next = ref.next;
150     Symbol sym = ref.getSymbol();
151     if (sym == null)
152       {
153         // Weakly referenced object has been collected.
154
if (prev == null)
155           table[index] = next;
156         else
157           prev.next = next;
158         num_bindings--;
159       }
160     else
161       {
162         if (sym.getLocalPart().equals(key))
163           return sym;
164         prev = ref;
165       }
166     ref = next;
167       }
168     return null;
169   }
170
171   public Symbol add(Symbol sym, int hash)
172   {
173     int index = hash & mask;
174     SymbolRef ref = new SymbolRef(sym, this);
175     sym.namespace = this;
176     ref.next = table[index];
177     table[index] = ref;
178     num_bindings++;
179     if (num_bindings >= table.length)
180       rehash();
181     return sym;
182   }
183
184   public Symbol lookup(String JavaDoc key, int hash, boolean create)
185   {
186     synchronized (this)
187       {
188     Symbol sym = lookupInternal(key, hash);
189     if (sym != null)
190       return sym;
191
192     /*
193     // Do we need to synchronize on nsTable as well? FIXME
194     for (NamespaceUse used = imported; used != null;
195          used = used.nextImported)
196       {
197         el = lookup(key, hash, false);
198         if (el != null)
199           return el;
200       }
201     */

202     if (create)
203       return add(new Symbol(this, key), hash);
204     else
205       return null;
206       }
207   }
208
209   public boolean remove (Symbol symbol)
210   {
211     synchronized (this)
212       {
213     String JavaDoc name = symbol.getLocalPart();
214     int hash = name.hashCode();
215     int index = hash & mask;
216     SymbolRef prev = null;
217     SymbolRef ref = table[index];
218     while (ref != null)
219       {
220         SymbolRef next = ref.next;
221         Symbol refsym = ref.getSymbol();
222         if (refsym == null || refsym == symbol)
223           {
224         if (prev == null)
225           table[index] = next;
226         else
227           prev.next = next;
228         num_bindings--;
229         if (refsym != null)
230           return true;
231           }
232         else
233           prev = ref;
234         ref = next;
235       }
236     return false;
237       }
238   }
239
240   protected SymbolRef[] table;
241   int log2Size;
242   private int mask;
243   int num_bindings;
244
245   protected void rehash ()
246   {
247     int oldCapacity = table.length;
248     int newCapacity = 2 * oldCapacity;
249     int newMask = newCapacity - 1;
250     int countInserted = 0;
251     SymbolRef[] oldTable = table;
252     SymbolRef[] newTable = new SymbolRef[newCapacity];
253
254     for (int i = oldCapacity; --i >= 0;)
255       {
256     for (SymbolRef ref = oldTable[i]; ref != null; )
257       {
258         SymbolRef next = ref.next;
259         Symbol sym = ref.getSymbol();
260         if (sym != null)
261           {
262         String JavaDoc key = sym.getName();
263         int hash = key.hashCode();
264         int index = hash & newMask;
265         countInserted++;
266         ref.next = newTable[index];
267         newTable[index] = ref;
268           }
269         ref = next;
270       }
271       }
272
273     table = newTable;
274     log2Size++;
275     mask = newMask;
276     num_bindings = countInserted;
277   }
278
279   public void writeExternal(ObjectOutput out) throws IOException
280   {
281     out.writeObject(getName());
282     out.writeObject(prefix);
283   }
284
285   public void readExternal(ObjectInput in)
286     throws IOException, ClassNotFoundException JavaDoc
287   {
288     name = ((String JavaDoc) in.readObject()).intern();
289     prefix = (String JavaDoc) in.readObject();
290   }
291
292   public Object JavaDoc readResolve() throws ObjectStreamException
293   {
294     String JavaDoc name = getName();
295     if (name != null)
296       {
297         String JavaDoc xname = (prefix == null || prefix.length() == 0 ? name
298                         : (prefix + " -> "+ name));
299     Namespace ns = (Namespace) nsTable.get(xname);
300     if (ns != null)
301       return ns;
302     nsTable.put(xname, this);
303       }
304     return this;
305    
306   }
307
308   public String JavaDoc toString()
309   { return "#,(namespace \""+name+"\")"; }
310 }
311
312 /** A week reference to a <code>Symbol</code>.
313  * This is to allow <code>Symbol</code>s to be garbage collected,
314  * even though they're referenced from a <code>Namespace</code>. */

315
316 class SymbolRef
317   /* #ifdef JAVA2 */
318   extends java.lang.ref.WeakReference JavaDoc
319   /* #endif */
320 {
321   SymbolRef next;
322
323   /* #ifndef JAVA2 */
324   // Symbol sym;
325
/* #endif */
326
327   /*
328   String getName ()
329   {
330     Symbol sym = getSymbol();
331     return sym == null ? null : sym.getName();
332   }
333   */

334
335   SymbolRef (Symbol sym, Namespace ns)
336   {
337     /* #ifdef JAVA2 */
338     super(sym);
339     /* #else */
340     // this.sym = sym;
341
/* #endif */
342   }
343
344   Symbol getSymbol()
345   {
346     /* #ifdef JAVA2 */
347     return (Symbol) get();
348     /* #endif */
349     /* #ifndef JAVA2 */
350     // return sym;
351
/* #endif */
352   }
353
354   public String JavaDoc toString()
355   {
356     return "SymbolRef["+getSymbol()+"]";
357   }
358 }
359
Popular Tags