/* * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana * University Research and Technology * Corporation. All rights reserved. * Copyright (c) 2004-2005 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, * University of Stuttgart. All rights reserved. * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ package mpi; import java.nio.*; import java.util.*; /** * Base class for defining struct data types. */ public abstract class Struct { private int extent; private ArrayList fields = new ArrayList(); private Datatype datatype, types[]; private int offsets[], lengths[]; private static final String typeMismatch = "Type mismatch"; private void commit() throws MPIException { if(datatype == null) createStruct(); } private void createStruct() throws MPIException { int count = fields.size(); types = new Datatype[count]; offsets = new int[count]; lengths = new int[count]; for(int i = 0; i < count; i++) { Field f = fields.get(i); types[i] = f.type instanceof Struct ? ((Struct)f.type).datatype : (Datatype)f.type; offsets[i] = f.offset; lengths[i] = f.length; } datatype = Datatype.createStruct(lengths, offsets, types); datatype.commit(); extent = datatype.getExtent(); } /** * Returns the extent of the struct data type. * @return Extent of the struct data type. * @throws MPIException Signals that an MPI exception of some sort has occurred. */ public final int getExtent() throws MPIException { commit(); return extent; } /** * Returns the data type of the struct. * @return The data type of the struct. * @throws MPIException Signals that an MPI exception of some sort has occurred. */ public final Datatype getType() throws MPIException { commit(); return datatype; } /** * Creates a Data object. * @return New Data object. */ protected abstract Data newData(); @SuppressWarnings("unchecked") private T newData(ByteBuffer buffer, int offset) { Data d = newData(); d.buffer = buffer; d.offset = offset; return (T)d; } @SuppressWarnings("javadoc") /** * Gets a Data object in order to access to the buffer. * @param buffer the Data object will read/write on this buffer. * @return Data object * @throws MPIException Signals that an MPI exception of some sort has occurred. */ public final T getData(ByteBuffer buffer) throws MPIException { commit(); return newData(buffer, 0); } @SuppressWarnings("javadoc") /** * Gets a Data object in order to access to the struct at the * specified position of a struct array stored in a Buffer. * @param buffer The Data object will read/write on this buffer. * @param index Index of the struct in the buffer. * @return Data object. * @throws MPIException Signals that an MPI exception of some sort has occurred. */ public final T getData(ByteBuffer buffer, int index) throws MPIException { commit(); return newData(buffer, index * extent); } @SuppressWarnings("javadoc") /** * Gets a Data object in order to access to the byte array. * @param array The Data object will read/write on this byte array. * @return Data object. * @throws MPIException Signals that an MPI exception of some sort has occurred. */ public final T getData(byte[] array) throws MPIException { ByteBuffer buffer = ByteBuffer.wrap(array); buffer.order(ByteOrder.nativeOrder()); return getData(buffer); } @SuppressWarnings("javadoc") /** * Gets a Data object in order to access to the struct at the * specified position of a struct array stored in a byte array. * @param array The Data object will read/write on this byte array. * @param index Index of the struct in the array. * @return Data object. * @throws MPIException Signals that an MPI exception of some sort has occurred. */ public final T getData(byte[] array, int index) throws MPIException { ByteBuffer buffer = ByteBuffer.wrap(array); buffer.order(ByteOrder.nativeOrder()); return getData(buffer, index); } private int addField(Object type, int typeExtent, int length) { if(datatype != null) throw new AssertionError("The struct data type was committed."); int offset = extent; extent += typeExtent * length; fields.add(new Field(type, offset, length)); return offset; } /** * Sets the offset of the next field. *

The offset must be greater or equal to the accumulated extent. * @param offset offset of the next field * @return this object in order to allow adding fields in a chained expression */ public final Struct setOffset(int offset) { if(datatype != null) throw new AssertionError("The struct data type was committed."); if(offset < extent) { throw new IllegalArgumentException( "The offset must be greater or equal to the accumulated extent."); } extent = offset; return this; } /** * Adds a byte field to this struct. * @return Offset of the new field. */ public final int addByte() { return addByte(1); } /** * Adds a byte array to this struct. * @param length Length of the array. * @return Offset of the new field. */ public final int addByte(int length) { return addField(MPI.BYTE, 1, length); } /** * Adds a char field to this struct. * @return Offset of the new field. */ public final int addChar() { return addChar(1); } /** * Adds a char array to this struct. * @param length Length of the array. * @return Offset of the new field. */ public final int addChar(int length) { return addField(MPI.CHAR, 2, length); } /** * Adds a short field to this struct. * @return Offset of the new field. */ public final int addShort() { return addShort(1); } /** * Adds a short array to this struct. * @param length Length of the array. * @return Offset of the new field. */ public final int addShort(int length) { return addField(MPI.SHORT, 2, length); } /** * Adds an int field to this struct. * @return Offset of the new field. */ public final int addInt() { return addInt(1); } /** * Adds an int array to this struct. * @param length Length of the array. * @return Offset of the new field. */ public final int addInt(int length) { return addField(MPI.INT, 4, length); } /** * Adds a long field to this struct. * @return Offset of the new field. */ public final int addLong() { return addLong(1); } /** * Adds a long array to this struct. * @param length Length of the array. * @return Offset of the new field. */ public final int addLong(int length) { return addField(MPI.LONG, 8, length); } /** * Adds a float field to this struct. * @return Offset of the new field. */ public final int addFloat() { return addFloat(1); } /** * Adds a float array to this struct. * @param length Length of the array. * @return Offset of the new field. */ public final int addFloat(int length) { return addField(MPI.FLOAT, 4, length); } /** * Adds a double field to this struct. * @return Offset of the new field. */ public final int addDouble() { return addDouble(1); } /** * Adds a double array to this struct. * @param length Length of the array. * @return Offset of the new field. */ public final int addDouble(int length) { return addField(MPI.DOUBLE, 8, length); } /** * Adds a struct field to this struct. * @param struct Type of the field. * @return Offset of the new field. * @throws MPIException Signals that an MPI exception of some sort has occurred. */ public final int addStruct(Struct struct) throws MPIException { return addStruct(struct, 1); } /** * Adds an array of structs to this struct. * @param struct Type of the array. * @param length Length of the array. * @return Offset of the new field. * @throws MPIException Signals that an MPI exception of some sort has occurred. */ public final int addStruct(Struct struct, int length) throws MPIException { struct.commit(); return addField(struct, struct.extent, length); } /** * Adds a field of the specified data type. * @param type Data type. * @return Offset of the new field. * @throws MPIException Signals that an MPI exception of some sort has occurred. */ public final int addData(Datatype type) throws MPIException { return addData(type, 1); } /** * Adds an array of the specified data type. * @param type Data type. * @param length Length of the array. * @return Offset of the new field. * @throws MPIException Signals that an MPI exception of some sort has occurred. */ public final int addData(Datatype type, int length) throws MPIException { return addField(type, type.getExtent() * type.baseSize, length); } private boolean validType(int fieldOffset, int index, Datatype type) { int i = Arrays.binarySearch(offsets, fieldOffset); return index >= 0 && index < lengths[i] && type == types[i]; } private static class Field { private Object type; private int offset, length; private Field(Object type, int offset, int length) { this.type = type; this.offset = offset; this.length = length; } } // Field /** * Base class for reading/writing data in a struct stored in a byte buffer. */ public abstract class Data { private ByteBuffer buffer; private int offset; /** * Gets the buffer where this struct data is stored. *

The buffer can be used in {@code send}/{@code recv} operations. * @return Buffer where the struct data is stored. */ public final ByteBuffer getBuffer() { return offset == 0 ? buffer : MPI.slice(buffer, offset); } /** * Gets the byte value of a field. * @param field Offset of the field. * @return Byte value. */ protected final byte getByte(int field) { assert validType(field, 0, MPI.BYTE) : typeMismatch; return buffer.get(offset + field); } /** * Gets the byte value at the specified position of a byte array. * @param field Offset of the byte array. * @param index Index of the byte in the array. * @return Byte value. */ protected final byte getByte(int field, int index) { assert validType(field, index, MPI.BYTE) : typeMismatch; return buffer.get(offset + field + index); } /** * Puts a byte value in a field. * @param field Offset of the field. * @param v Byte value. */ protected final void putByte(int field, byte v) { assert validType(field, 0, MPI.BYTE) : typeMismatch; buffer.put(offset + field, v); } /** * Puts a byte value at the specified position of a byte array. * @param field Offset of the byte array. * @param index Index of the byte in the array. * @param v Byte value. */ protected final void putByte(int field, int index, byte v) { assert validType(field, index, MPI.BYTE) : typeMismatch; buffer.put(offset + field + index, v); } /** * Gets the char value of a field. * @param field Offset of the field. * @return Char value. */ protected final char getChar(int field) { assert validType(field, 0, MPI.CHAR) : typeMismatch; return buffer.getChar(offset + field); } /** * Gets the char value at the specified position of a char array. * @param field Offset of the char array. * @param index Index of the char in the array. * @return Char value. */ protected final char getChar(int field, int index) { assert validType(field, index, MPI.CHAR) : typeMismatch; return buffer.getChar(offset + field + index * 2); } /** * Puts a char value in a field. * @param field Offset of the field. * @param v Char value. */ protected final void putChar(int field, char v) { assert validType(field, 0, MPI.CHAR) : typeMismatch; buffer.putChar(offset + field, v); } /** * Puts a char value at the specified position of a char array. * @param field Offset of the char array. * @param index Index of the char in the array. * @param v Char value. */ protected final void putChar(int field, int index, char v) { assert validType(field, index, MPI.CHAR) : typeMismatch; buffer.putChar(offset + field + index * 2, v); } /** * Gets the short value of a field. * @param field Offset of the field. * @return Short value. */ protected final short getShort(int field) { assert validType(field, 0, MPI.SHORT) : typeMismatch; return buffer.getShort(offset + field); } /** * Gets the short value at the specified position of a short array. * @param field Offset of the short array. * @param index Index of the short in the array. * @return Short value. */ protected final short getShort(int field, int index) { assert validType(field, index, MPI.SHORT) : typeMismatch; return buffer.getShort(offset + field + index * 2); } /** * Puts a short value in a field. * @param field Offset of the field. * @param v Short value. */ protected final void putShort(int field, short v) { assert validType(field, 0, MPI.SHORT) : typeMismatch; buffer.putShort(offset + field, v); } /** * Puts a short value at the specified position of a short array. * @param field Offset of the short array. * @param index Index of the short in the array. * @param v Short value. */ protected final void putShort(int field, int index, short v) { assert validType(field, index, MPI.SHORT) : typeMismatch; buffer.putShort(offset + field + index * 2, v); } /** * Gets the int value of a field. * @param field Offset of the field. * @return Int value. */ protected final int getInt(int field) { assert validType(field, 0, MPI.INT) : typeMismatch; return buffer.getInt(offset + field); } /** * Gets the int value at the specified position of an int array. * @param field Offset of the int array. * @param index Index of the int in the array. * @return Int value. */ protected final int getInt(int field, int index) { assert validType(field, index, MPI.INT) : typeMismatch; return buffer.getInt(offset + field + index * 4); } /** * Puts an int value in a field. * @param field Offset of the field. * @param v Int value. */ protected final void putInt(int field, int v) { assert validType(field, 0, MPI.INT) : typeMismatch; buffer.putInt(offset + field, v); } /** * Puts an int value at the specified position of an int array. * @param field Offset of the int array. * @param index Index of the int in the array. * @param v Int value. */ protected final void putInt(int field, int index, int v) { assert validType(field, index, MPI.INT) : typeMismatch; buffer.putInt(offset + field + index * 4, v); } /** * Gets the long value of a field. * @param field Offset of the field. * @return Long value. */ protected final long getLong(int field) { assert validType(field, 0, MPI.LONG) : typeMismatch; return buffer.getLong(offset + field); } /** * Gets the long value at the specified position of a long array. * @param field Offset of the long array. * @param index Index of the long in the array. * @return Long value. */ protected final long getLong(int field, int index) { assert validType(field, index, MPI.LONG) : typeMismatch; return buffer.getLong(offset + field + index * 8); } /** * Puts a long value in a field. * @param field Offset of the field. * @param v Long value. */ protected final void putLong(int field, long v) { assert validType(field, 0, MPI.LONG) : typeMismatch; buffer.putLong(offset + field, v); } /** * Puts a long value at the specified position of a long array. * @param field Offset of the long array. * @param index Index of the long in the array. * @param v Long value. */ protected final void putLong(int field, int index, long v) { assert validType(field, index, MPI.LONG) : typeMismatch; buffer.putLong(offset + field + index * 8, v); } /** * Gets the float value of a field. * @param field Offset of the field. * @return Float value. */ protected final float getFloat(int field) { assert validType(field, 0, MPI.FLOAT) : typeMismatch; return buffer.getFloat(offset + field); } /** * Gets the float value at the specified position of a float array. * @param field Offset of the float array. * @param index Index of the float in the array. * @return Float value. */ protected final float getFloat(int field, int index) { assert validType(field, index, MPI.FLOAT) : typeMismatch; return buffer.getFloat(offset + field + index * 4); } /** * Puts a float value in a field. * @param field Offset of the field. * @param v Float value. */ protected final void putFloat(int field, float v) { assert validType(field, 0, MPI.FLOAT) : typeMismatch; buffer.putFloat(offset + field, v); } /** * Puts a float value at the specified position of a float array. * @param field Offset of the float array. * @param index Index of the float in the array. * @param v Float value. */ protected final void putFloat(int field, int index, float v) { assert validType(field, index, MPI.FLOAT) : typeMismatch; buffer.putFloat(offset + field + index * 4, v); } /** * Gets the double value of a field. * @param field Offset of the field. * @return Double value. */ protected final double getDouble(int field) { assert validType(field, 0, MPI.DOUBLE) : typeMismatch; return buffer.getDouble(offset + field); } /** * Gets the double value at the specified position of a double array. * @param field Offset of the double array. * @param index Index of the double in the array. * @return Double value. */ protected final double getDouble(int field, int index) { assert validType(field, index, MPI.DOUBLE) : typeMismatch; return buffer.getDouble(offset + field + index * 8); } /** * Puts a double value in a field. * @param field Offset of the field. * @param v Double value. */ protected final void putDouble(int field, double v) { assert validType(field, 0, MPI.DOUBLE) : typeMismatch; buffer.putDouble(offset + field, v); } /** * Puts a double value at the specified position of a double array. * @param field Offset of the double array. * @param index Index of the double in the array. * @param v Double value. */ protected final void putDouble(int field, int index, double v) { assert validType(field, index, MPI.DOUBLE) : typeMismatch; buffer.putDouble(offset + field + index * 8, v); } @SuppressWarnings("javadoc") /** * Gets the struct data of a field. * @param struct Struct type. * @param field Offset of the field. * @return Struct data. */ protected final D getData(S struct, int field) { Struct s = (Struct)struct; assert validType(field, 0, s.datatype) : typeMismatch; return s.newData(buffer, offset + field); } @SuppressWarnings("javadoc") /** * Gets the struct data at the specified position of a struct array. * @param struct Struct type. * @param field Offset of the struct array. * @param index Index of the struct in the array. * @return Struct data. */ protected final D getData(S struct, int field, int index) { Struct s = (Struct)struct; assert validType(field, index, s.datatype) : typeMismatch; return s.newData(buffer, offset + field + index * s.extent); } /** * Gets the buffer of a field. *

The buffer can be used in {@code send}/{@code recv} operations. * @param type Data type of the buffer. * @param field Offset of the field. * @return Buffer object. */ protected final ByteBuffer getBuffer(Datatype type, int field) { assert validType(field, 0, type) : typeMismatch; int position = offset + field; return position == 0 ? buffer : MPI.slice(buffer, position); } /** * Gets the buffer data at the specified position of a buffer array. *

The buffer can be used in {@code send}/{@code recv} operations. * @param type Data type of the buffer. * @param field Offset of the buffer array. * @param index Index of the buffer in the array. * @return Buffer object. * @throws MPIException Signals that an MPI exception of some sort has occurred. */ protected final ByteBuffer getBuffer(Datatype type, int field, int index) throws MPIException { assert validType(field, index, type) : typeMismatch; int extent = type.getExtent() * type.baseSize, position = offset + field + index * extent; return position == 0 ? buffer : MPI.slice(buffer, position); } } // Data } // Struct