1 // @HEADER
2 // ***********************************************************************
3 //
4 //                    Teuchos: Common Tools Package
5 //                 Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef TEUCHOS_DETAILS_MPITYPETRAITS_HPP
43 #define TEUCHOS_DETAILS_MPITYPETRAITS_HPP
44 
45 /// \file Teuchos_Details_MpiTypeTraits.hpp
46 /// \brief Declaration of Teuchos::Details::MpiTypeTraits (only if
47 ///   building with MPI)
48 
49 #include "Teuchos_config.h"
50 
51 #ifdef HAVE_TEUCHOS_MPI
52 
53 #include <mpi.h>
54 #include <complex>
55 
56 namespace Teuchos {
57 namespace Details {
58 
59 /// \class MpiTypeTraits
60 /// \brief Traits class mapping from type T to its MPI_Datatype
61 /// \tparam T The type being sent or received.  T must be default
62 ///   constructible.  It must also be either one of C++'s built-in
63 ///   types (like \c int or \c double), or a struct or "struct-like"
64 ///   type like <tt>std::complex<double</tt>, for which sizeof(T)
65 ///   correctly conveys the amount of data to send or receive.
66 template<class T>
67 class MpiTypeTraits {
68 public:
69   /// \brief Whether this class is specialized for T.
70   ///
71   /// If this class has <i>not</i> been specialized for T, then the
72   /// return value of getType (either the one-argument or
73   /// zero-argument version) is undefined.
74   static const bool isSpecialized = false;
75 
76   /// \brief Whether you must call MPI_Type_free on the return value
77   ///   of getType (both versions) after use.
78   ///
79   /// It is illegal to call MPI_Type_free on a built-in MPI_Datatype.
80   /// It is required to call MPI_Type_free on a non-built-in ("custom"
81   /// or "derived") MPI_Datatype after use.  In the latter case, the
82   /// MPI standard says that you may call MPI_Type_free on an
83   /// MPI_Datatype as soon as you are done using the MPI_Datatype in
84   /// your code on that process, even if there is an outstanding
85   /// asynchronous operation on that process that uses the
86   /// MPI_Datatype.
87   ///
88   /// This applies to both the one-argument and the zero-argument
89   /// version of getType.  If the return value of one needs freeing,
90   /// so must the return value of the other one.  (IMPLEMENTERS:
91   /// Please make note of the previous sentence.)
92   static const bool needsFree = false;
93 
94   /// \brief The MPI_Datatype corresponding to the given T instance.
95   ///
96   /// For more generality, this method requires passing in a T
97   /// instance.  The method may or may not ignore this instance,
98   /// depending on the type T.  The reason for passing in an instance
99   /// is that some MPI_Datatype constructors, e.g., MPI_Type_struct,
100   /// need actual offsets of the fields in an actual instance of T, in
101   /// order to construct the MPI_Datatype safely and portably.  If T
102   /// has no default constructor, we have no way of doing so without
103   /// accepting a T instance.
104   ///
105   /// Specializations for T that do not need an instance of T in order
106   /// to construct the MPI_Datatype safely, may overload this method
107   /// not to require an instance of T.  However, all specializations
108   /// must retain the overload that takes a T instance.  This lets
109   /// users invoke this method in the same way for all types T.
getType(const T &)110   static MPI_Datatype getType (const T&) {
111     // In this default implementation, isSpecialized == false, so the
112     // return value of getType is undefined.  We have to return
113     // something, so we return the predefined "invalid" MPI_Datatype,
114     // MPI_DATATYPE_NULL.  Specializations of getType need to redefine
115     // this method to return something other than MPI_DATATYPE_NULL.
116     return MPI_DATATYPE_NULL;
117   }
118 };
119 
120 //
121 // Specializations of MpiTypeTraits.
122 //
123 
124 /// \brief Specialization for T = char.
125 ///
126 /// This requires MPI 1.2.
127 template<>
128 class MpiTypeTraits<char> {
129 public:
130   //! Whether this is a defined specialization of MpiTypeTraits (it is).
131   static const bool isSpecialized = true;
132 
133   /// \brief Whether you must call MPI_Type_free on the return value
134   ///   of getType (both versions) after use.
135   static const bool needsFree = false;
136 
137   //! MPI_Datatype corresponding to the given T instance.
getType(const char &)138   static MPI_Datatype getType (const char&) {
139     return MPI_CHAR;
140   }
141 
142   //! MPI_Datatype corresponding to the type T.
getType()143   static MPI_Datatype getType () {
144     return MPI_CHAR;
145   }
146 };
147 
148 /// \brief Specialization for T = unsigned char.
149 ///
150 /// This requires MPI 1.2.
151 template<>
152 class MpiTypeTraits<unsigned char> {
153 public:
154   //! Whether this is a defined specialization of MpiTypeTraits (it is).
155   static const bool isSpecialized = true;
156 
157   /// \brief Whether you must call MPI_Type_free on the return value
158   ///   of getType (both versions) after use.
159   static const bool needsFree = false;
160 
161   //! MPI_Datatype corresponding to the given T instance.
getType(const unsigned char &)162   static MPI_Datatype getType (const unsigned char&) {
163     return MPI_UNSIGNED_CHAR;
164   }
165 
166   //! MPI_Datatype corresponding to the type T.
getType()167   static MPI_Datatype getType () {
168     return MPI_UNSIGNED_CHAR;
169   }
170 };
171 
172 #if MPI_VERSION >= 2
173 /// \brief Specialization for T = signed char.
174 ///
175 /// This requires MPI 2.0.
176 template<>
177 class MpiTypeTraits<signed char> {
178 public:
179   //! Whether this is a defined specialization of MpiTypeTraits (it is).
180   static const bool isSpecialized = true;
181 
182   /// \brief Whether you must call MPI_Type_free on the return value
183   ///   of getType (both versions) after use.
184   static const bool needsFree = false;
185 
186   //! MPI_Datatype corresponding to the given T instance.
getType(const signed char &)187   static MPI_Datatype getType (const signed char&) {
188     return MPI_SIGNED_CHAR;
189   }
190 
191   //! MPI_Datatype corresponding to the type T.
getType()192   static MPI_Datatype getType () {
193     return MPI_SIGNED_CHAR;
194   }
195 };
196 #endif // MPI_VERSION >= 2
197 
198 // mfh 09 Nov 2016: amb reports on 11 Nov 2014: "I am disabling these
199 // specializations for now. MPI_C_DOUBLE_COMPLEX is causing a problem
200 // in some builds. This code was effectively turned on only yesterday
201 // (10 Nov 2014) when TEUCHOS_HAVE_COMPLEX was corrected to be
202 // HAVE_TEUCHOS_COMPLEX, so evidently there are no users of these
203 // specializations."
204 //
205 // mfh 14 Nov 2016: my work-around for the above issue, is
206 // conservatively to assume that I need MPI_VERSION >= 3 for these
207 // types to exist.  If I don't have MPI_VERSION >= 3, I create custom
208 // MPI_Datatype for these types.
209 
210 namespace Impl {
211 
212 /// \brief Struct for use in computeStdComplexMpiDatatype (see below).
213 ///
214 /// The actual real and imaginary fields in std::complex<T> are
215 /// private.  While the instance methods real() and imag() return
216 /// references to those fields, it's not legal to take the addresses
217 /// of the return values of those methods ("invalid initialization"
218 /// errors, etc.).  Thus, we construct another struct here which
219 /// should have exactly the same layout, and use it in the function
220 /// below.
221 template<class T>
222 struct MyComplex {
223   T re;
224   T im;
225 };
226 
227 /// \brief Compute MPI_Datatype for instance of std::complex<T>.
228 ///
229 /// This function assumes the following:
230 /// <ul>
231 /// <li> <tt> MpiTypeTraits<T>::isSpecialized </tt> </li>
232 /// <li> <tt> ! MpiTypeTraits<T>::needsFree </tt>
233 /// <li> std::complex<T> has the same layout as
234 ///      <tt>struct { T re; T im; };</tt> </li>
235 /// <li> Every instance of T has the same MPI_Datatype </li>
236 /// </ul>
237 template<class T>
238 MPI_Datatype
computeStdComplexMpiDatatype(const std::complex<T> & z)239 computeStdComplexMpiDatatype (const std::complex<T>& z)
240 {
241 #ifdef HAVE_TEUCHOSCORE_CXX11
242   static_assert (MpiTypeTraits<T>::isSpecialized, "This function only "
243                  "works if MpiTypeTraits<T>::isSpecialized.");
244   static_assert (! MpiTypeTraits<T>::needsFree, "This function requires "
245                  "! MpiTypeTraits<T>::needsFree, since otherwise it would "
246                  "leak memory.");
247 #endif // HAVE_TEUCHOSCORE_CXX11
248 
249   // We assume here that every instance of T has the same
250   // MPI_Datatype, i.e., has the same binary representation.
251   MPI_Datatype innerDatatype = MpiTypeTraits<T>::getType (z.real ());
252   MPI_Datatype outerDatatype; // return value
253 
254   // If std::complex<T> has the same layout as T[2], then we can use a
255   // contiguous derived MPI_Datatype.  This is likely the only code
256   // path that will execute.  Contiguous types are likely more
257   // efficient for MPI to execute, and almost certainly more efficient
258   // for MPI to set up.
259   if (sizeof (std::complex<T>) == 2 * sizeof (T)) {
260     (void) MPI_Type_contiguous (2, innerDatatype, &outerDatatype);
261   }
262   else { // must use the general struct approach
263     // I borrowed and adapted the code below from the MPICH
264     // documentation:
265     //
266     // www.mpich.org/static/docs/v3.1/www3/MPI_Type_struct.html
267     int blockLengths[3];
268     MPI_Aint arrayOfDisplacements[3];
269     MPI_Datatype arrayOfTypes[3];
270 
271 #ifdef HAVE_TEUCHOSCORE_CXX11
272     // See documentation of MyComplex (above) for explanation.
273     static_assert (sizeof (MyComplex<T>) == sizeof (std::complex<T>),
274                    "Attempt to construct a struct of the same size and layout "
275                    "as std::complex<T> failed.");
276 #endif // HAVE_TEUCHOSCORE_CXX11
277     MyComplex<T> z2;
278 
279     // First entry in the struct.
280     blockLengths[0] = 1;
281     // Normally, &z2.re would equal &z2, but I'll be conservative and
282     // actually compute the offset, even though it's probably just 0.
283     //
284     // Need the cast to prevent the compiler complaining about
285     // subtracting addresses of different types.
286     arrayOfDisplacements[0] = reinterpret_cast<char*>(&z2.re) - reinterpret_cast<char*>(&z2);
287     arrayOfTypes[0] = innerDatatype;
288 
289     // Second entry in the struct.
290     blockLengths[1] = 1;
291     arrayOfDisplacements[1] = reinterpret_cast<char*>(&z2.im) - reinterpret_cast<char*>(&z2);
292     arrayOfTypes[1] = innerDatatype;
293 
294 #if MPI_VERSION < 2
295     // Upper bound of the struct.
296     blockLengths[2] = 1;
297     arrayOfDisplacements[2] = sizeof (MyComplex<T>);
298     arrayOfTypes[2] = MPI_UB; // "upper bound type"; signals end of struct
299 #endif // MPI_VERSION < 2
300 
301     // Define the MPI_Datatype.
302 #if MPI_VERSION < 2
303     (void) MPI_Type_struct (3, blockLengths, arrayOfDisplacements,
304                             arrayOfTypes, &outerDatatype);
305 #else
306     // Don't include the upper bound with MPI_Type_create_struct.
307     (void) MPI_Type_create_struct (2, blockLengths, arrayOfDisplacements,
308                                    arrayOfTypes, &outerDatatype);
309 #endif // MPI_VERSION < 2
310   }
311 
312   MPI_Type_commit (&outerDatatype);
313   return outerDatatype;
314 }
315 
316 } // namespace Impl
317 
318 
319 //! Specialization of MpiTypeTraits for std::complex<double>.
320 template<>
321 class MpiTypeTraits< std::complex<double> > {
322 private:
323 #if MPI_VERSION >= 3
324   static const bool hasMpi3 = true;
325 #else
326   static const bool hasMpi3 = false;
327 #endif // MPI_VERSION >= 3
328 
329 public:
330   //! Whether this is a defined specialization of MpiTypeTraits (it is).
331   static const bool isSpecialized = true;
332 
333   /// \brief Whether you must call MPI_Type_free on the return value
334   ///   of getType (both versions) after use.
335   static const bool needsFree = ! hasMpi3;
336 
337   //! MPI_Datatype corresponding to the given std::complex<double> instance.
getType(const std::complex<double> & z)338   static MPI_Datatype getType (const std::complex<double>& z) {
339     if (hasMpi3) {
340 #if MPI_VERSION >= 3
341       return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
342 #else
343       return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
344 #endif // MPI_VERSION >= 3
345     }
346     else { // ! hasMpi3
347       return Impl::computeStdComplexMpiDatatype<double> (z);
348     }
349   }
350 
351   //! MPI_Datatype corresponding to all std::complex<double> instances.
getType()352   static MPI_Datatype getType () {
353     if (hasMpi3) {
354 #if MPI_VERSION >= 3
355       return MPI_C_DOUBLE_COMPLEX; // requires MPI 2.?
356 #else
357       return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
358 #endif // MPI_VERSION >= 3
359     }
360     else { // ! hasMpi3
361       // Values are arbitrary.  The function just looks at the address
362       // offsets of the class fields, not their contents.
363       std::complex<double> z (3.0, 4.0);
364       return Impl::computeStdComplexMpiDatatype<double> (z);
365     }
366   }
367 };
368 
369 template<>
370 class MpiTypeTraits< std::complex<float> > {
371 private:
372 #if MPI_VERSION >= 3
373   static const bool hasMpi3 = true;
374 #else
375   static const bool hasMpi3 = false;
376 #endif // MPI_VERSION >= 3
377 
378 public:
379   //! Whether this is a defined specialization of MpiTypeTraits (it is).
380   static const bool isSpecialized = true;
381 
382   /// \brief Whether you must call MPI_Type_free on the return value
383   ///   of getType (both versions) after use.
384   static const bool needsFree = ! hasMpi3;
385 
386   //! MPI_Datatype corresponding to the given std::complex<float> instance.
getType(const std::complex<float> & z)387   static MPI_Datatype getType (const std::complex<float>& z) {
388     if (hasMpi3) {
389 #if MPI_VERSION >= 3
390       return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
391 #else
392       return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
393 #endif // MPI_VERSION >= 3
394     }
395     else { // ! hasMpi3
396       return Impl::computeStdComplexMpiDatatype<float> (z);
397     }
398   }
399 
400   //! MPI_Datatype corresponding to all std::complex<float> instances.
getType()401   static MPI_Datatype getType () {
402     if (hasMpi3) {
403 #if MPI_VERSION >= 3
404       return MPI_C_FLOAT_COMPLEX; // requires MPI 2.?
405 #else
406       return MPI_DATATYPE_NULL; // FIXME (mfh 17 Nov 2016) Better to throw?
407 #endif // MPI_VERSION >= 3
408     }
409     else { // ! hasMpi3
410       // Values are arbitrary.  The function just looks at the address
411       // offsets of the class fields, not their contents.
412       std::complex<float> z (3.0, 4.0);
413       return Impl::computeStdComplexMpiDatatype<float> (z);
414     }
415   }
416 };
417 
418 //! Specialization for T = double.
419 template<>
420 class MpiTypeTraits<double> {
421 public:
422   //! Whether this is a defined specialization of MpiTypeTraits (it is).
423   static const bool isSpecialized = true;
424 
425   /// \brief Whether you must call MPI_Type_free on the return value
426   ///   of getType (both versions) after use.
427   static const bool needsFree = false;
428 
429   //! MPI_Datatype corresponding to the given T instance.
getType(const double &)430   static MPI_Datatype getType (const double&) {
431     return MPI_DOUBLE;
432   }
433 
434   //! MPI_Datatype corresponding to the type T.
getType()435   static MPI_Datatype getType () {
436     return MPI_DOUBLE;
437   }
438 };
439 
440 //! Specialization for T = float.
441 template<>
442 class MpiTypeTraits<float> {
443 public:
444   //! Whether this is a defined specialization of MpiTypeTraits (it is).
445   static const bool isSpecialized = true;
446 
447   /// \brief Whether you must call MPI_Type_free on the return value
448   ///   of getType (both versions) after use.
449   static const bool needsFree = false;
450 
451   //! MPI_Datatype corresponding to the given T instance.
getType(const float &)452   static MPI_Datatype getType (const float&) {
453     return MPI_FLOAT;
454   }
455 
456   //! MPI_Datatype corresponding to the type T.
getType()457   static MPI_Datatype getType () {
458     return MPI_FLOAT;
459   }
460 };
461 
462 //! Specialization for T = long long.
463 template<>
464 class MpiTypeTraits<long long> {
465 public:
466   //! Whether this is a defined specialization of MpiTypeTraits (it is).
467   static const bool isSpecialized = true;
468 
469   /// \brief Whether you must call MPI_Type_free on the return value
470   ///   of getType (both versions) after use.
471   static const bool needsFree = false;
472 
473   //! MPI_Datatype corresponding to the given T instance.
getType(const long long &)474   static MPI_Datatype getType (const long long&) {
475     return MPI_LONG_LONG; // synonym for MPI_LONG_LONG_INT in MPI 2.2
476   }
477 
478   //! MPI_Datatype corresponding to the type T.
getType()479   static MPI_Datatype getType () {
480     return MPI_LONG_LONG;
481   }
482 };
483 
484 
485 #if MPI_VERSION >= 2
486 /// \brief Specialization for T = long long.
487 ///
488 /// This requires MPI 2.0.
489 template<>
490 class MpiTypeTraits<unsigned long long> {
491 public:
492   //! Whether this is a defined specialization of MpiTypeTraits (it is).
493   static const bool isSpecialized = true;
494 
495   /// \brief Whether you must call MPI_Type_free on the return value
496   ///   of getType (both versions) after use.
497   static const bool needsFree = false;
498 
499   //! MPI_Datatype corresponding to the given T instance.
getType(const unsigned long long &)500   static MPI_Datatype getType (const unsigned long long&) {
501     return MPI_UNSIGNED_LONG_LONG;
502   }
503 
504   //! MPI_Datatype corresponding to the type T.
getType()505   static MPI_Datatype getType () {
506     return MPI_UNSIGNED_LONG_LONG;
507   }
508 };
509 #endif // MPI_VERSION >= 2
510 
511 //! Specialization for T = long.
512 template<>
513 class MpiTypeTraits<long> {
514 public:
515   //! Whether this is a defined specialization of MpiTypeTraits (it is).
516   static const bool isSpecialized = true;
517 
518   /// \brief Whether you must call MPI_Type_free on the return value
519   ///   of getType (both versions) after use.
520   static const bool needsFree = false;
521 
522   //! MPI_Datatype corresponding to the given T instance.
getType(const long &)523   static MPI_Datatype getType (const long&) {
524     return MPI_LONG;
525   }
526 
527   //! MPI_Datatype corresponding to the type T.
getType()528   static MPI_Datatype getType () {
529     return MPI_LONG;
530   }
531 };
532 
533 //! Specialization for T = unsigned long.
534 template<>
535 class MpiTypeTraits<unsigned long> {
536 public:
537   //! Whether this is a defined specialization of MpiTypeTraits (it is).
538   static const bool isSpecialized = true;
539 
540   /// \brief Whether you must call MPI_Type_free on the return value
541   ///   of getType (both versions) after use.
542   static const bool needsFree = false;
543 
544   //! MPI_Datatype corresponding to the given T instance.
getType(const unsigned long &)545   static MPI_Datatype getType (const unsigned long&) {
546     return MPI_UNSIGNED_LONG;
547   }
548 
549   //! MPI_Datatype corresponding to the type T.
getType()550   static MPI_Datatype getType () {
551     return MPI_UNSIGNED_LONG;
552   }
553 };
554 
555 //! Specialization for T = int.
556 template<>
557 class MpiTypeTraits<int> {
558 public:
559   //! Whether this is a defined specialization of MpiTypeTraits (it is).
560   static const bool isSpecialized = true;
561 
562   /// \brief Whether you must call MPI_Type_free on the return value
563   ///   of getType (both versions) after use.
564   static const bool needsFree = false;
565 
566   //! MPI_Datatype corresponding to the given T instance.
getType(const int &)567   static MPI_Datatype getType (const int&) {
568     return MPI_INT;
569   }
570 
571   //! MPI_Datatype corresponding to the type T.
getType()572   static MPI_Datatype getType () {
573     return MPI_INT;
574   }
575 };
576 
577 //! Specialization for T = unsigned int.
578 template<>
579 class MpiTypeTraits<unsigned int> {
580 public:
581   //! Whether this is a defined specialization of MpiTypeTraits (it is).
582   static const bool isSpecialized = true;
583 
584   /// \brief Whether you must call MPI_Type_free on the return value
585   ///   of getType (both versions) after use.
586   static const bool needsFree = false;
587 
588   //! MPI_Datatype corresponding to the given T instance.
getType(const unsigned int &)589   static MPI_Datatype getType (const unsigned int&) {
590     return MPI_UNSIGNED;
591   }
592 
593   //! MPI_Datatype corresponding to the type T.
getType()594   static MPI_Datatype getType () {
595     return MPI_UNSIGNED;
596   }
597 };
598 
599 //! Specialization for T = short.
600 template<>
601 class MpiTypeTraits<short> {
602 public:
603   //! Whether this is a defined specialization of MpiTypeTraits (it is).
604   static const bool isSpecialized = true;
605 
606   /// \brief Whether you must call MPI_Type_free on the return value
607   ///   of getType (both versions) after use.
608   static const bool needsFree = false;
609 
610   //! MPI_Datatype corresponding to the given T instance.
getType(const short &)611   static MPI_Datatype getType (const short&) {
612     return MPI_SHORT;
613   }
614 
615   //! MPI_Datatype corresponding to the type T.
getType()616   static MPI_Datatype getType () {
617     return MPI_SHORT;
618   }
619 };
620 
621 //! Specialization for T = unsigned short.
622 template<>
623 class MpiTypeTraits<unsigned short> {
624 public:
625   //! Whether this is a defined specialization of MpiTypeTraits (it is).
626   static const bool isSpecialized = true;
627 
628   /// \brief Whether you must call MPI_Type_free on the return value
629   ///   of getType (both versions) after use.
630   static const bool needsFree = false;
631 
632   //! MPI_Datatype corresponding to the given T instance.
getType(const unsigned short &)633   static MPI_Datatype getType (const unsigned short&) {
634     return MPI_UNSIGNED_SHORT;
635   }
636 
637   //! MPI_Datatype corresponding to the type T.
getType()638   static MPI_Datatype getType () {
639     return MPI_UNSIGNED_SHORT;
640   }
641 };
642 
643 } // namespace Details
644 } // namespace Teuchos
645 
646 #endif // HAVE_TEUCHOS_MPI
647 
648 #endif // TEUCHOS_DETAILS_MPITYPETRAITS_HPP
649 
650