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