1fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Protocol Buffers - Google's data interchange format
2fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Copyright 2008 Google Inc.  All rights reserved.
3fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// http://code.google.com/p/protobuf/
4fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
5fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Redistribution and use in source and binary forms, with or without
6fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// modification, are permitted provided that the following conditions are
7fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// met:
8fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
9fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Redistributions of source code must retain the above copyright
10fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// notice, this list of conditions and the following disclaimer.
11fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Redistributions in binary form must reproduce the above
12fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// copyright notice, this list of conditions and the following disclaimer
13fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// in the documentation and/or other materials provided with the
14fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// distribution.
15fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//     * Neither the name of Google Inc. nor the names of its
16fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// contributors may be used to endorse or promote products derived from
17fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// this software without specific prior written permission.
18fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
19fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
31fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Author: kenton@google.com (Kenton Varda)
32fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville//
33fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Deals with the fact that hash_map is not defined everywhere.
34fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
35fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#ifndef GOOGLE_PROTOBUF_STUBS_HASH_H__
36fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#define GOOGLE_PROTOBUF_STUBS_HASH_H__
37fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
38fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <string.h>
39fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <google/protobuf/stubs/common.h>
40fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include "config.h"
41fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
42fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#if defined(HAVE_HASH_MAP) && defined(HAVE_HASH_SET)
43fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include HASH_MAP_H
44fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include HASH_SET_H
45fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#else
46fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#define MISSING_HASH
47fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <map>
48fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#include <set>
49fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#endif
50fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
51fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace google {
52fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillenamespace protobuf {
53fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
54fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#ifdef MISSING_HASH
55fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
56fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// This system doesn't have hash_map or hash_set.  Emulate them using map and
57fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// set.
58fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
59fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Make hash<T> be the same as less<T>.  Note that everywhere where custom
60fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// hash functions are defined in the protobuf code, they are also defined such
61fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// that they can be used as "less" functions, which is required by MSVC anyway.
62fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename Key>
63fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillestruct hash {
64fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // Dummy, just to make derivative hash functions compile.
65fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  int operator()(const Key& key) {
66fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    GOOGLE_LOG(FATAL) << "Should never be called.";
67fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return 0;
68fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
69fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
70fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  inline bool operator()(const Key& a, const Key& b) const {
71fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return a < b;
72fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
73fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
74fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
75fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Make sure char* is compared by value.
76fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <>
77fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillestruct hash<const char*> {
78fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  // Dummy, just to make derivative hash functions compile.
79fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  int operator()(const char* key) {
80fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    GOOGLE_LOG(FATAL) << "Should never be called.";
81fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return 0;
82fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
83fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
84fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  inline bool operator()(const char* a, const char* b) const {
85fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return strcmp(a, b) < 0;
86fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
87fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
88fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
89fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename Key, typename Data,
90fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename HashFcn = hash<Key>,
91fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename EqualKey = int >
92fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleclass hash_map : public std::map<Key, Data, HashFcn> {
93fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
94fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
95fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename Key,
96fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename HashFcn = hash<Key>,
97fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename EqualKey = int >
98fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleclass hash_set : public std::set<Key, HashFcn> {
99fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
100fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
101d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION)
102fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
103fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename Key>
104fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillestruct hash : public HASH_NAMESPACE::hash_compare<Key> {
105fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
106fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
107fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// MSVC's hash_compare<const char*> hashes based on the string contents but
108fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// compares based on the string pointer.  WTF?
109fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleclass CstringLess {
110fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville public:
111fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  inline bool operator()(const char* a, const char* b) const {
112fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return strcmp(a, b) < 0;
113fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
114fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
115fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
116fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <>
117fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillestruct hash<const char*>
118fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  : public HASH_NAMESPACE::hash_compare<const char*, CstringLess> {
119fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
120fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
121fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename Key, typename Data,
122fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename HashFcn = hash<Key>,
123fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename EqualKey = int >
124fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleclass hash_map : public HASH_NAMESPACE::hash_map<
125fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Key, Data, HashFcn> {
126fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
127fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
128fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename Key,
129fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename HashFcn = hash<Key>,
130fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename EqualKey = int >
131fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilleclass hash_set : public HASH_NAMESPACE::hash_set<
132fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Key, HashFcn> {
133fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
134fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
135fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#else
136fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
137fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename Key>
138fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillestruct hash : public HASH_NAMESPACE::hash<Key> {
139fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
140fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
141fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename Key>
142fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillestruct hash<const Key*> {
143fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  inline size_t operator()(const Key* key) const {
144fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return reinterpret_cast<size_t>(key);
145fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
146fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
147fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
148d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// Unlike the old SGI version, the TR1 "hash" does not special-case char*.  So,
149d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville// we go ahead and provide our own implementation.
150fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <>
151d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savillestruct hash<const char*> {
152d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  inline size_t operator()(const char* str) const {
153d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    size_t result = 0;
154d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    for (; *str != '\0'; str++) {
155d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville      result = 5 * result + *str;
156d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    }
157d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville    return result;
158d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Saville  }
159fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
160fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
161fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename Key, typename Data,
162fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename HashFcn = hash<Key>,
163fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename EqualKey = std::equal_to<Key> >
164d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savilleclass hash_map : public HASH_NAMESPACE::HASH_MAP_CLASS<
165fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Key, Data, HashFcn, EqualKey> {
166fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
167fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
168fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename Key,
169fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename HashFcn = hash<Key>,
170fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville          typename EqualKey = std::equal_to<Key> >
171d0332953cda33fb4f8e24ebff9c49159b69c43d6Wink Savilleclass hash_set : public HASH_NAMESPACE::HASH_SET_CLASS<
172fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    Key, HashFcn, EqualKey> {
173fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
174fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
175fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#endif
176fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
177fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <>
178fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillestruct hash<string> {
179fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  inline size_t operator()(const string& key) const {
180fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return hash<const char*>()(key.c_str());
181fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
182fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
183fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  static const size_t bucket_size = 4;
184fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  static const size_t min_buckets = 8;
185fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  inline size_t operator()(const string& a, const string& b) const {
186fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return a < b;
187fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
188fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
189fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
190fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savilletemplate <typename First, typename Second>
191fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillestruct hash<pair<First, Second> > {
192fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  inline size_t operator()(const pair<First, Second>& key) const {
193fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    size_t first_hash = hash<First>()(key.first);
194fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    size_t second_hash = hash<Second>()(key.second);
195fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
196fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // FIXME(kenton):  What is the best way to compute this hash?  I have
197fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    // no idea!  This seems a bit better than an XOR.
198fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return first_hash * ((1 << 16) - 1) + second_hash;
199fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
200fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
201fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  static const size_t bucket_size = 4;
202fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  static const size_t min_buckets = 8;
203fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  inline size_t operator()(const pair<First, Second>& a,
204fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville                           const pair<First, Second>& b) const {
205fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return a < b;
206fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
207fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
208fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
209fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// Used by GCC/SGI STL only.  (Why isn't this provided by the standard
210fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville// library?  :( )
211fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Savillestruct streq {
212fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  inline bool operator()(const char* a, const char* b) const {
213fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville    return strcmp(a, b) == 0;
214fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville  }
215fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville};
216fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
217fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace protobuf
218fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville}  // namespace google
219fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville
220fbaaef999ba563838ebd00874ed8a1c01fbf286dWink Saville#endif  // GOOGLE_PROTOBUF_STUBS_HASH_H__
221