A MultiViewMap is a generalization of the VarSrcTokTable in OoOJava. It is cumbersom...
[IRC.git] / Robust / src / Util / MultiViewMapBuilder.java
diff --git a/Robust/src/Util/MultiViewMapBuilder.java b/Robust/src/Util/MultiViewMapBuilder.java
new file mode 100644 (file)
index 0000000..8cc74c8
--- /dev/null
@@ -0,0 +1,122 @@
+// This builder does several things:
+//
+//   1) The MultiViewMap constructor is private because
+//      there is a lot of consistency checking to do in
+//      the inputs (like whether a view is specified 
+//      twice) so do all that in a builder and the map
+//      itself can assume valid inputs at the constructor.
+//
+//   2) The inputs to construct a MultiViewMap are tedious
+//      to code, so this builder lets you write the 
+//      specifications succinctly.
+//
+//   3) If you are creating many MultiViewMap's of the same
+//      type and views, it is best to have one builder that
+//      generates each fresh map rather than build up all
+//      the small specification objects again.
+//
+package Util;
+
+import java.util.BitSet;
+import java.util.Vector;
+
+
+public class MultiViewMapBuilder<T> {
+
+  private Class[]        keyTypes;
+  private Vector<BitSet> partialViews;
+  private BitSet         fullView;
+
+  private JoinOp<T> joinOp;
+  
+  private boolean checkTypes;
+  private boolean checkConsistency;
+  
+
+  // define the types and ordering of the multikey
+  public MultiViewMapBuilder( Class[] keyTypes, JoinOp<T> joinOp ) {
+    assert( keyTypes != null );
+    assert( joinOp != null );
+
+    if( keyTypes.length == 0 ) {
+      throw new IllegalArgumentException( "The multikey must have at least one key type." );
+    }
+
+    this.keyTypes         = keyTypes;
+    this.partialViews     = new Vector<BitSet>();
+    this.joinOp           = joinOp;
+    this.checkTypes       = false;
+    this.checkConsistency = false;
+
+    fullView = new BitSet( keyTypes.length );
+    for( int i = 0; i < keyTypes.length; ++i ) {
+      fullView.set( i );
+    }
+  }
+
+
+  public final BitSet addPartialView( Integer... keyIndices ) { 
+    if( keyIndices.length == 0 ) {
+      throw new IllegalArgumentException( "A view must have at least one key index." );
+    }
+
+    // build a view from the arg list
+    BitSet view = new BitSet( keyTypes.length );
+    for( Integer i : keyIndices ) {
+      if( i < 0 || i >= keyTypes.length ) {
+        throw new IllegalArgumentException( "Key index in view is out of bounds." );
+      }
+      if( view.get( i ) ) {
+        throw new IllegalArgumentException( "Key index in view is specified more than once." );
+      }
+      view.set( i );
+    }
+
+    if( keyIndices.length  == keyTypes.length &&
+        view.cardinality() == keyTypes.length ) {
+      throw new IllegalArgumentException( "The full view is always included implicitly." );
+    }
+
+    for( BitSet existingView : partialViews ) {
+      if( view.equals( existingView ) ) {
+        throw new IllegalArgumentException( "View matches an existing view." );
+      }
+    }
+
+    return addPartialView( view );
+  }
+
+
+  public final BitSet addPartialView( BitSet view ) {
+    partialViews.add( view );
+    return (BitSet) view.clone();
+  }
+
+
+  public final BitSet getFullView() {
+    return fullView;
+  }
+
+
+  public void setCheckTypes( boolean checkTypes ) {
+    this.checkTypes = checkTypes;
+  }
+
+
+  public void setCheckConsistency( boolean checkConsistency ) {
+    this.checkConsistency = checkConsistency;
+  }
+
+
+  public MultiViewMap<T> build() {
+    if( partialViews.isEmpty() ) {
+      throw new IllegalArgumentException( "No partial views specified for this builder." );
+    }
+    return new MultiViewMap<T>( keyTypes,
+                                joinOp,
+                                fullView,
+                                partialViews, 
+                                checkTypes, 
+                                checkConsistency );
+  }
+}