Last active
December 31, 2015 16:04
-
-
Save edefazio/bf6047cdcb706d7cf545 to your computer and use it in GitHub Desktop.
Template for a 32-bit Type that encompasses (2) associated Types (row and column)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.semiotics.type.grid; | |
import java.io.Serializable; | |
import java.util.HashSet; | |
import java.util.Set; | |
import io.semiotics.data.Word; | |
import io.semiotics.type.InvalidBin; | |
import io.semiotics.type.InvalidForm; | |
import io.semiotics.type.MultiPartForm.ObjectArrayDomain; | |
import io.semiotics.type.MultiPartForm.TwoPartDomain; | |
import io.semiotics.type.Type.Type32; | |
import io.semiotics.type.primitive.BoolType; | |
import io.semiotics.type.primitive.BoolType.BoolForm; | |
/** | |
* A multivariate {@code Type} with (2) dimensions for modeling | |
* a dimensional "relationship" between two data elements. | |
* (we use the terms "row" and "column" for the dimensions) | |
* | |
* A good example of this is a "weekly work calendar" where | |
* <UL> | |
* <LI>the COLUMNS are the Days of the Week {Sun, Mon, Tue, Wed, Thu, Fri, Sat} | |
* <LI>the ROWS are hours of the day {8:00am, 9:00am, 10:00am... 5:00pm} | |
* </UL> | |
* | |
* Each "form" of the {@code Type} contains two pieces of information | |
* (the Day and the hour) i.e. { Fr, 9:00am }, { Tu, 5:00pm} | |
* | |
* Also useful for: | |
* <UL> | |
* <LI> Modeling a <A HREF="https://en.wikipedia.org/wiki/Bitboard">BitBoard</A>-like data structure | |
* <LI> Addressing 2D "Coordinate" Systems ( pixels on a 1920x1080 display ) | |
* <LI> Associative Tables of Data (i.e. the BMI Body Mass Index) taking into account the height and weight) | |
* <LI> The game <A HREF="https://en.wikipedia.org/wiki/Battleship_(game)">"Battleship"</A> | |
* </UL> | |
* | |
* @author M. Eric DeFazio eric@typefra.me | |
*/ | |
public class /*{typeClass*/__GridOfType/*}*/ | |
implements Type32, Serializable | |
{ | |
/** The form of each GridOfType has (2) components (the row and column) */ | |
public final TwoPartForm TwoPartForm; | |
public static final String ROW_NAME = "/*{rowName*/ROW/*}*/"; | |
public static final String COLUMN_NAME = "/*{columnName*/COLUMN/*}*/"; | |
public static final String NAME = | |
"Grid("+ROW_NAME+" x "+COLUMN_NAME+")"; | |
public static final /*{rowType*/BoolType/*}*/ ROW_TYPE = | |
/*{rowTypeDeclare*/BoolType.INSTANCE/*}*/; | |
public static final /*{columnType*/BoolType/*}*/ COLUMN_TYPE = | |
/*{columnTypeDeclare*/BoolType.INSTANCE/*}*/; | |
public static final /*{rowFormBinding*/BoolForm/*}*/ ROW_FORM = | |
ROW_TYPE./*{rowFormField*/BoolForm/*}*/; | |
public static final /*{columnFormBinding*/BoolForm/*}*/ COLUMN_FORM = | |
COLUMN_TYPE./*{columnFormField*/BoolForm/*}*/; | |
public static final int MIN_BIN = ( ROW_TYPE.getFirstBin() * ( COLUMN_TYPE.getFirstBin() + 1 ) ); | |
public static final int MAX_BIN = ( ROW_TYPE.getLastBin() * ( COLUMN_TYPE.getLastBin() + 1 ) ); | |
public static final /*{typeClass*/__GridOfType/*}*/ INSTANCE = | |
new /*{typeClass*/__GridOfType/*}*/(); | |
public /*{typeClass*/__GridOfType/*}*/ ( ) | |
{ | |
this.TwoPartForm = new TwoPartForm ( ); | |
} | |
public static class TwoPartForm | |
implements ObjectArrayDomain, TwoPartDomain, Serializable | |
{ | |
private static final long serialVersionUID = 4639913330030094725L; | |
public final TypeSpecification specification; | |
public TwoPartForm ( ) | |
{ | |
if ( MAX_BIN / ( COLUMN_TYPE.getLastBin() + 1 ) != ROW_TYPE.getLastBin() ) | |
{ | |
throw new InvalidType ("Grid Overflow, the product of rowType x columnType overflows 32 bits"); | |
} | |
Set<Class<?>>deps = new HashSet<Class<?>>(); | |
deps.addAll( ROW_TYPE.getSpecification().allDependenciesSet() ); | |
deps.addAll( COLUMN_TYPE.getSpecification().allDependenciesSet() ); | |
deps.add( /*{typeClass*/__GridOfType/*}*/.class ); | |
Class<?>[] allDeps = deps.toArray(new Class<?>[0]); | |
this.specification = | |
TypeSpecification.of( /*{typeClass*/__GridOfType/*}*/.class, | |
"/*{typeClass*/__GridOfType/*}*/.INSTANCE", | |
new TypeForm( "TwoPartForm", TwoPartForm.class ), | |
allDeps ); | |
} | |
public int toBin( Object[] form ) | |
{ | |
if ( form != null && form.length == 2 ) | |
{ | |
return toBin( form[ 0 ], form[ 1 ] ); | |
} | |
throw new InvalidForm ( "Expected form[ 2 ] for "+describe() ); | |
} | |
/** packs (without validating) the row and column [Bin]s into a single [Bin] */ | |
public int packBins( int rowBin, int columnBin ) | |
{ | |
return ( rowBin * ( COLUMN_TYPE.getLastBin() + 1 ) ) + columnBin; | |
} | |
public int toBin( Object rowForm, Object columnForm ) | |
{ | |
if (! ( rowForm instanceof /*{rowFormObjectType*/Boolean/*}*/ ) ) | |
{ | |
throw new InvalidForm ("Expected rowForm \""+rowForm+"\" to be instanceof /*{rowFormObjectType*/Boolean/*}*/"); | |
} | |
if (! ( columnForm instanceof /*{columnFormObjectType*/Boolean/*}*/ ) ) | |
{ | |
throw new InvalidForm ("Expected columnForm \""+columnForm+"\" to be instanceof /*{columnFormObjectType*/Boolean/*}*/"); | |
} | |
return of( (/*{rowFormObjectType*/Boolean/*}*/)rowForm , (/*{columnFormObjectType*/Boolean/*}*/)columnForm ); | |
} | |
public int of( /*{rowFormType*/boolean/*}*/ rowForm, /*{columnFormType*/boolean/*}*/ columnForm ) | |
{ | |
int rowBin = ROW_TYPE.BoolForm.toBin( rowForm ); | |
int columnBin = COLUMN_TYPE.toBin( columnForm ); | |
return packBins( rowBin, columnBin ); | |
} | |
public Object[] toForm ( int bin ) | |
throws InvalidForm | |
{ | |
int rowBin = bin / ( COLUMN_TYPE.getLastBin() + 1 ); | |
int columnBin = bin % ( COLUMN_TYPE.getLastBin() + 1 ); | |
return toForm ( rowBin, columnBin ); | |
} | |
public Object[] toForm ( int rowBin, int columnBin ) | |
{ | |
return new Object[] { ROW_TYPE.toForm( rowBin ), COLUMN_TYPE.toForm( columnBin ) }; | |
} | |
@Override | |
public Object[] toForm( long bin ) | |
throws InvalidBin | |
{ | |
return toForm ( Word.to32Bit( bin ) ); | |
} | |
public String getName() | |
{ | |
return NAME; | |
} | |
public int getLastBin() | |
{ | |
return MAX_BIN; | |
} | |
public String describe() | |
{ | |
return getName() + " [0.."+getLastBin()+"]<-->{" | |
+ format( ROW_TYPE.toForm( ROW_TYPE.getFirstBin() ), COLUMN_TYPE.toForm( COLUMN_TYPE.getFirstBin() ) ) | |
+ ".." | |
+ format( ROW_TYPE.toForm( ROW_TYPE.getLastBin() ), COLUMN_TYPE.toForm( COLUMN_TYPE.getLastBin() ) ) | |
+ "}"; | |
} | |
@Override | |
public String format( Object[] form ) | |
throws InvalidForm | |
{ | |
if ( form != null && form.length == 2 ) | |
{ | |
return format ( form[ 0 ], form[ 1 ] ); | |
} | |
throw new InvalidForm ("Expected Object[2] form for "+describe()); | |
} | |
public String format ( Object rowForm, Object columnForm ) | |
{ | |
return "("+ROW_TYPE.format( rowForm )+","+COLUMN_TYPE.format( columnForm )+")"; | |
} | |
public String format ( boolean rowForm, boolean columnForm ) | |
{ | |
return "("+ROW_FORM.format( rowForm )+","+COLUMN_FORM.format( columnForm )+")"; | |
} | |
public boolean isValidBin ( int bin ) | |
{ | |
if ( bin >= MIN_BIN && bin <= MAX_BIN ) | |
{ | |
int rowBin = bin / ( COLUMN_TYPE.getLastBin() + 1 ); | |
int columnBin = bin % ( COLUMN_TYPE.getLastBin() + 1 ); | |
return isValidBins( rowBin, columnBin ); | |
} | |
return false; | |
} | |
public boolean isValidBins(int rowBin, int columnBin) | |
{ | |
return ROW_TYPE.isValidBin( rowBin ) && COLUMN_TYPE.isValidBin( columnBin ); | |
} | |
@Override | |
public boolean isValidForm( Object[] form ) | |
{ | |
return ( form != null && form.length == 2 ) && | |
isValidForms (form[ 0 ], form[ 1 ] ); | |
} | |
/** Here lets create good (specific) error messages to why a [Bin] might be bad*/ | |
public void validateBin( int bin ) | |
throws InvalidBin | |
{ | |
if ( bin < MIN_BIN ) | |
{ | |
throw new InvalidBin ("[Bin] [" + bin + "] is < min [Bin] [" + MIN_BIN + "]" ); | |
} | |
if ( bin > MAX_BIN ) | |
{ | |
throw new InvalidBin ("[Bin] [" + bin + "] is > max [Bin] [" + MAX_BIN + "]" ); | |
} | |
int rowBin = bin / ( COLUMN_TYPE.getLastBin() + 1 ); | |
int columnBin = bin % ( COLUMN_TYPE.getLastBin() + 1 ); | |
if (! ROW_TYPE.isValidBin( rowBin ) ) | |
{ | |
throw new InvalidBin ("[Bin] [" + bin + "] with rowBin [" + rowBin + "] is invalid for row " + ROW_TYPE.describe() + " of " + describe() ); | |
} | |
if (! COLUMN_TYPE.isValidBin( columnBin ) ) | |
{ | |
throw new InvalidBin ("[Bin] [" + bin + "] with columnBin [" + columnBin + "] is invalid for row " + COLUMN_TYPE.describe() + " of " + describe() ); | |
} | |
} | |
@Override | |
public boolean isValidForms ( Object rowForm, Object columnForm ) | |
{ | |
return ROW_TYPE.isValidForm( rowForm ) && COLUMN_TYPE.isValidForm( columnForm ); | |
} | |
@Override | |
public void validateForm( Object[] form ) | |
throws InvalidForm | |
{ | |
if ( form == null || form.length != 2 ) | |
{ | |
throw new InvalidForm ( "Expected Object[2] for " + describe() ); | |
} | |
validateForms ( form[ 0 ], form[ 1 ] ); | |
} | |
@Override | |
public void validateForms ( Object rowForm, Object columnForm ) | |
{ | |
if (! ROW_TYPE.isValidForm ( rowForm ) ) | |
{ | |
throw new InvalidForm (" Row Form \"" + rowForm + "\" is not valid for row of " + ROW_TYPE.describe() + " of " + describe() ); | |
} | |
if (! COLUMN_TYPE.isValidForm ( columnForm ) ) | |
{ | |
throw new InvalidForm (" Column Form \"" + columnForm + "\" is not valid for column of " + COLUMN_TYPE.describe() + " of "+describe() ); | |
} | |
} | |
public int synthesize() | |
{ | |
return packBins( ROW_TYPE.synthesize(), COLUMN_TYPE.synthesize() ); | |
} | |
} | |
@Override | |
public String getName() | |
{ | |
return NAME; | |
} | |
public int of( /*{rowFormType*/boolean/*}*/ rowForm, /*{columnFormType*/boolean/*}*/ columnForm ) | |
{ | |
return TwoPartForm.of( rowForm, columnForm ); | |
} | |
@Override | |
public String describe() | |
{ | |
return TwoPartForm.describe(); | |
} | |
@Override | |
public TypeSpecification getSpecification() | |
{ | |
return TwoPartForm.specification; | |
} | |
@Override | |
public Object toForm( int bin ) | |
throws InvalidBin | |
{ | |
return TwoPartForm.toForm( bin ); | |
} | |
@Override | |
public Object toForm( long bin ) | |
throws InvalidBin | |
{ | |
return TwoPartForm.toForm( bin ); | |
} | |
public String format (/*{rowForm*/boolean rowForm/*}*/, /*{columnForm*/boolean/*}*/ columnForm ) | |
throws InvalidForm | |
{ | |
return TwoPartForm.format( rowForm, columnForm ); | |
} | |
@Override | |
public String format( Object form ) | |
throws InvalidForm | |
{ | |
if ( form instanceof Object[] ) | |
{ | |
return TwoPartForm.format( (Object[]) form ); | |
} | |
throw new InvalidForm ( "Expected Object[2] for " + describe() ); | |
} | |
@Override | |
public boolean isValidForm( Object form ) | |
{ | |
if ( form instanceof Object[] ) | |
{ | |
return TwoPartForm.isValidForm( (Object[]) form ); | |
} | |
return false; | |
} | |
@Override | |
public void validateForm( Object form ) | |
throws InvalidForm | |
{ | |
if ( form instanceof Object[] ) | |
{ | |
TwoPartForm.validateForm( (Object[]) form ); | |
return; | |
} | |
throw new InvalidForm ("Expected Object[2] for " + describe() ); | |
} | |
@Override | |
public int toBin( Object form ) | |
throws InvalidForm | |
{ | |
if ( form instanceof Object[] ) | |
{ | |
return TwoPartForm.toBin( (Object[]) form ); | |
} | |
throw new InvalidForm ("Expected Object[2] for " + describe() ); | |
} | |
@Override | |
public int getBitsCount() | |
{ | |
return 32 - Integer.numberOfLeadingZeros( MAX_BIN ); | |
} | |
@Override | |
public int getFirstBin() | |
{ | |
return MIN_BIN; | |
} | |
@Override | |
public int getLastBin() | |
{ | |
return MAX_BIN; | |
} | |
@Override | |
public boolean isValidBin( int bin ) | |
{ | |
return TwoPartForm.isValidBin( bin ); | |
} | |
@Override | |
public int validateBin( int bin ) | |
throws InvalidBin | |
{ | |
TwoPartForm.validateBin( bin ); | |
return bin; | |
} | |
@Override | |
public int synthesize() | |
{ | |
return TwoPartForm.synthesize(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment