1 cananian 1.1 // GenericContextFactory.java, created Tue Feb 26 03:57:04 2002 by cananian
 2 cananian 1.1 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu>
 3 cananian 1.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
 4 cananian 1.1 package harpoon.Analysis;
 5 cananian 1.1 
 6 cananian 1.1 import java.util.Arrays;
 7 cananian 1.1 import java.util.Collections;
 8 cananian 1.1 import java.util.HashMap;
 9 cananian 1.1 import java.util.List;
10 cananian 1.1 import java.util.Map;
11 cananian 1.1 /**
12 cananian 1.1  * A <code>GenericContextFactory</code> can create <code>Context</code>
13 cananian 1.1  * objects for any desired level of context-sensitivity.
14 cananian 1.1  * The context-sensitivity and caching behavior is specified in the
15 cananian 1.1  * <code>GenericContextFactory</code>'s constructor.
16 cananian 1.1  * 
17 cananian 1.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
18 cananian 1.4  * @version $Id: GenericContextFactory.java,v 1.4 2004/02/08 01:49:03 cananian Exp $
19 cananian 1.1  * @see Context
20 cananian 1.1  */
21 cananian 1.3 public class GenericContextFactory<E> {
22 cananian 1.1     private final int CONTEXT_SENSITIVITY;
23 cananian 1.3     private final Map<Context<E>,Context<E>> cache;
24 cananian 1.3     private final Context<E> root;
25 cananian 1.1     
26 cananian 1.1     /** Creates a <code>GenericContextFactory</code>. */
27 cananian 1.1     public GenericContextFactory(int context_sensitivity, boolean use_cache) {
28 cananian 1.1         this.CONTEXT_SENSITIVITY = context_sensitivity;
29 cananian 1.3         this.cache = use_cache ? new HashMap<Context<E>,Context<E>>() : null;
30 cananian 1.1         this.root = new ContextImpl();
31 cananian 1.1         if (this.cache!=null)
32 cananian 1.1             cache.put(this.root, this.root);
33 cananian 1.1     }
34 cananian 1.3     // XXX should return a bivariant context; adding something to it
35 cananian 1.3     // will make the context invariant.
36 cananian 1.3     public Context<E> makeEmptyContext() { return root; }
37 cananian 1.1     
38 cananian 1.3     private class ContextImpl extends Context<E> {
39 cananian 1.3         final E[] items;
40 cananian 1.3         List<E> cached_list = null;
41 cananian 1.4         ContextImpl() { this((E[])new Object[0]); }
42 cananian 1.3         ContextImpl(E[] items) { this.items = items; }
43 cananian 1.3         public Context<E> addElement(E o) {
44 cananian 1.1             // truncate context at CONTEXT_SENSITIVITY items.
45 cananian 1.4             E[] nitems = (E[])
46 cananian 1.4                 new Object[Math.min(CONTEXT_SENSITIVITY, items.length+1)];
47 cananian 1.1             if (nitems.length>0)
48 cananian 1.1                 nitems[nitems.length-1] = o;
49 cananian 1.1             if (nitems.length>1)
50 cananian 1.2                 System.arraycopy(items, items.length-(nitems.length-1),
51 cananian 1.2                                  nitems, 0, nitems.length-1);
52 cananian 1.3             Context<E> nc = new ContextImpl(nitems);
53 cananian 1.1             // maybe cache.
54 cananian 1.1             if (cache!=null)
55 cananian 1.1                 if (!cache.containsKey(nc))
56 cananian 1.1                     cache.put(nc, nc);
57 cananian 1.1                 else
58 cananian 1.3                     nc = cache.get(nc);
59 cananian 1.1             // ta-da!
60 cananian 1.1             return nc;
61 cananian 1.1         }
62 cananian 1.3         public List<E> asList() {
63 cananian 1.3             List<E> l = cached_list;
64 cananian 1.1             if (l==null) {
65 cananian 1.1                 l = Collections.unmodifiableList(Arrays.asList(items));
66 cananian 1.1                 if (cache!=null)
67 cananian 1.1                     cached_list = l;
68 cananian 1.1             }
69 cananian 1.1             return l;
70 cananian 1.1         }
71 cananian 1.1     }
72 cananian 1.1 }