blob: 583343222ec61af2e18ebbd0245b3ce1a36a70f5 [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001// 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
167namespace google {
168namespace 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.
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>,
208 typename EqualKey = std::equal_to<Key>,
209 typename Alloc = std::allocator< std::pair<const Key, Data> > >
210class 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
219template <typename Key,
220 typename HashFcn = hash<Key>,
221 typename EqualKey = std::equal_to<Key> >
222class 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
229template <typename Key>
230struct 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?
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*>
244 : public GOOGLE_PROTOBUF_HASH_COMPARE<const char*, CstringLess> {};
245
246template <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> > >
250class 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
262template <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> {
267 public:
268 hash_set(int = 0) {}
269};
270
271#else
272
273template <typename Key>
274struct hash : public GOOGLE_PROTOBUF_HASH_NAMESPACE::hash<Key> {
275};
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
284// Unlike the old SGI version, the TR1 "hash" does not special-case char*. So,
285// we go ahead and provide our own implementation.
286template <>
287struct 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
297template<>
298struct hash<bool> {
299 size_t operator()(bool x) const {
300 return static_cast<size_t>(x);
301 }
302};
303
304template <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> > >
308class 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
320template <typename Key, typename HashFcn = hash<Key>,
321 typename EqualKey = std::equal_to<Key> >
322class 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
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;
339 inline bool operator()(const string& a, const string& b) const {
340 return a < b;
341 }
342};
343
344template <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;
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? :( )
365struct 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__