Skip to content

Instantly share code, notes, and snippets.

@edefazio
Last active December 31, 2015 16:04
Show Gist options
  • Save edefazio/bf6047cdcb706d7cf545 to your computer and use it in GitHub Desktop.
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)
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