Tpetra Matrix/Vector Services Version of the Day
Tpetra_Details_FixedHashTable_def.hpp
00001 /*
00002 // @HEADER
00003 // ***********************************************************************
00004 //
00005 //          Tpetra: Templated Linear Algebra Services Package
00006 //                 Copyright (2008) Sandia Corporation
00007 //
00008 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00009 // the U.S. Government retains certain rights in this software.
00010 //
00011 // Redistribution and use in source and binary forms, with or without
00012 // modification, are permitted provided that the following conditions are
00013 // met:
00014 //
00015 // 1. Redistributions of source code must retain the above copyright
00016 // notice, this list of conditions and the following disclaimer.
00017 //
00018 // 2. Redistributions in binary form must reproduce the above copyright
00019 // notice, this list of conditions and the following disclaimer in the
00020 // documentation and/or other materials provided with the distribution.
00021 //
00022 // 3. Neither the name of the Corporation nor the names of the
00023 // contributors may be used to endorse or promote products derived from
00024 // this software without specific prior written permission.
00025 //
00026 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00027 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00029 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00030 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00031 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00032 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00033 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00034 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00035 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00036 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037 //
00038 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00039 //
00040 // ************************************************************************
00041 // @HEADER
00042 */
00043 
00044 #ifndef TPETRA_DETAILS_FIXEDHASHTABLE_DEF_HPP
00045 #define TPETRA_DETAILS_FIXEDHASHTABLE_DEF_HPP
00046 
00047 #ifdef DOXYGEN_USE_ONLY
00048   #include "Tpetra_Details_FixedHashTable_decl.hpp"
00049 #endif
00050 
00051 #include <Teuchos_as.hpp>
00052 #include "MurmurHash3.hpp"
00053 
00054 
00055 namespace Tpetra {
00056 namespace Details {
00057 
00058 template<typename KeyType, typename ValueType>
00059 int FixedHashTable<KeyType, ValueType>::hashFunc (const KeyType key) const {
00060 #ifdef TPETRA_USE_MURMUR_HASH
00061   uint32_t k;
00062   MurmurHash3_x86_32 ((void *) &key, sizeof (KeyType), 1, (void *) &k);
00063   return (int) (k % size_);
00064 #else
00065   // We are using Epetra's hash function by default, as we have
00066   // observed that it is much faster than the Murmur hash
00067   // function. However, this is not a good hash function for general
00068   // sets of keys.  For our typical use case, this is good.  Use
00069   // Murmur hash if the maps are sparse.
00070   const unsigned int seed = (2654435761U);
00071 
00072 #ifdef HAVE_TPETRA_DEBUG
00073   TEUCHOS_TEST_FOR_EXCEPTION(
00074     size_ == 0, std::logic_error, "Tpetra::Details::FixedHashTable::hashFunc: "
00075     "size_ == 0.  Please report this bug to the Tpetra developers.");
00076 #endif // HAVE_TPETRA_DEBUG
00077 
00078   const int intkey = (int) ((key & 0x000000007fffffffLL) +
00079                             ((key & 0x7fffffff80000000LL) >> 31));
00080   return (int) ((seed ^ intkey) % size_);
00081 #endif
00082 }
00083 
00084 template<typename KeyType, typename ValueType>
00085 int
00086 FixedHashTable<KeyType, ValueType>::getRecommendedSize (const int size)
00087 {
00088   // A large list of prime numbers.
00089   // Based on a recommendation by Andres Valloud in hash forums.
00090   //  There are only enough primes here so that between any number N and 2*N,
00091   //  there will be at least about 8 to choose from (except the first 10).
00092   //  This is a balance between a small list of primes, and getting a
00093   //  collection size that doesn't waste too much space.  In addition,
00094   //  the primes in this table were chosen so that they do not divide
00095   //  256^k +- a, for 1<=k<=8, and -32<=a<=32.  This is so that
00096   //  using them as a modulo will not have a tendency to just throw away
00097   //  the most significant bits of the object's hash.  The primes (except the
00098   //  first ten) or not close to any power of two to avoid aliasing
00099   //  between hash functions based on bit manipulation and the moduli.
00100   int primes [ ] = {
00101     3, 7, 13, 23, 53, 97, 193, 389, 769, 1543,
00102     2237, 2423, 2617, 2797, 2999, 3167, 3359, 3539,
00103     3727, 3911, 4441 , 4787 , 5119 , 5471 , 5801 , 6143 , 6521 , 6827
00104     , 7177 , 7517 , 7853 , 8887 , 9587 , 10243 , 10937 , 11617 , 12289
00105     , 12967 , 13649 , 14341 , 15013 , 15727
00106     , 17749 , 19121 , 20479 , 21859 , 23209 , 24593 , 25939 , 27329
00107     , 28669 , 30047 , 31469 , 35507 , 38231 , 40961 , 43711 , 46439
00108     , 49157 , 51893 , 54617 , 57347 , 60077 , 62801 , 70583 , 75619
00109     , 80669 , 85703 , 90749 , 95783 , 100823 , 105871 , 110909 , 115963
00110     , 120997 , 126031 , 141157 , 151237 , 161323 , 171401 , 181499 , 191579
00111     , 201653 , 211741 , 221813 , 231893 , 241979 , 252079
00112     , 282311 , 302483 , 322649 , 342803 , 362969 , 383143 , 403301 , 423457
00113     , 443629 , 463787 , 483953 , 504121 , 564617 , 604949 , 645313 , 685609
00114     , 725939 , 766273 , 806609 , 846931 , 887261 , 927587 , 967919 , 1008239
00115     , 1123477 , 1198397 , 1273289 , 1348177 , 1423067 , 1497983 , 1572869
00116     , 1647761 , 1722667 , 1797581 , 1872461 , 1947359 , 2022253
00117     , 2246953 , 2396759 , 2546543 , 2696363 , 2846161 , 2995973 , 3145739
00118     , 3295541 , 3445357 , 3595117 , 3744941 , 3894707 , 4044503
00119     , 4493921 , 4793501 , 5093089 , 5392679 , 5692279 , 5991883 , 6291469
00120     , 6591059 , 6890641 , 7190243 , 7489829 , 7789447 , 8089033
00121     , 8987807 , 9586981 , 10186177 , 10785371 , 11384539 , 11983729
00122     , 12582917 , 13182109 , 13781291 , 14380469 , 14979667 , 15578861
00123     , 16178053 , 17895707 , 19014187 , 20132683 , 21251141 , 22369661
00124     , 23488103 , 24606583 , 25725083 , 26843549 , 27962027 , 29080529
00125     , 30198989 , 31317469 , 32435981 , 35791397 , 38028379 , 40265327
00126     , 42502283 , 44739259 , 46976221 , 49213237 , 51450131 , 53687099
00127     , 55924061 , 58161041 , 60397993 , 62634959 , 64871921
00128     , 71582857 , 76056727 , 80530643 , 85004567 , 89478503 , 93952427
00129     , 98426347 , 102900263 , 107374217 , 111848111 , 116322053 , 120795971
00130     , 125269877 , 129743807 , 143165587 , 152113427 , 161061283 , 170009141
00131     , 178956983 , 187904819 , 196852693 , 205800547 , 214748383 , 223696237
00132     , 232644089 , 241591943 , 250539763 , 259487603 , 268435399 };
00133 
00134   int hsize = primes[220] ;
00135   for (int i = 0; i < 221; ++i) {
00136     if (size <= primes[i]) {
00137       hsize = primes[i];
00138       break;
00139     }
00140   }
00141   return hsize;
00142 }
00143 
00144 template<typename KeyType, typename ValueType>
00145 FixedHashTable<KeyType, ValueType>::
00146 FixedHashTable (const ArrayView<const KeyType>& keys) :
00147   size_ (0),
00148   rawPtr_ (NULL),
00149   rawVal_ (NULL),
00150   hasDuplicateKeys_ (false) // to revise in init()
00151 {
00152   init (keys, Teuchos::as<ValueType> (0));
00153 }
00154 
00155 template<typename KeyType, typename ValueType>
00156 FixedHashTable<KeyType, ValueType>::
00157 FixedHashTable (const ArrayView<const KeyType>& keys,
00158                 const ValueType startingValue) :
00159   size_ (0),
00160   rawPtr_ (NULL),
00161   rawVal_ (NULL),
00162   hasDuplicateKeys_ (false) // to revise in init()
00163 {
00164   init (keys, startingValue);
00165 }
00166 
00167 template<typename KeyType, typename ValueType>
00168 FixedHashTable<KeyType, ValueType>::
00169 FixedHashTable (const ArrayView<const KeyType>& keys,
00170                 const ArrayView<const ValueType>& vals) :
00171   size_ (0),
00172   rawPtr_ (NULL),
00173   rawVal_ (NULL),
00174   hasDuplicateKeys_ (false) // to revise in init()
00175 {
00176   init (keys, vals);
00177 }
00178 
00179 template<typename KeyType, typename ValueType>
00180 void
00181 FixedHashTable<KeyType, ValueType>::
00182 init (const ArrayView<const KeyType>& keys,
00183       const ValueType startingValue)
00184 {
00185   using Teuchos::arcp;
00186   using Teuchos::arcp_const_cast;
00187   using Teuchos::ArrayRCP;
00188   using Teuchos::as;
00189 
00190   const size_type numKeys = keys.size ();
00191   const size_type size = getRecommendedSize (as<int> (numKeys));
00192 #ifdef HAVE_TPETRA_DEBUG
00193   TEUCHOS_TEST_FOR_EXCEPTION(
00194     size == 0 && numKeys != 0, std::logic_error,
00195     "Tpetra::Details::FixedHashTable constructor: "
00196     "getRecommendedSize(" << numKeys << ") returned zero, "
00197     "even though the number of keys " << numKeys << " is nonzero.  "
00198     "Please report this bug to the Tpetra developers.");
00199 #endif // HAVE_TPETRA_DEBUG
00200 
00201   // We have to set the size_ internal state before calling the hash
00202   // function, since the hash function uses it.
00203   size_ = as<KeyType> (size);
00204 
00205   ArrayRCP<size_type> ptr (size + 1, 0);
00206   // The constructor that takes just a size argument automatically
00207   // fills the data.  We don't need to waste time filling it here
00208   // because we will do so below.  The try/catch block isn't strictly
00209   // necessary; we could just give "new std::pair<...> [numKeys]" to
00210   // the ArrayRCP constructor, since no other arguments of the
00211   // constructor might throw before entering the constructor.
00212   ArrayRCP<std::pair<KeyType, ValueType> > val;
00213   std::pair<KeyType, ValueType>* rawVal = NULL;
00214   try {
00215     rawVal = new std::pair<KeyType, ValueType> [numKeys];
00216     val = arcp<std::pair<KeyType, ValueType> > (rawVal, 0, numKeys, true);
00217   } catch (...) {
00218     if (rawVal != NULL) {
00219       delete [] rawVal;
00220     }
00221     throw;
00222   }
00223 
00224   // Compute number of entries in each hash table position.
00225   for (size_type k = 0; k < numKeys; ++k) {
00226     const int hashVal = hashFunc (keys[k]);
00227     // Shift over one, so that counts[j] = ptr[j+1].  See below.
00228     ++ptr[hashVal+1];
00229 
00230     if (ptr[hashVal+1] > 1) {
00231       hasDuplicateKeys_ = true;
00232     }
00233   }
00234 
00235   // Compute row offsets via prefix sum:
00236   //
00237   // ptr[i+1] = \sum_{j=0}^{i} counts[j].
00238   //
00239   // Thus, ptr[i+1] - ptr[i] = counts[i], so that ptr[i+1] = ptr[i] +
00240   // counts[i].  If we stored counts[i] in ptr[i+1] on input, then the
00241   // formula is ptr[i+1] += ptr[i].
00242   for (size_type i = 0; i < size; ++i) {
00243     ptr[i+1] += ptr[i];
00244   }
00245   //ptr[0] = 0; // We've already done this when initializing ptr above.
00246 
00247   // curRowStart[i] is the offset of the next element in row i.
00248   ArrayRCP<size_type> curRowStart (size, 0);
00249 
00250   // Fill in the hash table.
00251   for (size_type k = 0; k < numKeys; ++k) {
00252     const KeyType key = keys[k];
00253     const ValueType theVal = startingValue + as<ValueType> (k);
00254     const int hashVal = hashFunc (key);
00255 
00256     const size_type offset = curRowStart[hashVal];
00257     const size_type curPos = ptr[hashVal] + offset;
00258 
00259     val[curPos].first = key;
00260     val[curPos].second = theVal;
00261     ++curRowStart[hashVal];
00262   }
00263 
00264   // "Commit" the computed arrays.
00265   ptr_ = arcp_const_cast<const size_type> (ptr);
00266 
00267   // FIXME (mfh 25 Apr 2013) arcp_const_cast on val_ and
00268   // val_.getRawPtr() both cause a hang with MPI for some reason.  Not
00269   // sure what's going on.  Anyway, calling val.release(), recreating
00270   // val_ by hand, and using the released raw pointer as rawVal_,
00271   // seems to fix the problem.
00272 
00273   //val_ = arcp_const_cast<const std::pair<KeyType, ValueType> > (val);
00274   const std::pair<KeyType, ValueType>* valRaw = val.release ();
00275   val_ = ArrayRCP<const std::pair<KeyType, ValueType> > (valRaw, 0, numKeys, true);
00276   //val_ = arcp<const std::pair<KeyType, ValueType> > (valRaw, 0, numKeys, true);
00277   rawPtr_ = ptr_.getRawPtr ();
00278   //  rawVal_ = val_.getRawPtr ();
00279   rawVal_ = valRaw;
00280 }
00281 
00282 
00283 template<typename KeyType, typename ValueType>
00284 void
00285 FixedHashTable<KeyType, ValueType>::
00286 init (const ArrayView<const KeyType>& keys,
00287       const ArrayView<const ValueType>& vals)
00288 {
00289   using Teuchos::arcp;
00290   using Teuchos::arcp_const_cast;
00291   using Teuchos::ArrayRCP;
00292   using Teuchos::as;
00293 
00294   const size_type numKeys = keys.size ();
00295   const size_type size = getRecommendedSize (as<int> (numKeys));
00296 #ifdef HAVE_TPETRA_DEBUG
00297   TEUCHOS_TEST_FOR_EXCEPTION(
00298     size == 0 && numKeys != 0, std::logic_error,
00299     "Tpetra::Details::FixedHashTable constructor: "
00300     "getRecommendedSize(" << numKeys << ") returned zero, "
00301     "even though the number of keys " << numKeys << " is nonzero.  "
00302     "Please report this bug to the Tpetra developers.");
00303 #endif // HAVE_TPETRA_DEBUG
00304 
00305   // We have to set the size_ internal state before calling the hash
00306   // function, since the hash function uses it.
00307   size_ = as<KeyType> (size);
00308 
00309   ArrayRCP<size_type> ptr (size + 1, 0);
00310   // The constructor that takes just a size argument automatically
00311   // fills the data.  We don't need to waste time filling it here
00312   // because we will do so below.  The try/catch block isn't strictly
00313   // necessary; we could just give "new std::pair<...> [numKeys]" to
00314   // the ArrayRCP constructor, since no other arguments of the
00315   // constructor might throw before entering the constructor.
00316   ArrayRCP<std::pair<KeyType, ValueType> > val;
00317   std::pair<KeyType, ValueType>* rawVal = NULL;
00318   try {
00319     rawVal = new std::pair<KeyType, ValueType> [numKeys];
00320     val = arcp<std::pair<KeyType, ValueType> > (rawVal, 0, numKeys, true);
00321   } catch (...) {
00322     if (rawVal != NULL) {
00323       delete [] rawVal;
00324     }
00325     throw;
00326   }
00327 
00328   // Compute number of entries in each hash table position.
00329   for (size_type k = 0; k < numKeys; ++k) {
00330     const int hashVal = hashFunc (keys[k]);
00331     // Shift over one, so that counts[j] = ptr[j+1].  See below.
00332     ++ptr[hashVal+1];
00333 
00334     if (ptr[hashVal+1] > 1) {
00335       hasDuplicateKeys_ = true;
00336     }
00337   }
00338 
00339   // Compute row offsets via prefix sum:
00340   //
00341   // ptr[i+1] = \sum_{j=0}^{i} counts[j].
00342   //
00343   // Thus, ptr[i+1] - ptr[i] = counts[i], so that ptr[i+1] = ptr[i] +
00344   // counts[i].  If we stored counts[i] in ptr[i+1] on input, then the
00345   // formula is ptr[i+1] += ptr[i].
00346   for (size_type i = 0; i < size; ++i) {
00347     ptr[i+1] += ptr[i];
00348   }
00349   //ptr[0] = 0; // We've already done this when initializing ptr above.
00350 
00351   // curRowStart[i] is the offset of the next element in row i.
00352   ArrayRCP<size_type> curRowStart (size, 0);
00353 
00354   // Fill in the hash table.
00355   for (size_type k = 0; k < numKeys; ++k) {
00356     const KeyType key = keys[k];
00357     const ValueType theVal = vals[k];
00358     const int hashVal = hashFunc (key);
00359 
00360     const size_type offset = curRowStart[hashVal];
00361     const size_type curPos = ptr[hashVal] + offset;
00362 
00363     val[curPos].first = key;
00364     val[curPos].second = theVal;
00365     ++curRowStart[hashVal];
00366   }
00367 
00368   // "Commit" the computed arrays.
00369   ptr_ = arcp_const_cast<const size_type> (ptr);
00370 
00371   // FIXME (mfh 25 Apr 2013) arcp_const_cast on val_ and
00372   // val_.getRawPtr() both cause a hang with MPI for some reason.  Not
00373   // sure what's going on.  Anyway, calling val.release(), recreating
00374   // val_ by hand, and using the released raw pointer as rawVal_,
00375   // seems to fix the problem.
00376 
00377   //val_ = arcp_const_cast<const std::pair<KeyType, ValueType> > (val);
00378   const std::pair<KeyType, ValueType>* valRaw = val.release ();
00379   val_ = ArrayRCP<const std::pair<KeyType, ValueType> > (valRaw, 0, numKeys, true);
00380   //val_ = arcp<const std::pair<KeyType, ValueType> > (valRaw, 0, numKeys, true);
00381   rawPtr_ = ptr_.getRawPtr ();
00382   //  rawVal_ = val_.getRawPtr ();
00383   rawVal_ = valRaw;
00384 }
00385 
00386 
00387 template<typename KeyType, typename ValueType>
00388 FixedHashTable<KeyType, ValueType>::
00389 FixedHashTable (const FixedHashTable & obj) :
00390   size_ (obj.size_),
00391   ptr_ (obj.ptr_),
00392   val_ (obj.val_),
00393   rawPtr_ (obj.rawPtr_),
00394   rawVal_ (obj.rawVal_),
00395   hasDuplicateKeys_ (obj.hasDuplicateKeys_)
00396 {}
00397 
00398 template<typename KeyType, typename ValueType>
00399 ValueType
00400 FixedHashTable<KeyType, ValueType>::
00401 get (const KeyType key) const
00402 {
00403   const int hashVal = hashFunc (key);
00404 #ifdef HAVE_TPETRA_DEBUG
00405 
00406   const size_type start = ptr_[hashVal];
00407   const size_type end = ptr_[hashVal+1];
00408   for (size_type k = start; k < end; ++k) {
00409     if (val_[k].first == key) {
00410       return val_[k].second;
00411     }
00412   }
00413 #else
00414   const size_type start = rawPtr_[hashVal];
00415   const size_type end = rawPtr_[hashVal+1];
00416   for (size_type k = start; k < end; ++k) {
00417     if (rawVal_[k].first == key) {
00418       return rawVal_[k].second;
00419     }
00420   }
00421 #endif // HAVE_TPETRA_DEBUG
00422   return Teuchos::OrdinalTraits<ValueType>::invalid ();
00423 }
00424 
00425 template <typename KeyType, typename ValueType>
00426 std::string FixedHashTable<KeyType, ValueType>::description() const {
00427   std::ostringstream oss;
00428   oss << "FixedHashTable<"
00429       << Teuchos::TypeNameTraits<KeyType>::name () << ","
00430       << Teuchos::TypeNameTraits<ValueType>::name () << ">: "
00431       << "{ numKeys: " << val_.size ()
00432       << ", tableSize: " << ptr_.size () << " }";
00433   return oss.str();
00434 }
00435 
00436 template <typename KeyType, typename ValueType>
00437 void
00438 FixedHashTable<KeyType, ValueType>::
00439 describe (Teuchos::FancyOStream &out,
00440           const Teuchos::EVerbosityLevel verbLevel) const
00441 {
00442   using std::endl;
00443   using std::setw;
00444   using Teuchos::OSTab;
00445   using Teuchos::rcpFromRef;
00446   using Teuchos::TypeNameTraits;
00447   using Teuchos::VERB_DEFAULT;
00448   using Teuchos::VERB_NONE;
00449   using Teuchos::VERB_LOW;
00450   using Teuchos::VERB_EXTREME;
00451 
00452   Teuchos::EVerbosityLevel vl = verbLevel;
00453   if (vl == VERB_DEFAULT) vl = VERB_LOW;
00454 
00455   if (vl == VERB_NONE) {
00456     // do nothing
00457   }
00458   else if (vl == VERB_LOW) {
00459     out << this->description() << endl;
00460   }
00461   else {  // MEDIUM, HIGH or EXTREME
00462     out << "FixedHashTable:" << endl;
00463     {
00464       OSTab tab1 (rcpFromRef (out));
00465 
00466       const std::string label = this->getObjectLabel ();
00467       if (label != "") {
00468         out << "label: " << label << endl;
00469       }
00470       out << "Template parameters:" << endl;
00471       {
00472         OSTab tab2 (rcpFromRef (out));
00473         out << "KeyType: " << TypeNameTraits<KeyType>::name () << endl
00474             << "ValueType: " << TypeNameTraits<ValueType>::name () << endl;
00475       }
00476 
00477       const size_type tableSize = size_;
00478       const size_type numKeys = val_.size ();
00479 
00480       out << "Table parameters:" << endl;
00481       {
00482         OSTab tab2 (rcpFromRef (out));
00483         out << "numKeys: " << numKeys << endl
00484             << "tableSize: " << tableSize << endl;
00485       }
00486 
00487       if (vl >= VERB_EXTREME) {
00488         out << "Contents: ";
00489         if (tableSize == 0 || numKeys == 0) {
00490           out << "[]" << endl;
00491         } else {
00492           out << "[ " << endl;
00493           {
00494             OSTab tab2 (rcpFromRef (out));
00495             for (size_type i = 0; i < tableSize; ++i) {
00496               OSTab tab3 (rcpFromRef (out));
00497               out << "[";
00498               for (size_type k = ptr_[i]; k < ptr_[i+1]; ++k) {
00499                 out << "(" << val_[k].first << "," << val_[k].second << ")";
00500                 if (k + 1 < ptr_[i+1]) {
00501                   out << ", ";
00502                 }
00503               }
00504               out << "]" << endl;
00505             } // for each table position i
00506           }
00507           out << "]" << endl;
00508         } // The table contains entries
00509       } // vl >= VERB_EXTREME
00510     }
00511     out << endl;
00512   } // if vl > VERB_LOW
00513 }
00514 
00515 } // namespace Details
00516 } // namespace Tpetra
00517 
00518 // Macro that explicitly instantiates FixedHashTable for the given local
00519 // ordinal (LO) and global ordinal (GO) types.  Note that FixedHashTable's
00520 // template parameters occur in the opposite order of most Tpetra
00521 // classes.  This is because FixedHashTable performs global-to-local
00522 // lookup, and the convention in templated C++ lookup tables (such as
00523 // std::map) is <KeyType, ValueType>.
00524 //
00525 // This macro must be explanded within the Tpetra::Details namespace.
00526 #define TPETRA_DETAILS_FIXEDHASHTABLE_INSTANT_DEFAULTNODE(LO,GO) \
00527   template class FixedHashTable< GO , LO >;                      \
00528 
00529 #endif // TPETRA_DETAILS_FIXEDHASHTABLE_DEF_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines