1 /*
   2  * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
   3  *                         University Research and Technology
   4  *                         Corporation.  All rights reserved.
   5  * Copyright (c) 2004-2005 The University of Tennessee and The University
   6  *                         of Tennessee Research Foundation.  All rights
   7  *                         reserved.
   8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
   9  *                         University of Stuttgart.  All rights reserved.
  10  * Copyright (c) 2004-2005 The Regents of the University of California.
  11  *                         All rights reserved.
  12  * Copyright (c) 2015      Los Alamos National Security, LLC. All rights
  13  *                         reserved.
  14  * Copyright (c) 2018      FUJITSU LIMITED.  All rights reserved.
  15  * $COPYRIGHT$
  16  *
  17  * Additional copyrights may follow
  18  *
  19  * $HEADER$
  20  *
  21  *
  22  * This file is almost a complete re-write for Open MPI compared to the
  23  * original mpiJava package. Its license and copyright are listed below.
  24  * See <path to ompi/mpi/java/README> for more information.
  25  *
  26  *
  27  *  Licensed under the Apache License, Version 2.0 (the "License");
  28  *  you may not use this file except in compliance with the License.
  29  *  You may obtain a copy of the License at
  30  *
  31  *     http://www.apache.org/licenses/LICENSE-2.0
  32  *
  33  *  Unless required by applicable law or agreed to in writing, software
  34  *  distributed under the License is distributed on an "AS IS" BASIS,
  35  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  36  *  See the License for the specific language governing permissions and
  37  *  limitations under the License.
  38  *
  39  *
  40  * File         : Datatype.java
  41  * Author       : Sang Lim, Sung-Hoon Ko, Xinying Li, Bryan Carpenter
  42  * Created      : Thu Apr  9 12:22:15 1998
  43  * Revision     : $Revision: 1.14 $
  44  * Updated      : $Date: 2003/01/16 16:39:34 $
  45  * Copyright: Northeast Parallel Architectures Center
  46  *            at Syracuse University 1998
  47  */
  48 
  49 package mpi;
  50 
  51 import java.nio.*;
  52 
  53 /**
  54  * The {@code Datatype} class represents {@code MPI_Datatype} handles.
  55  */
  56 public final class Datatype implements Freeable, Cloneable
  57 {
  58         protected long handle;
  59         protected int baseType;
  60         protected int baseSize;
  61 
  62         // Cache to avoid unnecessary jni calls.
  63         private int lb, extent, trueLb, trueExtent;
  64 
  65         protected static final int NULL       =  0;
  66         protected static final int BYTE       =  1;
  67         protected static final int CHAR       =  2;
  68         protected static final int SHORT      =  3;
  69         protected static final int BOOLEAN    =  4;
  70         protected static final int INT        =  5;
  71         protected static final int LONG       =  6;
  72         protected static final int FLOAT      =  7;
  73         protected static final int DOUBLE     =  8;
  74         protected static final int PACKED     =  9;
  75         protected static final int INT2       = 10;
  76         protected static final int SHORT_INT  = 11;
  77         protected static final int LONG_INT   = 12;
  78         protected static final int FLOAT_INT  = 13;
  79         protected static final int DOUBLE_INT = 14;
  80         protected static final int FLOAT_COMPLEX  = 15;
  81         protected static final int DOUBLE_COMPLEX = 16;
  82 
  83         static
  84         {
  85                 init();
  86         }
  87 
  88         private static native void init();
  89 
  90         /*
  91          * Constructor used in static initializer of 'MPI'.
  92          *
  93          * (Called before MPI.Init(), so cannot make any native MPI calls.)
  94          *
  95          * (Initialization done in separate 'setBasic', so can create
  96          * datatype objects for 'BYTE', etc in static initializers invoked before
  97          * MPI.Init(), then initialize objects after MPI initialized.)
  98          */
  99         protected Datatype()
 100         {
 101         }
 102 
 103         protected void setBasic(int type)
 104         {
 105                 baseType = type;
 106                 handle   = getDatatype(type);
 107                 baseSize = type == NULL ? 0 : getSize(handle);
 108         }
 109 
 110         protected void setBasic(int type, Datatype oldType)
 111         {
 112                 baseType = oldType.baseType;
 113                 handle   = getDatatype(type);
 114                 baseSize = oldType.baseSize;
 115         }
 116 
 117         private static native long getDatatype(int type);
 118 
 119         /*
 120          * Constructor used in 'create*' methods.
 121          */
 122         private Datatype(Datatype oldType, long handle)
 123         {
 124                 baseType = oldType.baseType;
 125                 baseSize = oldType.baseSize;
 126                 this.handle = handle;
 127         }
 128 
 129         /*
 130          * Constructor used in 'create*' methods.
 131          */
 132         private Datatype(int baseType, int baseSize, long handle)
 133         {
 134                 this.baseType = baseType;
 135                 this.baseSize = baseSize;
 136                 this.handle   = handle;
 137         }
 138 
 139         /**
 140          * Returns the lower bound of a datatype.
 141          * <p>Java binding of the MPI operation {@code MPI_TYPE_GET_EXTENT}.
 142          * @return lower bound of datatype
 143          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 144          */
 145         public int getLb() throws MPIException
 146         {
 147                 if(extent == 0)
 148                         getLbExtent();
 149 
 150                 return lb;
 151         }
 152 
 153         /**
 154          * Returns the extent of a datatype.
 155          * <p>Java binding of the MPI operation {@code MPI_TYPE_GET_EXTENT}.
 156          * @return datatype extent
 157          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 158          */
 159         public int getExtent() throws MPIException
 160         {
 161                 if(extent == 0)
 162                         getLbExtent();
 163 
 164                 return extent;
 165         }
 166 
 167         private void getLbExtent() throws MPIException
 168         {
 169                 MPI.check();
 170                 int lbExt[] = new int[2];
 171                 getLbExtent(handle, lbExt);
 172                 lb     = lbExt[0] / baseSize;
 173                 extent = lbExt[1] / baseSize;
 174         }
 175 
 176         private native void getLbExtent(long handle, int[] lbExt);
 177 
 178         /**
 179          * Returns the true lower bound of a datatype.
 180          * <p>Java binding of the MPI operation {@code MPI_TYPE_GET_TRUE_EXTENT}.
 181          * @return lower bound of datatype
 182          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 183          */
 184         public int getTrueLb() throws MPIException
 185         {
 186                 if(trueExtent == 0)
 187                         getTrueLbExtent();
 188 
 189                 return trueLb;
 190         }
 191 
 192         /**
 193          * Returns the true extent of a datatype.
 194          * <p>Java binding of the MPI operation {@code MPI_TYPE_GET_TRUE_EXTENT}.
 195          * @return datatype true extent
 196          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 197          */
 198         public int getTrueExtent() throws MPIException
 199         {
 200                 if(trueExtent == 0)
 201                         getTrueLbExtent();
 202 
 203                 return trueExtent;
 204         }
 205 
 206         private void getTrueLbExtent() throws MPIException
 207         {
 208                 MPI.check();
 209                 int lbExt[] = new int[2];
 210                 getTrueLbExtent(handle, lbExt);
 211                 trueLb     = lbExt[0] / baseSize;
 212                 trueExtent = lbExt[1] / baseSize;
 213         }
 214 
 215         private native void getTrueLbExtent(long handle, int[] lbExt);
 216 
 217         /**
 218          * Returns the total size of a datatype - the number of buffer
 219          * elements it represents.
 220          * <p>Java binding of the MPI operation {@code MPI_TYPE_SIZE}.
 221          * @return datatype size
 222          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 223          */
 224         public int getSize() throws MPIException
 225         {
 226                 MPI.check();
 227                 return getSize(handle) / baseSize;
 228         }
 229 
 230         private native int getSize(long type);
 231 
 232         /**
 233          * Commits a derived datatype.
 234          * Java binding of the MPI operation {@code MPI_TYPE_COMMIT}.
 235          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 236          */
 237         public void commit() throws MPIException
 238         {
 239                 MPI.check();
 240                 commit(handle);
 241         }
 242 
 243         private native void commit(long type);
 244 
 245         /**
 246          * Frees the datatype.
 247          * <p>Java binding of the MPI operation {@code MPI_TYPE_FREE}.
 248          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 249          */
 250         @Override public void free() throws MPIException
 251         {
 252                 MPI.check();
 253                 handle = free(handle);
 254         }
 255 
 256         private native long free(long type) throws MPIException;
 257 
 258         /**
 259          * Returns {@code true} if this datatype is MPI_DATATYPE_NULL.
 260          * @return {@code true} if this datatype is MPI_DATATYPE_NULL
 261          */
 262         public boolean isNull()
 263         {
 264                 return handle == MPI.DATATYPE_NULL.handle;
 265         }
 266 
 267         /**
 268          * Java binding of {@code MPI_TYPE_DUP}.
 269          * <p>It is recommended to use {@link #dup} instead of {@link #clone}
 270          * because the last can't throw an {@link mpi.MPIException}.
 271          * @return new datatype
 272          */
 273         @Override public Datatype clone()
 274         {
 275                 try
 276                 {
 277                         return dup();
 278                 }
 279                 catch(MPIException e)
 280                 {
 281                         throw new RuntimeException(e.getMessage());
 282                 }
 283         }
 284 
 285         /**
 286          * Java binding of {@code MPI_TYPE_DUP}.
 287          * @return new datatype
 288          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 289          */
 290         public Datatype dup() throws MPIException
 291         {
 292                 MPI.check();
 293                 return new Datatype(this, dup(handle));
 294         }
 295 
 296         private native long dup(long type) throws MPIException;
 297 
 298         /**
 299          * Construct new datatype representing replication of old datatype into
 300          * contiguous locations.
 301          * <p>Java binding of the MPI operation {@code MPI_TYPE_CONTIGUOUS}.
 302          * <p>The base type of the new datatype is the same as the base type of
 303          * {@code oldType}.
 304          * @param count   replication count
 305          * @param oldType old datatype
 306          * @return new datatype
 307          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 308          */
 309         public static Datatype createContiguous(int count, Datatype oldType)
 310                         throws MPIException
 311         {
 312                 MPI.check();
 313                 return new Datatype(oldType, getContiguous(count, oldType.handle));
 314         }
 315 
 316         private static native long getContiguous(int count, long oldType);
 317 
 318         /**
 319          * Construct new datatype representing replication of old datatype into
 320          * locations that consist of equally spaced blocks.
 321          * <p>Java binding of the MPI operation {@code MPI_TYPE_VECTOR}.
 322          * <p>The base type of the new datatype is the same as the base type of
 323          * {@code oldType}.
 324          * @param count       number of blocks
 325          * @param blockLength number of elements in each block
 326          * @param stride      number of elements between start of each block
 327          * @param oldType     old datatype
 328          * @return new datatype
 329          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 330          */
 331         public static Datatype createVector(int count, int blockLength,
 332                         int stride, Datatype oldType)
 333                                         throws MPIException
 334         {
 335                 MPI.check();
 336                 long handle = getVector(count, blockLength, stride, oldType.handle);
 337                 return new Datatype(oldType, handle);
 338         }
 339 
 340         private static native long getVector(
 341                         int count, int blockLength, int stride, long oldType)
 342                                         throws MPIException;
 343 
 344         /**
 345          * Identical to {@code createVector} except that the stride is expressed
 346          * directly in terms of the buffer index, rather than the units of
 347          * the old type.
 348          * <p>Java binding of the MPI operation {@code MPI_TYPE_CREATE_HVECTOR}.
 349          * @param count       number of blocks
 350          * @param blockLength number of elements in each
 351          * @param stride      number of bytes between start of each block
 352          * @param oldType     old datatype
 353          * @return new datatype
 354          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 355          */
 356         public static Datatype createHVector(int count, int blockLength,
 357                         int stride, Datatype oldType)
 358                                         throws MPIException
 359         {
 360                 MPI.check();
 361                 long handle = getHVector(count, blockLength, stride, oldType.handle);
 362                 return new Datatype(oldType, handle);
 363         }
 364 
 365         private static native long getHVector(
 366                         int count, int blockLength, int stride, long oldType)
 367                                         throws MPIException;
 368 
 369         /**
 370          * Construct new datatype representing replication of old datatype into
 371          * a sequence of blocks where each block can contain a different number
 372          * of copies and have a different displacement.
 373          * <p>Java binding of the MPI operation {@code MPI_TYPE_INDEXED}.
 374          * <p>The number of blocks is taken to be size of the {@code blockLengths}
 375          * argument. The second argument, {@code displacements}, should be the
 376          * same size. The base type of the new datatype is the same as the base
 377          * type of {@code oldType}.
 378          * @param blockLengths  number of elements per block
 379          * @param displacements displacement of each block in units of old type
 380          * @param oldType       old datatype
 381          * @return new datatype
 382          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 383          */
 384         public static Datatype createIndexed(int[] blockLengths,
 385                         int[] displacements, Datatype oldType)
 386                                         throws MPIException
 387         {
 388                 MPI.check();
 389                 long handle = getIndexed(blockLengths, displacements, oldType.handle);
 390                 return new Datatype(oldType, handle);
 391         }
 392 
 393         private static native long getIndexed(
 394                         int[] blockLengths, int[] displacements, long oldType)
 395                                         throws MPIException;
 396 
 397         /**
 398          * Identical to {@code createIndexed} except that the displacements are
 399          * expressed directly in terms of the buffer index, rather than the
 400          * units of the old type.
 401          * <p>Java binding of the MPI operation {@code MPI_TYPE_CREATE_HINDEXED}.
 402          * @param blockLengths  number of elements per block
 403          * @param displacements byte displacement in buffer for each block
 404          * @param oldType       old datatype
 405          * @return new datatype
 406          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 407          */
 408         public static Datatype createHIndexed(int[] blockLengths,
 409                         int[] displacements, Datatype oldType)
 410                                         throws MPIException
 411         {
 412                 MPI.check();
 413                 long handle = getHIndexed(blockLengths, displacements, oldType.handle);
 414                 return new Datatype(oldType, handle);
 415         }
 416 
 417         private static native long getHIndexed(
 418                         int[] blockLengths, int[] displacements, long oldType)
 419                                         throws MPIException;
 420 
 421         /**
 422          * The most general type constructor.
 423          * <p>Java binding of the MPI operation {@code MPI_TYPE_CREATE_STRUCT}.
 424          * <p>The number of blocks is taken to be size of the {@code blockLengths}
 425          * argument. The second and third arguments, {@code displacements},
 426          * and {@code types}, should be the same size.
 427          * @param blockLengths  number of elements in each block
 428          * @param displacements byte displacement of each block
 429          * @param types         type of elements in each block
 430          * @return new datatype
 431          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 432          */
 433         public static Datatype createStruct(int[] blockLengths,
 434                         int[] displacements, Datatype[] types)
 435                                         throws MPIException
 436         {
 437                 MPI.check();
 438                 long handle = getStruct(blockLengths, displacements, types);
 439                 return new Datatype(MPI.BYTE, handle);
 440         }
 441 
 442         private static native long getStruct(
 443                         int[] blockLengths, int[] displacements, Datatype[] types)
 444                                         throws MPIException;
 445 
 446         /*
 447          * JMS add proper documentation here
 448          * JMS int != Aint!  This needs to be fixed throughout.
 449          */
 450         /**
 451          * Create a datatype with a new lower bound and extent from an existing
 452          * datatype.
 453          * <p>Java binding of the MPI operation {@code MPI_TYPE_CREATE_RESIZED}.
 454          * @param oldType input datatype
 455          * @param lb      new lower bound of datatype (address integer)
 456          * @param extent  new extent of datatype (address integer)
 457          * @return new datatype
 458          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 459          */
 460         public static Datatype createResized(Datatype oldType, int lb, int extent)
 461                         throws MPIException
 462         {
 463                 MPI.check();
 464                 long handle = getResized(oldType.handle, lb, extent);
 465                 return new Datatype(oldType, handle);
 466         }
 467 
 468         private static native long getResized(long oldType, int lb, int extent);
 469 
 470         /**
 471          * Sets the print name for the datatype.
 472          * @param name name for the datatype
 473          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 474          */
 475         public void setName(String name) throws MPIException
 476         {
 477                 MPI.check();
 478                 setName(handle, name);
 479         }
 480 
 481         private native void setName(long handle, String name) throws MPIException;
 482 
 483         /**
 484          * Return the print name from the datatype.
 485          * @return name of the datatype
 486          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 487          */
 488         public String getName() throws MPIException
 489         {
 490                 MPI.check();
 491                 return getName(handle);
 492         }
 493 
 494         private native String getName(long handle) throws MPIException;
 495 
 496         /**
 497          * Create a new attribute key.
 498          * <p>Java binding of the MPI operation {@code MPI_TYPE_CREATE_KEYVAL}.
 499          * @return attribute key for future access
 500          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 501          */
 502         public static int createKeyval() throws MPIException
 503         {
 504                 MPI.check();
 505                 return createKeyval_jni();
 506         }
 507 
 508         private static native int createKeyval_jni() throws MPIException;
 509 
 510         /**
 511          * Frees an attribute key.
 512          * <p>Java binding of the MPI operation {@code MPI_TYPE_FREE_KEYVAL}.
 513          * @param keyval attribute key
 514          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 515          */
 516         public static void freeKeyval(int keyval) throws MPIException
 517         {
 518                 MPI.check();
 519                 freeKeyval_jni(keyval);
 520         }
 521 
 522         private static native void freeKeyval_jni(int keyval) throws MPIException;
 523 
 524         /**
 525          * Stores attribute value associated with a key.
 526          * <p>Java binding of the MPI operation {@code MPI_TYPE_SET_ATTR}.
 527          * @param keyval attribute key
 528          * @param value  attribute value
 529          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 530          */
 531         public void setAttr(int keyval, Object value) throws MPIException
 532         {
 533                 MPI.check();
 534                 setAttr(handle, keyval, MPI.attrSet(value));
 535         }
 536 
 537         private native void setAttr(long type, int keyval, byte[] value)
 538                         throws MPIException;
 539 
 540         /**
 541          * Retrieves attribute value by key.
 542          * <p>Java binding of the MPI operation {@code MPI_TYPE_GET_ATTR}.
 543          * @param keyval attribute key
 544          * @return attribute value or null if no attribute is associated with the key.
 545          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 546          */
 547         public Object getAttr(int keyval) throws MPIException
 548         {
 549                 MPI.check();
 550                 Object obj = getAttr(handle, keyval);
 551                 return obj instanceof byte[] ? MPI.attrGet((byte[])obj) : obj;
 552         }
 553 
 554         private native Object getAttr(long type, int keyval) throws MPIException;
 555 
 556         /**
 557          * Deletes an attribute value associated with a key.
 558          * <p>Java binding of the MPI operation {@code MPI_TYPE_DELETE_ATTR}.
 559          * @param keyval attribute key
 560          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 561          */
 562         public void deleteAttr(int keyval) throws MPIException
 563         {
 564                 MPI.check();
 565                 deleteAttr(handle, keyval);
 566         }
 567 
 568         private native void deleteAttr(long type, int keyval) throws MPIException;
 569 
 570         /**
 571          * Gets the offset of a buffer in bytes.
 572          * @param buffer buffer
 573          * @return offset in bytes
 574          */
 575         protected int getOffset(Object buffer)
 576         {
 577                 return baseSize * ((Buffer)buffer).arrayOffset();
 578         }
 579 
 580 } // Datatype