a bug fix...
[IRC.git] / Robust / src / Util / MultiViewMapBuilder.java
1 // This builder does several things:
2 //
3 //   1) The MultiViewMap constructor is private because
4 //      there is a lot of consistency checking to do in
5 //      the inputs (like whether a view is specified 
6 //      twice) so do all that in a builder and the map
7 //      itself can assume valid inputs at the constructor.
8 //
9 //   2) The inputs to construct a MultiViewMap are tedious
10 //      to code, so this builder lets you write the 
11 //      specifications succinctly.
12 //
13 //   3) If you are creating many MultiViewMap's of the same
14 //      type and views, it is best to have one builder that
15 //      generates each fresh map rather than build up all
16 //      the small specification objects again.
17 //
18 package Util;
19
20 import java.util.BitSet;
21 import java.util.Vector;
22
23
24 public class MultiViewMapBuilder<T> {
25
26   private Class[]        keyTypes;
27   private Vector<BitSet> partialViews;
28   private BitSet         fullView;
29
30   private JoinOp<T> joinOp;
31   
32   private boolean checkTypes;
33   private boolean checkConsistency;
34   
35
36   // define the types and ordering of the multikey
37   public MultiViewMapBuilder( Class[] keyTypes, JoinOp<T> joinOp ) {
38     assert( keyTypes != null );
39     assert( joinOp != null );
40
41     if( keyTypes.length == 0 ) {
42       throw new IllegalArgumentException( "The multikey must have at least one key type." );
43     }
44
45     this.keyTypes         = keyTypes;
46     this.partialViews     = new Vector<BitSet>();
47     this.joinOp           = joinOp;
48     this.checkTypes       = false;
49     this.checkConsistency = false;
50
51     fullView = new BitSet( keyTypes.length );
52     for( int i = 0; i < keyTypes.length; ++i ) {
53       fullView.set( i );
54     }
55   }
56
57
58   public final BitSet addPartialView( Integer... keyIndices ) { 
59     if( keyIndices.length == 0 ) {
60       throw new IllegalArgumentException( "A view must have at least one key index." );
61     }
62
63     // build a view from the arg list
64     BitSet view = new BitSet( keyTypes.length );
65     for( Integer i : keyIndices ) {
66       if( i < 0 || i >= keyTypes.length ) {
67         throw new IllegalArgumentException( "Key index in view is out of bounds." );
68       }
69       if( view.get( i ) ) {
70         throw new IllegalArgumentException( "Key index in view is specified more than once." );
71       }
72       view.set( i );
73     }
74
75     if( keyIndices.length  == keyTypes.length &&
76         view.cardinality() == keyTypes.length ) {
77       throw new IllegalArgumentException( "The full view is always included implicitly." );
78     }
79
80     for( BitSet existingView : partialViews ) {
81       if( view.equals( existingView ) ) {
82         throw new IllegalArgumentException( "View matches an existing view." );
83       }
84     }
85
86     return addPartialView( view );
87   }
88
89
90   public final BitSet addPartialView( BitSet view ) {
91     partialViews.add( view );
92     return (BitSet) view.clone();
93   }
94
95
96   public final BitSet getFullView() {
97     return fullView;
98   }
99
100
101   public void setCheckTypes( boolean checkTypes ) {
102     this.checkTypes = checkTypes;
103   }
104
105
106   public void setCheckConsistency( boolean checkConsistency ) {
107     this.checkConsistency = checkConsistency;
108   }
109
110
111   public MultiViewMap<T> build() {
112     if( partialViews.isEmpty() ) {
113       throw new IllegalArgumentException( "No partial views specified for this builder." );
114     }
115     return new MultiViewMap<T>( keyTypes,
116                                 joinOp,
117                                 fullView,
118                                 partialViews, 
119                                 checkTypes, 
120                                 checkConsistency );
121   }
122 }