Brian Silverman | 9c614bc | 2016-02-15 20:20:02 -0500 | [diff] [blame^] | 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@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 | # undef GOOGLE_PROTOBUF_HAVE_HASH_MAP |
| 112 | # undef GOOGLE_PROTOBUF_HAVE_HASH_SET |
| 113 | # elif _MSC_VER >= 1310 |
| 114 | # define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext |
| 115 | # include <hash_map> |
| 116 | # define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map |
| 117 | # include <hash_set> |
| 118 | # define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set |
| 119 | # define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare |
| 120 | # else |
| 121 | # define GOOGLE_PROTOBUF_HASH_NAMESPACE std |
| 122 | # include <hash_map> |
| 123 | # define GOOGLE_PROTOBUF_HASH_MAP_CLASS hash_map |
| 124 | # include <hash_set> |
| 125 | # define GOOGLE_PROTOBUF_HASH_SET_CLASS hash_set |
| 126 | # define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare |
| 127 | # endif |
| 128 | |
| 129 | // **ADD NEW COMPILERS SUPPORT HERE.** |
| 130 | // For other compilers, undefine the macro and fallback to use std::map, in |
| 131 | // google/protobuf/stubs/hash.h |
| 132 | #else |
| 133 | # undef GOOGLE_PROTOBUF_HAVE_HASH_MAP |
| 134 | # undef GOOGLE_PROTOBUF_HAVE_HASH_SET |
| 135 | #endif |
| 136 | |
| 137 | #if defined(GOOGLE_PROTOBUF_HAS_CXX11_HASH) |
| 138 | # define GOOGLE_PROTOBUF_HASH_NAMESPACE std |
| 139 | # include <unordered_map> |
| 140 | # define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map |
| 141 | # include <unordered_set> |
| 142 | # define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set |
| 143 | #elif defined(GOOGLE_PROTOBUF_HAS_TR1) |
| 144 | # define GOOGLE_PROTOBUF_HASH_NAMESPACE std::tr1 |
| 145 | # include <tr1/unordered_map> |
| 146 | # define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map |
| 147 | # include <tr1/unordered_set> |
| 148 | # define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set |
| 149 | #endif |
| 150 | |
| 151 | # define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \ |
| 152 | namespace google { \ |
| 153 | namespace protobuf { |
| 154 | # define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }} |
| 155 | |
| 156 | #undef GOOGLE_PROTOBUF_HAS_CXX11_HASH |
| 157 | #undef GOOGLE_PROTOBUF_HAS_TR1 |
| 158 | |
| 159 | #if defined(GOOGLE_PROTOBUF_HAVE_HASH_MAP) && \ |
| 160 | defined(GOOGLE_PROTOBUF_HAVE_HASH_SET) |
| 161 | #else |
| 162 | #define GOOGLE_PROTOBUF_MISSING_HASH |
| 163 | #include <map> |
| 164 | #include <set> |
| 165 | #endif |
| 166 | |
| 167 | namespace google { |
| 168 | namespace protobuf { |
| 169 | |
| 170 | #ifdef GOOGLE_PROTOBUF_MISSING_HASH |
| 171 | #undef GOOGLE_PROTOBUF_MISSING_HASH |
| 172 | |
| 173 | // This system doesn't have hash_map or hash_set. Emulate them using map and |
| 174 | // set. |
| 175 | |
| 176 | // Make hash<T> be the same as less<T>. Note that everywhere where custom |
| 177 | // hash functions are defined in the protobuf code, they are also defined such |
| 178 | // that they can be used as "less" functions, which is required by MSVC anyway. |
| 179 | template <typename Key> |
| 180 | struct hash { |
| 181 | // Dummy, just to make derivative hash functions compile. |
| 182 | int operator()(const Key& key) { |
| 183 | GOOGLE_LOG(FATAL) << "Should never be called."; |
| 184 | return 0; |
| 185 | } |
| 186 | |
| 187 | inline bool operator()(const Key& a, const Key& b) const { |
| 188 | return a < b; |
| 189 | } |
| 190 | }; |
| 191 | |
| 192 | // Make sure char* is compared by value. |
| 193 | template <> |
| 194 | struct hash<const char*> { |
| 195 | // Dummy, just to make derivative hash functions compile. |
| 196 | int operator()(const char* key) { |
| 197 | GOOGLE_LOG(FATAL) << "Should never be called."; |
| 198 | return 0; |
| 199 | } |
| 200 | |
| 201 | inline bool operator()(const char* a, const char* b) const { |
| 202 | return strcmp(a, b) < 0; |
| 203 | } |
| 204 | }; |
| 205 | |
| 206 | template <typename Key, typename Data, |
| 207 | typename HashFcn = hash<Key>, |
| 208 | typename EqualKey = std::equal_to<Key>, |
| 209 | typename Alloc = std::allocator< std::pair<const Key, Data> > > |
| 210 | class hash_map : public std::map<Key, Data, HashFcn, Alloc> { |
| 211 | typedef std::map<Key, Data, HashFcn, Alloc> BaseClass; |
| 212 | |
| 213 | public: |
| 214 | hash_map(int a = 0, const HashFcn& b = HashFcn(), |
| 215 | const EqualKey& c = EqualKey(), |
| 216 | const Alloc& d = Alloc()) : BaseClass(b, d) {} |
| 217 | }; |
| 218 | |
| 219 | template <typename Key, |
| 220 | typename HashFcn = hash<Key>, |
| 221 | typename EqualKey = std::equal_to<Key> > |
| 222 | class hash_set : public std::set<Key, HashFcn> { |
| 223 | public: |
| 224 | hash_set(int = 0) {} |
| 225 | }; |
| 226 | |
| 227 | #elif defined(_MSC_VER) && !defined(_STLPORT_VERSION) |
| 228 | |
| 229 | template <typename Key> |
| 230 | struct hash : public GOOGLE_PROTOBUF_HASH_COMPARE<Key> { |
| 231 | }; |
| 232 | |
| 233 | // MSVC's hash_compare<const char*> hashes based on the string contents but |
| 234 | // compares based on the string pointer. WTF? |
| 235 | class CstringLess { |
| 236 | public: |
| 237 | inline bool operator()(const char* a, const char* b) const { |
| 238 | return strcmp(a, b) < 0; |
| 239 | } |
| 240 | }; |
| 241 | |
| 242 | template <> |
| 243 | struct hash<const char*> |
| 244 | : public GOOGLE_PROTOBUF_HASH_COMPARE<const char*, CstringLess> {}; |
| 245 | |
| 246 | template <typename Key, typename Data, |
| 247 | typename HashFcn = hash<Key>, |
| 248 | typename EqualKey = std::equal_to<Key>, |
| 249 | typename Alloc = std::allocator< std::pair<const Key, Data> > > |
| 250 | class hash_map |
| 251 | : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< |
| 252 | Key, Data, HashFcn, EqualKey, Alloc> { |
| 253 | typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< |
| 254 | Key, Data, HashFcn, EqualKey, Alloc> BaseClass; |
| 255 | |
| 256 | public: |
| 257 | hash_map(int a = 0, const HashFcn& b = HashFcn(), |
| 258 | const EqualKey& c = EqualKey(), |
| 259 | const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {} |
| 260 | }; |
| 261 | |
| 262 | template <typename Key, typename HashFcn = hash<Key>, |
| 263 | typename EqualKey = std::equal_to<Key> > |
| 264 | class hash_set |
| 265 | : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS< |
| 266 | Key, HashFcn, EqualKey> { |
| 267 | public: |
| 268 | hash_set(int = 0) {} |
| 269 | }; |
| 270 | |
| 271 | #else |
| 272 | |
| 273 | template <typename Key> |
| 274 | struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash<Key> { |
| 275 | }; |
| 276 | |
| 277 | template <typename Key> |
| 278 | struct hash<const Key*> { |
| 279 | inline size_t operator()(const Key* key) const { |
| 280 | return reinterpret_cast<size_t>(key); |
| 281 | } |
| 282 | }; |
| 283 | |
| 284 | // Unlike the old SGI version, the TR1 "hash" does not special-case char*. So, |
| 285 | // we go ahead and provide our own implementation. |
| 286 | template <> |
| 287 | struct hash<const char*> { |
| 288 | inline size_t operator()(const char* str) const { |
| 289 | size_t result = 0; |
| 290 | for (; *str != '\0'; str++) { |
| 291 | result = 5 * result + *str; |
| 292 | } |
| 293 | return result; |
| 294 | } |
| 295 | }; |
| 296 | |
| 297 | template<> |
| 298 | struct hash<bool> { |
| 299 | size_t operator()(bool x) const { |
| 300 | return static_cast<size_t>(x); |
| 301 | } |
| 302 | }; |
| 303 | |
| 304 | template <typename Key, typename Data, |
| 305 | typename HashFcn = hash<Key>, |
| 306 | typename EqualKey = std::equal_to<Key>, |
| 307 | typename Alloc = std::allocator< std::pair<const Key, Data> > > |
| 308 | class hash_map |
| 309 | : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< |
| 310 | Key, Data, HashFcn, EqualKey, Alloc> { |
| 311 | typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS< |
| 312 | Key, Data, HashFcn, EqualKey, Alloc> BaseClass; |
| 313 | |
| 314 | public: |
| 315 | hash_map(int a = 0, const HashFcn& b = HashFcn(), |
| 316 | const EqualKey& c = EqualKey(), |
| 317 | const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {} |
| 318 | }; |
| 319 | |
| 320 | template <typename Key, typename HashFcn = hash<Key>, |
| 321 | typename EqualKey = std::equal_to<Key> > |
| 322 | class hash_set |
| 323 | : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS< |
| 324 | Key, HashFcn, EqualKey> { |
| 325 | public: |
| 326 | hash_set(int = 0) {} |
| 327 | }; |
| 328 | |
| 329 | #endif // !GOOGLE_PROTOBUF_MISSING_HASH |
| 330 | |
| 331 | template <> |
| 332 | struct hash<string> { |
| 333 | inline size_t operator()(const string& key) const { |
| 334 | return hash<const char*>()(key.c_str()); |
| 335 | } |
| 336 | |
| 337 | static const size_t bucket_size = 4; |
| 338 | static const size_t min_buckets = 8; |
| 339 | inline bool operator()(const string& a, const string& b) const { |
| 340 | return a < b; |
| 341 | } |
| 342 | }; |
| 343 | |
| 344 | template <typename First, typename Second> |
| 345 | struct hash<pair<First, Second> > { |
| 346 | inline size_t operator()(const pair<First, Second>& key) const { |
| 347 | size_t first_hash = hash<First>()(key.first); |
| 348 | size_t second_hash = hash<Second>()(key.second); |
| 349 | |
| 350 | // FIXME(kenton): What is the best way to compute this hash? I have |
| 351 | // no idea! This seems a bit better than an XOR. |
| 352 | return first_hash * ((1 << 16) - 1) + second_hash; |
| 353 | } |
| 354 | |
| 355 | static const size_t bucket_size = 4; |
| 356 | static const size_t min_buckets = 8; |
| 357 | inline bool operator()(const pair<First, Second>& a, |
| 358 | const pair<First, Second>& b) const { |
| 359 | return a < b; |
| 360 | } |
| 361 | }; |
| 362 | |
| 363 | // Used by GCC/SGI STL only. (Why isn't this provided by the standard |
| 364 | // library? :( ) |
| 365 | struct streq { |
| 366 | inline bool operator()(const char* a, const char* b) const { |
| 367 | return strcmp(a, b) == 0; |
| 368 | } |
| 369 | }; |
| 370 | |
| 371 | } // namespace protobuf |
| 372 | } // namespace google |
| 373 | |
| 374 | #endif // GOOGLE_PROTOBUF_STUBS_HASH_H__ |