Home | History | Annotate | Download | only in stubs
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 // Author: kenton (at) google.com (Kenton Varda)
     32 //
     33 // Deals with the fact that hash_map is not defined everywhere.
     34 
     35 #ifndef GOOGLE_PROTOBUF_STUBS_HASH_H__
     36 #define GOOGLE_PROTOBUF_STUBS_HASH_H__
     37 
     38 #include <string.h>
     39 #include <google/protobuf/stubs/common.h>
     40 
     41 #define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1
     42 #define GOOGLE_PROTOBUF_HAVE_HASH_SET 1
     43 
     44 // Android
     45 #if defined(__ANDROID__)
     46 # undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
     47 # undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
     48 
     49 // Use C++11 unordered_{map|set} if available.
     50 #elif ((_LIBCPP_STD_VER >= 11) || \
     51       (((__cplusplus >= 201103L) || defined(__GXX_EXPERIMENTAL_CXX0X)) && \
     52       (__GLIBCXX__ > 20090421)))
     53 # define GOOGLE_PROTOBUF_HAS_CXX11_HASH
     54 
     55 // For XCode >= 4.6:  the compiler is clang with libc++.
     56 // For earlier XCode version: the compiler is gcc-4.2.1 with libstdc++.
     57 // libc++ provides <unordered_map> and friends even in non C++11 mode,
     58 // and it does not provide the tr1 library. Therefore the following macro
     59 // checks against this special case.
     60 // Note that we should not test the __APPLE_CC__ version number or the
     61 // __clang__ macro, since the new compiler can still use -stdlib=libstdc++, in
     62 // which case <unordered_map> is not compilable without -std=c++11
     63 #elif defined(__APPLE_CC__)
     64 # if __GNUC__ >= 4
     65 #  define GOOGLE_PROTOBUF_HAS_TR1
     66 # else
     67 // Not tested for gcc < 4... These setting can compile under 4.2.1 though.
     68 #  define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx
     69 #  include <ext/hash_map>
     70 #  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
     71 #  include <ext/hash_set>
     72 #  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
     73 # endif
     74 
     75 // Version checks for gcc.
     76 #elif defined(__GNUC__)
     77 // For GCC 4.x+, use tr1::unordered_map/set; otherwise, follow the
     78 // instructions from:
     79 // https://gcc.gnu.org/onlinedocs/libstdc++/manual/backwards.html
     80 # if __GNUC__ >= 4
     81 #  define GOOGLE_PROTOBUF_HAS_TR1
     82 # elif __GNUC__ >= 3
     83 #  include <backward/hash_map>
     84 #  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
     85 #  include <backward/hash_set>
     86 #  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
     87 #  if __GNUC__ == 3 && __GNUC_MINOR__ == 0
     88 #   define GOOGLE_PROTOBUF_HASH_NAMESPACE std       // GCC 3.0
     89 #  else
     90 #   define GOOGLE_PROTOBUF_HASH_NAMESPACE __gnu_cxx // GCC 3.1 and later
     91 #  endif
     92 # else
     93 #  define GOOGLE_PROTOBUF_HASH_NAMESPACE
     94 #  include <hash_map>
     95 #  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
     96 #  include <hash_set>
     97 #  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
     98 # endif
     99 
    100 // Version checks for MSC.
    101 // Apparently Microsoft decided to move hash_map *back* to the std namespace in
    102 // MSVC 2010:
    103 // http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx
    104 // And.. they are moved back to stdext in MSVC 2013 (haven't checked 2012). That
    105 // said, use unordered_map for MSVC 2010 and beyond is our safest bet.
    106 #elif defined(_MSC_VER)
    107 # if _MSC_VER >= 1600  // Since Visual Studio 2010
    108 #  define GOOGLE_PROTOBUF_HAS_CXX11_HASH
    109 #  define GOOGLE_PROTOBUF_HASH_COMPARE std::hash_compare
    110 # elif _MSC_VER >= 1500  // Since Visual Studio 2008
    111 #  define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext
    112 #  include <hash_map>
    113 #  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
    114 #  include <hash_set>
    115 #  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
    116 #  define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare
    117 #  define GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
    118 # elif _MSC_VER >= 1310
    119 #  define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext
    120 #  include <hash_map>
    121 #  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
    122 #  include <hash_set>
    123 #  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
    124 #  define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare
    125 # else
    126 #  define GOOGLE_PROTOBUF_HASH_NAMESPACE std
    127 #  include <hash_map>
    128 #  define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map
    129 #  include <hash_set>
    130 #  define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set
    131 #  define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare
    132 # endif
    133 
    134 // **ADD NEW COMPILERS SUPPORT HERE.**
    135 // For other compilers, undefine the macro and fallback to use std::map, in
    136 // google/protobuf/stubs/hash.h
    137 #else
    138 # undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
    139 # undef GOOGLE_PROTOBUF_HAVE_HASH_SET
    140 #endif
    141 
    142 #if defined(GOOGLE_PROTOBUF_HAS_CXX11_HASH)
    143 # define GOOGLE_PROTOBUF_HASH_NAMESPACE std
    144 # include <unordered_map>
    145 # define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map
    146 # include <unordered_set>
    147 # define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set
    148 #elif defined(GOOGLE_PROTOBUF_HAS_TR1)
    149 # define GOOGLE_PROTOBUF_HASH_NAMESPACE std::tr1
    150 # include <tr1/unordered_map>
    151 # define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map
    152 # include <tr1/unordered_set>
    153 # define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set
    154 #endif
    155 
    156 # define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \
    157   namespace google {                                      \
    158   namespace protobuf {
    159 # define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }}
    160 
    161 #undef GOOGLE_PROTOBUF_HAS_CXX11_HASH
    162 #undef GOOGLE_PROTOBUF_HAS_TR1
    163 
    164 #if defined(GOOGLE_PROTOBUF_HAVE_HASH_MAP) && \
    165     defined(GOOGLE_PROTOBUF_HAVE_HASH_SET)
    166 #else
    167 #define GOOGLE_PROTOBUF_MISSING_HASH
    168 #include <map>
    169 #include <set>
    170 #endif
    171 
    172 namespace google {
    173 namespace protobuf {
    174 
    175 #ifdef GOOGLE_PROTOBUF_MISSING_HASH
    176 #undef GOOGLE_PROTOBUF_MISSING_HASH
    177 
    178 // This system doesn't have hash_map or hash_set.  Emulate them using map and
    179 // set.
    180 
    181 // Make hash<T> be the same as less<T>.  Note that everywhere where custom
    182 // hash functions are defined in the protobuf code, they are also defined such
    183 // that they can be used as "less" functions, which is required by MSVC anyway.
    184 template <typename Key>
    185 struct hash {
    186   // Dummy, just to make derivative hash functions compile.
    187   int operator()(const Key& key) {
    188     GOOGLE_LOG(FATAL) << "Should never be called.";
    189     return 0;
    190   }
    191 
    192   inline bool operator()(const Key& a, const Key& b) const {
    193     return a < b;
    194   }
    195 };
    196 
    197 // Make sure char* is compared by value.
    198 template <>
    199 struct hash<const char*> {
    200   // Dummy, just to make derivative hash functions compile.
    201   int operator()(const char* key) {
    202     GOOGLE_LOG(FATAL) << "Should never be called.";
    203     return 0;
    204   }
    205 
    206   inline bool operator()(const char* a, const char* b) const {
    207     return strcmp(a, b) < 0;
    208   }
    209 };
    210 
    211 template <typename Key, typename Data,
    212           typename HashFcn = hash<Key>,
    213           typename EqualKey = std::equal_to<Key>,
    214           typename Alloc = std::allocator< std::pair<const Key, Data> > >
    215 class hash_map : public std::map<Key, Data, HashFcn, Alloc> {
    216   typedef std::map<Key, Data, HashFcn, Alloc> BaseClass;
    217 
    218  public:
    219   hash_map(int a = 0, const HashFcn& b = HashFcn(),
    220            const EqualKey& c = EqualKey(),
    221            const Alloc& d = Alloc()) : BaseClass(b, d) {}
    222 
    223   HashFcn hash_function() const { return HashFcn(); }
    224 };
    225 
    226 template <typename Key,
    227           typename HashFcn = hash<Key>,
    228           typename EqualKey = std::equal_to<Key> >
    229 class hash_set : public std::set<Key, HashFcn> {
    230  public:
    231   hash_set(int = 0) {}
    232 
    233   HashFcn hash_function() const { return HashFcn(); }
    234 };
    235 
    236 #elif defined(_MSC_VER) && !defined(_STLPORT_VERSION)
    237 
    238 template <typename Key>
    239 struct hash : public GOOGLE_PROTOBUF_HASH_COMPARE<Key> {
    240 };
    241 
    242 // MSVC's hash_compare<const char*> hashes based on the string contents but
    243 // compares based on the string pointer.  WTF?
    244 class CstringLess {
    245  public:
    246   inline bool operator()(const char* a, const char* b) const {
    247     return strcmp(a, b) < 0;
    248   }
    249 };
    250 
    251 template <>
    252 struct hash<const char*>
    253     : public GOOGLE_PROTOBUF_HASH_COMPARE<const char*, CstringLess> {};
    254 
    255 #ifdef GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
    256 
    257 template <typename Key, typename HashFcn, typename EqualKey>
    258 struct InternalHashCompare : public GOOGLE_PROTOBUF_HASH_COMPARE<Key> {
    259   InternalHashCompare() {}
    260   InternalHashCompare(HashFcn hashfcn, EqualKey equalkey)
    261       : hashfcn_(hashfcn), equalkey_(equalkey) {}
    262   size_t operator()(const Key& key) const { return hashfcn_(key); }
    263   bool operator()(const Key& key1, const Key& key2) const {
    264     return !equalkey_(key1, key2);
    265   }
    266   HashFcn hashfcn_;
    267   EqualKey equalkey_;
    268 };
    269 
    270 template <typename Key, typename Data,
    271           typename HashFcn = hash<Key>,
    272           typename EqualKey = std::equal_to<Key>,
    273           typename Alloc = std::allocator< std::pair<const Key, Data> > >
    274 class hash_map
    275     : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
    276           Key, Data, InternalHashCompare<Key, HashFcn, EqualKey>, Alloc> {
    277   typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
    278       Key, Data, InternalHashCompare<Key, HashFcn, EqualKey>, Alloc> BaseClass;
    279 
    280  public:
    281   hash_map(int a = 0, const HashFcn& b = HashFcn(),
    282            const EqualKey& c = EqualKey(), const Alloc& d = Alloc())
    283       : BaseClass(InternalHashCompare<Key, HashFcn, EqualKey>(b, c), d) {}
    284 
    285   HashFcn hash_function() const { return HashFcn(); }
    286 };
    287 
    288 template <typename Key, typename HashFcn = hash<Key>,
    289           typename EqualKey = std::equal_to<Key> >
    290 class hash_set
    291     : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
    292           Key, InternalHashCompare<Key, HashFcn, EqualKey> > {
    293  public:
    294   hash_set(int = 0) {}
    295 
    296   HashFcn hash_function() const { return HashFcn(); }
    297 };
    298 
    299 #else  // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
    300 
    301 template <typename Key, typename Data,
    302           typename HashFcn = hash<Key>,
    303           typename EqualKey = std::equal_to<Key>,
    304           typename Alloc = std::allocator< std::pair<const Key, Data> > >
    305 class hash_map
    306     : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
    307           Key, Data, HashFcn, EqualKey, Alloc> {
    308   typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
    309       Key, Data, HashFcn, EqualKey, Alloc> BaseClass;
    310 
    311  public:
    312   hash_map(int a = 0, const HashFcn& b = HashFcn(),
    313            const EqualKey& c = EqualKey(),
    314            const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {}
    315 
    316   HashFcn hash_function() const { return HashFcn(); }
    317 };
    318 
    319 template <typename Key, typename HashFcn = hash<Key>,
    320           typename EqualKey = std::equal_to<Key> >
    321 class hash_set
    322     : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
    323           Key, HashFcn, EqualKey> {
    324  public:
    325   hash_set(int = 0) {}
    326 
    327   HashFcn hash_function() const { return HashFcn(); }
    328 };
    329 #endif  // GOOGLE_PROTOBUF_CONTAINERS_NEED_HASH_COMPARE
    330 
    331 #else  // defined(_MSC_VER) && !defined(_STLPORT_VERSION)
    332 
    333 template <typename Key>
    334 struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash<Key> {
    335 };
    336 
    337 template <typename Key>
    338 struct hash<const Key*> {
    339   inline size_t operator()(const Key* key) const {
    340     return reinterpret_cast<size_t>(key);
    341   }
    342 };
    343 
    344 // Unlike the old SGI version, the TR1 "hash" does not special-case char*.  So,
    345 // we go ahead and provide our own implementation.
    346 template <>
    347 struct hash<const char*> {
    348   inline size_t operator()(const char* str) const {
    349     size_t result = 0;
    350     for (; *str != '\0'; str++) {
    351       result = 5 * result + *str;
    352     }
    353     return result;
    354   }
    355 };
    356 
    357 template<>
    358 struct hash<bool> {
    359   size_t operator()(bool x) const {
    360     return static_cast<size_t>(x);
    361   }
    362 };
    363 
    364 template <typename Key, typename Data,
    365           typename HashFcn = hash<Key>,
    366           typename EqualKey = std::equal_to<Key>,
    367           typename Alloc = std::allocator< std::pair<const Key, Data> > >
    368 class hash_map
    369     : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
    370           Key, Data, HashFcn, EqualKey, Alloc> {
    371   typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
    372       Key, Data, HashFcn, EqualKey, Alloc> BaseClass;
    373 
    374  public:
    375   hash_map(int a = 0, const HashFcn& b = HashFcn(),
    376            const EqualKey& c = EqualKey(),
    377            const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {}
    378 
    379   HashFcn hash_function() const { return HashFcn(); }
    380 };
    381 
    382 template <typename Key, typename HashFcn = hash<Key>,
    383           typename EqualKey = std::equal_to<Key> >
    384 class hash_set
    385     : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
    386           Key, HashFcn, EqualKey> {
    387  public:
    388   hash_set(int = 0) {}
    389 
    390   HashFcn hash_function() const { return HashFcn(); }
    391 };
    392 
    393 #endif  // !GOOGLE_PROTOBUF_MISSING_HASH
    394 
    395 template <>
    396 struct hash<string> {
    397   inline size_t operator()(const string& key) const {
    398     return hash<const char*>()(key.c_str());
    399   }
    400 
    401   static const size_t bucket_size = 4;
    402   static const size_t min_buckets = 8;
    403   inline bool operator()(const string& a, const string& b) const {
    404     return a < b;
    405   }
    406 };
    407 
    408 template <typename First, typename Second>
    409 struct hash<pair<First, Second> > {
    410   inline size_t operator()(const pair<First, Second>& key) const {
    411     size_t first_hash = hash<First>()(key.first);
    412     size_t second_hash = hash<Second>()(key.second);
    413 
    414     // FIXME(kenton):  What is the best way to compute this hash?  I have
    415     // no idea!  This seems a bit better than an XOR.
    416     return first_hash * ((1 << 16) - 1) + second_hash;
    417   }
    418 
    419   static const size_t bucket_size = 4;
    420   static const size_t min_buckets = 8;
    421   inline bool operator()(const pair<First, Second>& a,
    422                            const pair<First, Second>& b) const {
    423     return a < b;
    424   }
    425 };
    426 
    427 // Used by GCC/SGI STL only.  (Why isn't this provided by the standard
    428 // library?  :( )
    429 struct streq {
    430   inline bool operator()(const char* a, const char* b) const {
    431     return strcmp(a, b) == 0;
    432   }
    433 };
    434 
    435 }  // namespace protobuf
    436 }  // namespace google
    437 
    438 #endif  // GOOGLE_PROTOBUF_STUBS_HASH_H__
    439