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$
  15  *
  16  * Additional copyrights may follow
  17  *
  18  * $HEADER$
  19  */
  20 
  21 package mpi;
  22 
  23 import java.nio.*;
  24 import java.util.*;
  25 
  26 /**
  27  * Base class for defining struct data types.
  28  */
  29 public abstract class Struct
  30 {
  31         private int extent;
  32         private ArrayList<Field> fields = new ArrayList<Field>();
  33 
  34         private Datatype datatype, types[];
  35         private int offsets[], lengths[];
  36         private static final String typeMismatch = "Type mismatch";
  37 
  38         private void commit() throws MPIException
  39         {
  40                 if(datatype == null)
  41                         createStruct();
  42         }
  43 
  44         private void createStruct() throws MPIException
  45         {
  46                 int count = fields.size();
  47                 types   = new Datatype[count];
  48                 offsets = new int[count];
  49                 lengths = new int[count];
  50 
  51                 for(int i = 0; i < count; i++)
  52                 {
  53                         Field f = fields.get(i);
  54 
  55                         types[i] = f.type instanceof Struct ? ((Struct)f.type).datatype
  56                                         : (Datatype)f.type;
  57                         offsets[i] = f.offset;
  58                         lengths[i] = f.length;
  59                 }
  60 
  61                 datatype = Datatype.createStruct(lengths, offsets, types);
  62                 datatype.commit();
  63                 extent = datatype.getExtent();
  64         }
  65 
  66         /**
  67          * Returns the extent of the struct data type.
  68          * @return Extent of the struct data type.
  69          * @throws MPIException Signals that an MPI exception of some sort has occurred.
  70          */
  71         public final int getExtent() throws MPIException
  72         {
  73                 commit();
  74                 return extent;
  75         }
  76 
  77         /**
  78          * Returns the data type of the struct.
  79          * @return The data type of the struct.
  80          * @throws MPIException Signals that an MPI exception of some sort has occurred.
  81          */
  82         public final Datatype getType() throws MPIException
  83         {
  84                 commit();
  85                 return datatype;
  86         }
  87 
  88         /**
  89          * Creates a Data object.
  90          * @return New Data object.
  91          */
  92         protected abstract Data newData();
  93 
  94         @SuppressWarnings("unchecked")
  95         private <T extends Data> T newData(ByteBuffer buffer, int offset)
  96         {
  97                 Data d = newData();
  98                 d.buffer = buffer;
  99                 d.offset = offset;
 100                 return (T)d;
 101         }
 102 
 103         @SuppressWarnings("javadoc")
 104         /**
 105          * Gets a Data object in order to access to the buffer.
 106          * @param buffer the Data object will read/write on this buffer.
 107          * @return Data object
 108          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 109          */
 110         public final <T extends Data> T getData(ByteBuffer buffer) throws MPIException
 111         {
 112                 commit();
 113                 return newData(buffer, 0);
 114         }
 115 
 116         @SuppressWarnings("javadoc")
 117         /**
 118          * Gets a Data object in order to access to the struct at the
 119          * specified position of a struct array stored in a Buffer.
 120          * @param buffer The Data object will read/write on this buffer.
 121          * @param index  Index of the struct in the buffer.
 122          * @return Data object.
 123          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 124          */
 125         public final <T extends Data> T getData(ByteBuffer buffer, int index)
 126                         throws MPIException
 127         {
 128                 commit();
 129                 return newData(buffer, index * extent);
 130         }
 131 
 132         @SuppressWarnings("javadoc")
 133         /**
 134          * Gets a Data object in order to access to the byte array.
 135          * @param array The Data object will read/write on this byte array.
 136          * @return Data object.
 137          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 138          */
 139         public final <T extends Data> T getData(byte[] array) throws MPIException
 140         {
 141                 ByteBuffer buffer = ByteBuffer.wrap(array);
 142                 buffer.order(ByteOrder.nativeOrder());
 143                 return getData(buffer);
 144         }
 145 
 146         @SuppressWarnings("javadoc")
 147         /**
 148          * Gets a Data object in order to access to the struct at the
 149          * specified position of a struct array stored in a byte array.
 150          * @param array The Data object will read/write on this byte array.
 151          * @param index Index of the struct in the array.
 152          * @return Data object.
 153          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 154          */
 155         public final <T extends Data> T getData(byte[] array, int index)
 156                         throws MPIException
 157         {
 158                 ByteBuffer buffer = ByteBuffer.wrap(array);
 159                 buffer.order(ByteOrder.nativeOrder());
 160                 return getData(buffer, index);
 161         }
 162 
 163         private int addField(Object type, int typeExtent, int length)
 164         {
 165                 if(datatype != null)
 166                         throw new AssertionError("The struct data type was committed.");
 167 
 168                 int offset = extent;
 169                 extent += typeExtent * length;
 170                 fields.add(new Field(type, offset, length));
 171                 return offset;
 172         }
 173 
 174         /**
 175          * Sets the offset of the next field.
 176          * <p>The offset must be greater or equal to the accumulated extent.
 177          * @param offset offset of the next field
 178          * @return this object in order to allow adding fields in a chained expression
 179          */
 180         public final Struct setOffset(int offset)
 181         {
 182                 if(datatype != null)
 183                         throw new AssertionError("The struct data type was committed.");
 184 
 185                 if(offset < extent)
 186                 {
 187                         throw new IllegalArgumentException(
 188                                         "The offset must be greater or equal to the accumulated extent.");
 189                 }
 190 
 191                 extent = offset;
 192                 return this;
 193         }
 194 
 195         /**
 196          * Adds a byte field to this struct.
 197          * @return Offset of the new field.
 198          */
 199         public final int addByte()
 200         {
 201                 return addByte(1);
 202         }
 203 
 204         /**
 205          * Adds a byte array to this struct.
 206          * @param length Length of the array.
 207          * @return Offset of the new field.
 208          */
 209         public final int addByte(int length)
 210         {
 211                 return addField(MPI.BYTE, 1, length);
 212         }
 213 
 214         /**
 215          * Adds a char field to this struct.
 216          * @return Offset of the new field.
 217          */
 218         public final int addChar()
 219         {
 220                 return addChar(1);
 221         }
 222 
 223         /**
 224          * Adds a char array to this struct.
 225          * @param length Length of the array.
 226          * @return Offset of the new field.
 227          */
 228         public final int addChar(int length)
 229         {
 230                 return addField(MPI.CHAR, 2, length);
 231         }
 232 
 233         /**
 234          * Adds a short field to this struct.
 235          * @return Offset of the new field.
 236          */
 237         public final int addShort()
 238         {
 239                 return addShort(1);
 240         }
 241 
 242         /**
 243          * Adds a short array to this struct.
 244          * @param length Length of the array.
 245          * @return Offset of the new field.
 246          */
 247         public final int addShort(int length)
 248         {
 249                 return addField(MPI.SHORT, 2, length);
 250         }
 251 
 252         /**
 253          * Adds an int field to this struct.
 254          * @return Offset of the new field.
 255          */
 256         public final int addInt()
 257         {
 258                 return addInt(1);
 259         }
 260 
 261         /**
 262          * Adds an int array to this struct.
 263          * @param length Length of the array.
 264          * @return Offset of the new field.
 265          */
 266         public final int addInt(int length)
 267         {
 268                 return addField(MPI.INT, 4, length);
 269         }
 270 
 271         /**
 272          * Adds a long field to this struct.
 273          * @return Offset of the new field.
 274          */
 275         public final int addLong()
 276         {
 277                 return addLong(1);
 278         }
 279 
 280         /**
 281          * Adds a long array to this struct.
 282          * @param length Length of the array.
 283          * @return Offset of the new field.
 284          */
 285         public final int addLong(int length)
 286         {
 287                 return addField(MPI.LONG, 8, length);
 288         }
 289 
 290         /**
 291          * Adds a float field to this struct.
 292          * @return Offset of the new field.
 293          */
 294         public final int addFloat()
 295         {
 296                 return addFloat(1);
 297         }
 298 
 299         /**
 300          * Adds a float array to this struct.
 301          * @param length Length of the array.
 302          * @return Offset of the new field.
 303          */
 304         public final int addFloat(int length)
 305         {
 306                 return addField(MPI.FLOAT, 4, length);
 307         }
 308 
 309         /**
 310          * Adds a double field to this struct.
 311          * @return Offset of the new field.
 312          */
 313         public final int addDouble()
 314         {
 315                 return addDouble(1);
 316         }
 317 
 318         /**
 319          * Adds a double array to this struct.
 320          * @param length Length of the array.
 321          * @return Offset of the new field.
 322          */
 323         public final int addDouble(int length)
 324         {
 325                 return addField(MPI.DOUBLE, 8, length);
 326         }
 327 
 328         /**
 329          * Adds a struct field to this struct.
 330          * @param struct Type of the field.
 331          * @return Offset of the new field.
 332          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 333          */
 334         public final int addStruct(Struct struct) throws MPIException
 335         {
 336                 return addStruct(struct, 1);
 337         }
 338 
 339         /**
 340          * Adds an array of structs to this struct.
 341          * @param struct Type of the array.
 342          * @param length Length of the array.
 343          * @return Offset of the new field.
 344          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 345          */
 346         public final int addStruct(Struct struct, int length) throws MPIException
 347         {
 348                 struct.commit();
 349                 return addField(struct, struct.extent, length);
 350         }
 351 
 352         /**
 353          * Adds a field of the specified data type.
 354          * @param type Data type.
 355          * @return Offset of the new field.
 356          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 357          */
 358         public final int addData(Datatype type) throws MPIException
 359         {
 360                 return addData(type, 1);
 361         }
 362 
 363         /**
 364          * Adds an array of the specified data type.
 365          * @param type Data type.
 366          * @param length Length of the array.
 367          * @return Offset of the new field.
 368          * @throws MPIException Signals that an MPI exception of some sort has occurred.
 369          */
 370         public final int addData(Datatype type, int length) throws MPIException
 371         {
 372                 return addField(type, type.getExtent() * type.baseSize, length);
 373         }
 374 
 375         private boolean validType(int fieldOffset, int index, Datatype type)
 376         {
 377                 int i = Arrays.binarySearch(offsets, fieldOffset);
 378                 return index >= 0 && index < lengths[i] && type == types[i];
 379         }
 380 
 381         private static class Field
 382         {
 383                 private Object type;
 384                 private int offset, length;
 385 
 386                 private Field(Object type, int offset, int length)
 387                 {
 388                         this.type   = type;
 389                         this.offset = offset;
 390                         this.length = length;
 391                 }
 392 
 393         } // Field
 394 
 395         /**
 396          * Base class for reading/writing data in a struct stored in a byte buffer.
 397          */
 398         public abstract class Data
 399         {
 400                 private ByteBuffer buffer;
 401                 private int offset;
 402 
 403                 /**
 404                  * Gets the buffer where this struct data is stored.
 405                  * <p>The buffer can be used in {@code send}/{@code recv} operations.
 406                  * @return Buffer where the struct data is stored.
 407                  */
 408                 public final ByteBuffer getBuffer()
 409                 {
 410                         return offset == 0 ? buffer : MPI.slice(buffer, offset);
 411                 }
 412 
 413                 /**
 414                  * Gets the byte value of a field.
 415                  * @param field Offset of the field.
 416                  * @return Byte value.
 417                  */
 418                 protected final byte getByte(int field)
 419                 {
 420                         assert validType(field, 0, MPI.BYTE) : typeMismatch;
 421                         return buffer.get(offset + field);
 422                 }
 423 
 424                 /**
 425                  * Gets the byte value at the specified position of a byte array.
 426                  * @param field Offset of the byte array.
 427                  * @param index Index of the byte in the array.
 428                  * @return Byte value.
 429                  */
 430                 protected final byte getByte(int field, int index)
 431                 {
 432                         assert validType(field, index, MPI.BYTE) : typeMismatch;
 433                         return buffer.get(offset + field + index);
 434                 }
 435 
 436                 /**
 437                  * Puts a byte value in a field.
 438                  * @param field Offset of the field.
 439                  * @param v     Byte value.
 440                  */
 441                 protected final void putByte(int field, byte v)
 442                 {
 443                         assert validType(field, 0, MPI.BYTE) : typeMismatch;
 444                         buffer.put(offset + field, v);
 445                 }
 446 
 447                 /**
 448                  * Puts a byte value at the specified position of a byte array.
 449                  * @param field Offset of the byte array.
 450                  * @param index Index of the byte in the array.
 451                  * @param v     Byte value.
 452                  */
 453                 protected final void putByte(int field, int index, byte v)
 454                 {
 455                         assert validType(field, index, MPI.BYTE) : typeMismatch;
 456                         buffer.put(offset + field + index, v);
 457                 }
 458 
 459                 /**
 460                  * Gets the char value of a field.
 461                  * @param field Offset of the field.
 462                  * @return Char value.
 463                  */
 464                 protected final char getChar(int field)
 465                 {
 466                         assert validType(field, 0, MPI.CHAR) : typeMismatch;
 467                         return buffer.getChar(offset + field);
 468                 }
 469 
 470                 /**
 471                  * Gets the char value at the specified position of a char array.
 472                  * @param field Offset of the char array.
 473                  * @param index Index of the char in the array.
 474                  * @return Char value.
 475                  */
 476                 protected final char getChar(int field, int index)
 477                 {
 478                         assert validType(field, index, MPI.CHAR) : typeMismatch;
 479                         return buffer.getChar(offset + field + index * 2);
 480                 }
 481 
 482                 /**
 483                  * Puts a char value in a field.
 484                  * @param field Offset of the field.
 485                  * @param v     Char value.
 486                  */
 487                 protected final void putChar(int field, char v)
 488                 {
 489                         assert validType(field, 0, MPI.CHAR) : typeMismatch;
 490                         buffer.putChar(offset + field, v);
 491                 }
 492 
 493                 /**
 494                  * Puts a char value at the specified position of a char array.
 495                  * @param field Offset of the char array.
 496                  * @param index Index of the char in the array.
 497                  * @param v     Char value.
 498                  */
 499                 protected final void putChar(int field, int index, char v)
 500                 {
 501                         assert validType(field, index, MPI.CHAR) : typeMismatch;
 502                         buffer.putChar(offset + field + index * 2, v);
 503                 }
 504 
 505                 /**
 506                  * Gets the short value of a field.
 507                  * @param field Offset of the field.
 508                  * @return Short value.
 509                  */
 510                 protected final short getShort(int field)
 511                 {
 512                         assert validType(field, 0, MPI.SHORT) : typeMismatch;
 513                         return buffer.getShort(offset + field);
 514                 }
 515 
 516                 /**
 517                  * Gets the short value at the specified position of a short array.
 518                  * @param field Offset of the short array.
 519                  * @param index Index of the short in the array.
 520                  * @return Short value.
 521                  */
 522                 protected final short getShort(int field, int index)
 523                 {
 524                         assert validType(field, index, MPI.SHORT) : typeMismatch;
 525                         return buffer.getShort(offset + field + index * 2);
 526                 }
 527 
 528                 /**
 529                  * Puts a short value in a field.
 530                  * @param field Offset of the field.
 531                  * @param v     Short value.
 532                  */
 533                 protected final void putShort(int field, short v)
 534                 {
 535                         assert validType(field, 0, MPI.SHORT) : typeMismatch;
 536                         buffer.putShort(offset + field, v);
 537                 }
 538 
 539                 /**
 540                  * Puts a short value at the specified position of a short array.
 541                  * @param field Offset of the short array.
 542                  * @param index Index of the short in the array.
 543                  * @param v     Short value.
 544                  */
 545                 protected final void putShort(int field, int index, short v)
 546                 {
 547                         assert validType(field, index, MPI.SHORT) : typeMismatch;
 548                         buffer.putShort(offset + field + index * 2, v);
 549                 }
 550 
 551                 /**
 552                  * Gets the int value of a field.
 553                  * @param field Offset of the field.
 554                  * @return Int value.
 555                  */
 556                 protected final int getInt(int field)
 557                 {
 558                         assert validType(field, 0, MPI.INT) : typeMismatch;
 559                         return buffer.getInt(offset + field);
 560                 }
 561 
 562                 /**
 563                  * Gets the int value at the specified position of an int array.
 564                  * @param field Offset of the int array.
 565                  * @param index Index of the int in the array.
 566                  * @return Int value.
 567                  */
 568                 protected final int getInt(int field, int index)
 569                 {
 570                         assert validType(field, index, MPI.INT) : typeMismatch;
 571                         return buffer.getInt(offset + field + index * 4);
 572                 }
 573 
 574                 /**
 575                  * Puts an int value in a field.
 576                  * @param field Offset of the field.
 577                  * @param v     Int value.
 578                  */
 579                 protected final void putInt(int field, int v)
 580                 {
 581                         assert validType(field, 0, MPI.INT) : typeMismatch;
 582                         buffer.putInt(offset + field, v);
 583                 }
 584 
 585                 /**
 586                  * Puts an int value at the specified position of an int array.
 587                  * @param field Offset of the int array.
 588                  * @param index Index of the int in the array.
 589                  * @param v     Int value.
 590                  */
 591                 protected final void putInt(int field, int index, int v)
 592                 {
 593                         assert validType(field, index, MPI.INT) : typeMismatch;
 594                         buffer.putInt(offset + field + index * 4, v);
 595                 }
 596 
 597                 /**
 598                  * Gets the long value of a field.
 599                  * @param field Offset of the field.
 600                  * @return Long value.
 601                  */
 602                 protected final long getLong(int field)
 603                 {
 604                         assert validType(field, 0, MPI.LONG) : typeMismatch;
 605                         return buffer.getLong(offset + field);
 606                 }
 607 
 608                 /**
 609                  * Gets the long value at the specified position of a long array.
 610                  * @param field Offset of the long array.
 611                  * @param index Index of the long in the array.
 612                  * @return Long value.
 613                  */
 614                 protected final long getLong(int field, int index)
 615                 {
 616                         assert validType(field, index, MPI.LONG) : typeMismatch;
 617                         return buffer.getLong(offset + field + index * 8);
 618                 }
 619 
 620                 /**
 621                  * Puts a long value in a field.
 622                  * @param field Offset of the field.
 623                  * @param v     Long value.
 624                  */
 625                 protected final void putLong(int field, long v)
 626                 {
 627                         assert validType(field, 0, MPI.LONG) : typeMismatch;
 628                         buffer.putLong(offset + field, v);
 629                 }
 630 
 631                 /**
 632                  * Puts a long value at the specified position of a long array.
 633                  * @param field Offset of the long array.
 634                  * @param index Index of the long in the array.
 635                  * @param v     Long value.
 636                  */
 637                 protected final void putLong(int field, int index, long v)
 638                 {
 639                         assert validType(field, index, MPI.LONG) : typeMismatch;
 640                         buffer.putLong(offset + field + index * 8, v);
 641                 }
 642 
 643                 /**
 644                  * Gets the float value of a field.
 645                  * @param field Offset of the field.
 646                  * @return Float value.
 647                  */
 648                 protected final float getFloat(int field)
 649                 {
 650                         assert validType(field, 0, MPI.FLOAT) : typeMismatch;
 651                         return buffer.getFloat(offset + field);
 652                 }
 653 
 654                 /**
 655                  * Gets the float value at the specified position of a float array.
 656                  * @param field Offset of the float array.
 657                  * @param index Index of the float in the array.
 658                  * @return Float value.
 659                  */
 660                 protected final float getFloat(int field, int index)
 661                 {
 662                         assert validType(field, index, MPI.FLOAT) : typeMismatch;
 663                         return buffer.getFloat(offset + field + index * 4);
 664                 }
 665 
 666                 /**
 667                  * Puts a float value in a field.
 668                  * @param field Offset of the field.
 669                  * @param v     Float value.
 670                  */
 671                 protected final void putFloat(int field, float v)
 672                 {
 673                         assert validType(field, 0, MPI.FLOAT) : typeMismatch;
 674                         buffer.putFloat(offset + field, v);
 675                 }
 676 
 677                 /**
 678                  * Puts a float value at the specified position of a float array.
 679                  * @param field Offset of the float array.
 680                  * @param index Index of the float in the array.
 681                  * @param v     Float value.
 682                  */
 683                 protected final void putFloat(int field, int index, float v)
 684                 {
 685                         assert validType(field, index, MPI.FLOAT) : typeMismatch;
 686                         buffer.putFloat(offset + field + index * 4, v);
 687                 }
 688 
 689                 /**
 690                  * Gets the double value of a field.
 691                  * @param field Offset of the field.
 692                  * @return Double value.
 693                  */
 694                 protected final double getDouble(int field)
 695                 {
 696                         assert validType(field, 0, MPI.DOUBLE) : typeMismatch;
 697                         return buffer.getDouble(offset + field);
 698                 }
 699 
 700                 /**
 701                  * Gets the double value at the specified position of a double array.
 702                  * @param field Offset of the double array.
 703                  * @param index Index of the double in the array.
 704                  * @return Double value.
 705                  */
 706                 protected final double getDouble(int field, int index)
 707                 {
 708                         assert validType(field, index, MPI.DOUBLE) : typeMismatch;
 709                         return buffer.getDouble(offset + field + index * 8);
 710                 }
 711 
 712                 /**
 713                  * Puts a double value in a field.
 714                  * @param field Offset of the field.
 715                  * @param v     Double value.
 716                  */
 717                 protected final void putDouble(int field, double v)
 718                 {
 719                         assert validType(field, 0, MPI.DOUBLE) : typeMismatch;
 720                         buffer.putDouble(offset + field, v);
 721                 }
 722 
 723                 /**
 724                  * Puts a double value at the specified position of a double array.
 725                  * @param field Offset of the double array.
 726                  * @param index Index of the double in the array.
 727                  * @param v     Double value.
 728                  */
 729                 protected final void putDouble(int field, int index, double v)
 730                 {
 731                         assert validType(field, index, MPI.DOUBLE) : typeMismatch;
 732                         buffer.putDouble(offset + field + index * 8, v);
 733                 }
 734 
 735                 @SuppressWarnings("javadoc")
 736                 /**
 737                  * Gets the struct data of a field.
 738                  * @param struct Struct type.
 739                  * @param field  Offset of the field.
 740                  * @return Struct data.
 741                  */
 742                 protected final <S extends Struct, D extends Struct.Data>
 743                 D getData(S struct, int field)
 744                 {
 745                         Struct s = (Struct)struct;
 746                         assert validType(field, 0, s.datatype) : typeMismatch;
 747                         return s.newData(buffer, offset + field);
 748                 }
 749 
 750                 @SuppressWarnings("javadoc")
 751                 /**
 752                  * Gets the struct data at the specified position of a struct array.
 753                  * @param struct Struct type.
 754                  * @param field  Offset of the struct array.
 755                  * @param index  Index of the struct in the array.
 756                  * @return Struct data.
 757                  */
 758                 protected final <S extends Struct, D extends Struct.Data>
 759                 D getData(S struct, int field, int index)
 760                 {
 761                         Struct s = (Struct)struct;
 762                         assert validType(field, index, s.datatype) : typeMismatch;
 763                         return s.newData(buffer, offset + field + index * s.extent);
 764                 }
 765 
 766                 /**
 767                  * Gets the buffer of a field.
 768                  * <p>The buffer can be used in {@code send}/{@code recv} operations.
 769                  * @param type  Data type of the buffer.
 770                  * @param field Offset of the field.
 771                  * @return Buffer object.
 772                  */
 773                 protected final ByteBuffer getBuffer(Datatype type, int field)
 774                 {
 775                         assert validType(field, 0, type) : typeMismatch;
 776                         int position = offset + field;
 777                         return position == 0 ? buffer : MPI.slice(buffer, position);
 778                 }
 779 
 780                 /**
 781                  * Gets the buffer data at the specified position of a buffer array.
 782                  * <p>The buffer can be used in {@code send}/{@code recv} operations.
 783                  * @param type  Data type of the buffer.
 784                  * @param field Offset of the buffer array.
 785                  * @param index Index of the buffer in the array.
 786                  * @return Buffer object.
 787                  * @throws MPIException Signals that an MPI exception of some sort has occurred.
 788                  */
 789                 protected final ByteBuffer getBuffer(Datatype type, int field, int index)
 790                                 throws MPIException
 791                 {
 792                         assert validType(field, index, type) : typeMismatch;
 793 
 794                         int extent   = type.getExtent() * type.baseSize,
 795                                         position = offset + field + index * extent;
 796 
 797                         return position == 0 ? buffer : MPI.slice(buffer, position);
 798                 }
 799 
 800         } // Data
 801 
 802 } // Struct