blob: 583343222ec61af2e18ebbd0245b3ce1a36a70f5 [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
temporal40ee5512008-07-10 02:12:20 +00004//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
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>
Bo Yang9f563bd2015-07-06 16:07:57 -070040
41#define GOOGLE_PROTOBUF_HAVE_HASH_MAP 1
42#define GOOGLE_PROTOBUF_HAVE_HASH_SET 1
43
Bo Yang7c14dc82015-09-15 18:25:02 -070044// Android
45#if defined(__ANDROID__)
46# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
47# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
48
Peter Kasting5ea84dd2015-08-27 14:04:04 -070049// Use C++11 unordered_{map|set} if available.
Bo Yang7c14dc82015-09-15 18:25:02 -070050#elif ((_LIBCPP_STD_VER >= 11) || \
51 (((__cplusplus >= 201103L) || defined(__GXX_EXPERIMENTAL_CXX0X)) && \
Peter Kastinga1be7112015-08-27 19:59:06 -070052 (__GLIBCXX__ > 20090421)))
Bo Yang9f563bd2015-07-06 16:07:57 -070053# 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
Bo Yangff7bdad2015-08-23 10:45:14 -0700111# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP
112# undef GOOGLE_PROTOBUF_HAVE_HASH_SET
Bo Yang9f563bd2015-07-06 16:07:57 -0700113# 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
Bo Yangff7bdad2015-08-23 10:45:14 -0700151# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \
152 namespace google { \
153 namespace protobuf {
Jisi Liub0f66112015-08-21 11:18:45 -0700154# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }}
Jisi Liub0f66112015-08-21 11:18:45 -0700155
Bo Yang9f563bd2015-07-06 16:07:57 -0700156#undef GOOGLE_PROTOBUF_HAS_CXX11_HASH
157#undef GOOGLE_PROTOBUF_HAS_TR1
temporal40ee5512008-07-10 02:12:20 +0000158
Jisi Liudf184fb2015-02-25 15:28:44 -0800159#if defined(GOOGLE_PROTOBUF_HAVE_HASH_MAP) && \
160 defined(GOOGLE_PROTOBUF_HAVE_HASH_SET)
temporal40ee5512008-07-10 02:12:20 +0000161#else
Jisi Liudf184fb2015-02-25 15:28:44 -0800162#define GOOGLE_PROTOBUF_MISSING_HASH
kenton@google.com44103962008-09-19 16:53:32 +0000163#include <map>
164#include <set>
temporal40ee5512008-07-10 02:12:20 +0000165#endif
166
167namespace google {
168namespace protobuf {
169
Jisi Liudf184fb2015-02-25 15:28:44 -0800170#ifdef GOOGLE_PROTOBUF_MISSING_HASH
Yohei Yukawacf9f6032015-05-04 01:25:52 -0700171#undef GOOGLE_PROTOBUF_MISSING_HASH
kenton@google.com44103962008-09-19 16:53:32 +0000172
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.
179template <typename Key>
180struct 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.
193template <>
194struct 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
206template <typename Key, typename Data,
207 typename HashFcn = hash<Key>,
Jisi Liu4065a312015-03-01 21:02:22 -0800208 typename EqualKey = std::equal_to<Key>,
Jisi Liu14fe0c92015-03-01 19:51:58 -0800209 typename Alloc = std::allocator< std::pair<const Key, Data> > >
Bo Yang9f563bd2015-07-06 16:07:57 -0700210class hash_map : public std::map<Key, Data, HashFcn, Alloc> {
211 typedef std::map<Key, Data, HashFcn, Alloc> BaseClass;
Feng Xiao72f17c42015-05-25 18:18:29 -0700212
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000213 public:
Feng Xiao72f17c42015-05-25 18:18:29 -0700214 hash_map(int a = 0, const HashFcn& b = HashFcn(),
215 const EqualKey& c = EqualKey(),
Bo Yang9f563bd2015-07-06 16:07:57 -0700216 const Alloc& d = Alloc()) : BaseClass(b, d) {}
kenton@google.com44103962008-09-19 16:53:32 +0000217};
218
219template <typename Key,
220 typename HashFcn = hash<Key>,
Jisi Liu4065a312015-03-01 21:02:22 -0800221 typename EqualKey = std::equal_to<Key> >
kenton@google.com44103962008-09-19 16:53:32 +0000222class hash_set : public std::set<Key, HashFcn> {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000223 public:
224 hash_set(int = 0) {}
kenton@google.com44103962008-09-19 16:53:32 +0000225};
226
kenton@google.com3aa7a0d2009-08-17 20:34:29 +0000227#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION)
temporal40ee5512008-07-10 02:12:20 +0000228
229template <typename Key>
unknownca1c2522015-05-27 11:45:32 -0700230struct hash : public GOOGLE_PROTOBUF_HASH_COMPARE<Key> {
temporal40ee5512008-07-10 02:12:20 +0000231};
232
233// MSVC's hash_compare<const char*> hashes based on the string contents but
234// compares based on the string pointer. WTF?
235class CstringLess {
236 public:
237 inline bool operator()(const char* a, const char* b) const {
238 return strcmp(a, b) < 0;
239 }
240};
241
242template <>
243struct hash<const char*>
unknownca1c2522015-05-27 11:45:32 -0700244 : public GOOGLE_PROTOBUF_HASH_COMPARE<const char*, CstringLess> {};
temporal40ee5512008-07-10 02:12:20 +0000245
246template <typename Key, typename Data,
247 typename HashFcn = hash<Key>,
Jisi Liu4065a312015-03-01 21:02:22 -0800248 typename EqualKey = std::equal_to<Key>,
Jisi Liu14fe0c92015-03-01 19:51:58 -0800249 typename Alloc = std::allocator< std::pair<const Key, Data> > >
Jisi Liu4065a312015-03-01 21:02:22 -0800250class hash_map
251 : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
252 Key, Data, HashFcn, EqualKey, Alloc> {
Feng Xiao72f17c42015-05-25 18:18:29 -0700253 typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
254 Key, Data, HashFcn, EqualKey, Alloc> BaseClass;
255
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000256 public:
Feng Xiao72f17c42015-05-25 18:18:29 -0700257 hash_map(int a = 0, const HashFcn& b = HashFcn(),
258 const EqualKey& c = EqualKey(),
259 const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {}
temporal40ee5512008-07-10 02:12:20 +0000260};
261
Jisi Liu4065a312015-03-01 21:02:22 -0800262template <typename Key, typename HashFcn = hash<Key>,
263 typename EqualKey = std::equal_to<Key> >
264class hash_set
265 : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
266 Key, HashFcn, EqualKey> {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000267 public:
268 hash_set(int = 0) {}
temporal40ee5512008-07-10 02:12:20 +0000269};
270
271#else
272
273template <typename Key>
Jisi Liudf184fb2015-02-25 15:28:44 -0800274struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash<Key> {
temporal40ee5512008-07-10 02:12:20 +0000275};
276
277template <typename Key>
278struct hash<const Key*> {
279 inline size_t operator()(const Key* key) const {
280 return reinterpret_cast<size_t>(key);
281 }
282};
283
kenton@google.comee7e9422009-12-21 18:58:23 +0000284// Unlike the old SGI version, the TR1 "hash" does not special-case char*. So,
285// we go ahead and provide our own implementation.
temporal40ee5512008-07-10 02:12:20 +0000286template <>
kenton@google.comee7e9422009-12-21 18:58:23 +0000287struct 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 }
temporal40ee5512008-07-10 02:12:20 +0000295};
296
Bo Yangd6c9f642015-04-24 15:34:40 -0700297template<>
298struct hash<bool> {
299 size_t operator()(bool x) const {
300 return static_cast<size_t>(x);
301 }
302};
303
Jisi Liu4065a312015-03-01 21:02:22 -0800304template <typename Key, typename Data,
305 typename HashFcn = hash<Key>,
Jisi Liu885b6122015-02-28 14:51:22 -0800306 typename EqualKey = std::equal_to<Key>,
307 typename Alloc = std::allocator< std::pair<const Key, Data> > >
Jisi Liudf184fb2015-02-25 15:28:44 -0800308class hash_map
309 : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
Jisi Liu885b6122015-02-28 14:51:22 -0800310 Key, Data, HashFcn, EqualKey, Alloc> {
Feng Xiao72f17c42015-05-25 18:18:29 -0700311 typedef GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_MAP_CLASS<
312 Key, Data, HashFcn, EqualKey, Alloc> BaseClass;
313
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000314 public:
Feng Xiao72f17c42015-05-25 18:18:29 -0700315 hash_map(int a = 0, const HashFcn& b = HashFcn(),
316 const EqualKey& c = EqualKey(),
317 const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {}
temporal40ee5512008-07-10 02:12:20 +0000318};
319
Jisi Liudf184fb2015-02-25 15:28:44 -0800320template <typename Key, typename HashFcn = hash<Key>,
temporal40ee5512008-07-10 02:12:20 +0000321 typename EqualKey = std::equal_to<Key> >
Jisi Liudf184fb2015-02-25 15:28:44 -0800322class hash_set
323 : public GOOGLE_PROTOBUF_HASH_NAMESPACE::GOOGLE_PROTOBUF_HASH_SET_CLASS<
324 Key, HashFcn, EqualKey> {
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000325 public:
326 hash_set(int = 0) {}
temporal40ee5512008-07-10 02:12:20 +0000327};
328
Jisi Liudf184fb2015-02-25 15:28:44 -0800329#endif // !GOOGLE_PROTOBUF_MISSING_HASH
temporal40ee5512008-07-10 02:12:20 +0000330
331template <>
332struct 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;
Bo Yangd6c9f642015-04-24 15:34:40 -0700339 inline bool operator()(const string& a, const string& b) const {
temporal40ee5512008-07-10 02:12:20 +0000340 return a < b;
341 }
342};
343
kenton@google.comd37d46d2009-04-25 02:53:47 +0000344template <typename First, typename Second>
345struct 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;
Bo Yangd6c9f642015-04-24 15:34:40 -0700357 inline bool operator()(const pair<First, Second>& a,
kenton@google.comd37d46d2009-04-25 02:53:47 +0000358 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? :( )
365struct streq {
366 inline bool operator()(const char* a, const char* b) const {
367 return strcmp(a, b) == 0;
368 }
369};
370
temporal40ee5512008-07-10 02:12:20 +0000371} // namespace protobuf
372} // namespace google
373
374#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__