Skip to content

Commit

Permalink
table: add unsigned byte I/O capability via UBYTE_FLAG_INFO aux
Browse files Browse the repository at this point in the history
The new ValueInfo Tables.UBYTE_FLAG_INFO can be attached to table
columns (e.g. by STIL format-specific table I/O handlers) to flag
a column as containing values in the unsigned byte range.
This allows (scalar or array) byte-valued columns to be round-tripped
e.g. when reading/writeing FITS or VOTable files; previously they
tended to get promoted to short ints and never shortened again.
  • Loading branch information
mbtaylor committed Feb 26, 2015
1 parent d4a8efe commit 37a06ea
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 7 deletions.
22 changes: 22 additions & 0 deletions table/src/main/uk/ac/starlink/table/Tables.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,28 @@ public class Tables {
new DefaultValueInfo( "NULL_VALUE", Object.class,
"Integer value which represents a null" );

/**
* ValueInfo which may be used as part of a column's auxiliary metadata
* to indicate that the column's data represents, and can be
* serialised as, unsigned byte values. If so, the value is set to
* <code>Boolean.TRUE</code> (other values are treated as if absent).
* Data representing unsigned byte values will normally be represented
* within STIL by Short (16-bit integer) signed values,
* since there is no unsigned byte type in java.
* However, this flag may be used to indicate that the
* values can be serialised to unsigned-byte-capable output formats
* (for instance FITS and VOTable) using an unsigned byte serialisation.
* This annotation will normally only be honoured if the data type of
* the column is (scalar or array) short integer (16-bit) values.
* Some care should be exercised in applying this flag or (especially)
* modifying values in columns it applies to, that the actual column
* value range remains in the unsigned byte data range (0..255),
* since otherwise problems will result if it is serialised.
*/
public static final ValueInfo UBYTE_FLAG_INFO =
new DefaultValueInfo( "UBYTE_FLAG", Boolean.class,
"If true, data represents unsigned byte values" );

/**
* ValueInfo representing Right Ascension.
* The units are radians and it is non-nullable.
Expand Down
14 changes: 13 additions & 1 deletion table/src/testcases/uk/ac/starlink/table/AutoStarTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ public void addColumn( ColumnInfo colinfo ) {
final int esize = colinfo.getElementSize();
final boolean isArray = colinfo.isArray();
final int icol = getColumnCount() + 1;
final boolean isUbyte =
Boolean.TRUE
.equals( colinfo.getAuxDatumValue( Tables.UBYTE_FLAG_INFO,
Boolean.class ) );
int n1 = 1;
if ( shape != null && shape.length > 0 ) {
for ( int i = 0; i < shape.length; i++ ) {
Expand Down Expand Up @@ -78,7 +82,8 @@ else if ( clazz == Byte.class ) {
return new Byte( val );
}
else if ( clazz == Short.class ) {
return new Short( (short) irow );
return isUbyte ? new Short( (short) ( irow % 256 ) )
: new Short( (short) irow );
}
else if ( clazz == Integer.class ) {
return new Integer( icol + 100 * irow );
Expand Down Expand Up @@ -119,6 +124,13 @@ else if ( clazz == byte[].class ||
Object array = Array.newInstance( clazz.getComponentType(),
nel );
testcase.fillCycle( array, -icol - irow, icol + irow );
if ( clazz == short[].class && isUbyte ) {
short[] sarray = (short[]) array;
for ( int i = 0; i < sarray.length; i++ ) {
sarray[ i ] =
(short) ( Math.abs( sarray[ i ] ) % 256 );
}
}
return array;
}
else if ( clazz == String[].class ) {
Expand Down
27 changes: 21 additions & 6 deletions table/src/testcases/uk/ac/starlink/table/FormatsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ public class FormatsTest extends TableCase {
new DefaultValueInfo( "Size", Double.class, null );
private StarTableOutput sto = new StarTableOutput();
private static final String FUNNY_UNITS = "\"'<a&b>'\"";
private static final DescribedValue UBYTE_AUXDATUM =
new DescribedValue( Tables.UBYTE_FLAG_INFO, Boolean.TRUE );

static {
MATRIX_INFO.setShape( new int[] { 2, -1 } );
Expand Down Expand Up @@ -115,30 +117,43 @@ public Object readValue( long lrow ) {
}
} );

Class[] ptypes = { byte.class, short.class, int.class, long.class,
float.class, double.class, };
Class[] ptypes = { byte.class, short.class, short.class, int.class,
long.class, float.class, double.class, };
for ( int i = 0; i < ptypes.length; i++ ) {
final Class ptype = ptypes[ i ];
String pname = ptype.getName();
ColumnInfo colinfo = new ColumnInfo( MATRIX_INFO );
if ( i == 1 ) {
assertEquals( short.class, ptype );
pname = "ubyte";
colinfo.setAuxDatum( UBYTE_AUXDATUM );
}
colinfo.setContentClass( Array.newInstance( ptype, 0 ).getClass() );
colinfo.setName( ptype.getName() + "_matrix" );
colinfo.setName( pname + "_matrix" );
ctable.addColumn( colinfo );
ColumnInfo colinfo2 = new ColumnInfo( colinfo );
colinfo2.setName( ptype.getName() + "_vector" );
colinfo2.setName( pname + "_vector" );
final int nel = ( i + 2 ) % 4 + 2;
colinfo2.setShape( new int[] { nel } );
final int bs = i;
ctable.addColumn( colinfo2 );
}

Class[] stypes = { Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class, String.class };
Class[] stypes = { Byte.class, Short.class, Short.class, Integer.class,
Long.class, Float.class, Double.class,
String.class };
for ( int i = 0; i < stypes.length; i++ ) {
final int itype = i;
final Class stype = stypes[ i ];
String name = stype.getName().replaceFirst( "java.lang.", "" );
ColumnInfo colinfo = new ColumnInfo( name + "Scalar", stype,
name + " scalar data" );
if ( i == 1 ) {
assertEquals( Short.class, stype );
colinfo.setAuxDatum( UBYTE_AUXDATUM );
colinfo.setName( "ubyteScalar" );
colinfo.setDescription( "Unsigned byte scalar data" );
}
ctable.addColumn( colinfo );
}
}
Expand Down

0 comments on commit 37a06ea

Please sign in to comment.