source: GTP/trunk/Lib/Vis/Preprocessing/src/sparsehash/src/google/dense_hash_map @ 2162

Revision 2162, 11.2 KB checked in by mattausch, 17 years ago (diff)

improved hash performance with google hashmap

Line 
1// Copyright (c) 2005, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14//     * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ----
31// Author: Craig Silverstein
32//
33// This is just a very thin wrapper over densehashtable.h, just
34// like sgi stl's stl_hash_map is a very thin wrapper over
35// stl_hashtable.  The major thing we define is operator[], because
36// we have a concept of a data_type which stl_hashtable doesn't
37// (it only has a key and a value).
38//
39// NOTE: this is exactly like sparse_hash_map.h, with the word
40// "sparse" replaced by "dense", except for the addition of
41// set_empty_key().
42//
43//   YOU MUST CALL SET_EMPTY_KEY() IMMEDIATELY AFTER CONSTRUCTION.
44//
45// Otherwise your program will die in mysterious ways.
46//
47// In other respects, we adhere mostly to the STL semantics for
48// hash-map.  One important exception is that insert() invalidates
49// iterators entirely.  On the plus side, though, erase() doesn't
50// invalidate iterators at all, or even change the ordering of elements.
51//
52// Here are a few "power user" tips:
53//
54//    1) set_deleted_key():
55//         If you want to use erase() you must call set_deleted_key(),
56//         in addition to set_empty_key(), after construction.
57//
58//    2) resize(0):
59//         When an item is deleted, its memory isn't freed right
60//         away.  This allows you to iterate over a hashtable,
61//         and call erase(), without invalidating the iterator.
62//         To force the memory to be freed, call resize(0).
63//
64// Guide to what kind of hash_map to use:
65//   (1) dense_hash_map: fastest, uses the most memory
66//   (2) sparse_hash_map: slowest, uses the least memory
67//   (3) hash_map (STL): in the middle
68// Typically I use sparse_hash_map when I care about space and/or when
69// I need to save the hashtable on disk.  I use hash_map otherwise.  I
70// don't personally use dense_hash_map ever; the only use of
71// dense_hash_map I know of is to work around malloc() bugs in some
72// systems (dense_hash_map has a particularly simple allocation scheme).
73//
74// - dense_hash_map has, typically, a factor of 2 memory overhead (if your
75//   data takes up X bytes, the hash_map uses X more bytes in overhead).
76// - sparse_hash_map has about 2 bits overhead per entry.
77// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
78//   especially, inserts.  See time_hash_map.cc for details.
79//
80// See /usr/(local/)?doc/sparsehash-0.1/dense_hash_map.html
81// for information about how to use this class.
82
83#ifndef _DENSE_HASH_MAP_H_
84#define _DENSE_HASH_MAP_H_
85
86#include <google/sparsehash/config.h>
87#include <stdio.h>                   // for FILE * in read()/write()
88#include <algorithm>                 // for the default template args
89#include <functional>                // for equal_to
90#include <memory>                    // for alloc<>
91#include <google/sparsehash/hash_fun.h>
92#include <google/sparsehash/densehashtable.h>
93
94
95// Lots of STLs don't support type traits, so we might just do without.
96// We also have a guard to make sure we don't include this code twice:
97// once for sparse_hash_map and once for dense_hash_map.
98#if defined(UNDERSTANDS_TYPE_TRAITS) && !defined(_ANDED_TRAITS_)
99#define _ANDED_TRAITS_
100
101#if defined HAVE_TYPE_TRAITS
102#include <type_traits.h>
103#elif defined HAVE_BITS_TYPE_TRAITS
104#include <bits/type_traits.h>
105#endif
106
107// We need to let the densetable know that our pair<Key,Data> is
108// a Plain Old Data type if both the Key and Data are.
109template <class Key, class T>       
110struct __and_trait {                             // by default x & y == false
111    typedef __false_type tp;
112};
113
114template <> struct __and_trait<__true_type, __true_type> {   // but true & true == true
115    typedef __true_type tp;
116};
117
118#define AND_(trait)                                                     \
119   typedef typename __and_trait<typename __type_traits<Key>::trait,     \
120                                typename __type_traits< T >::trait>::tp \
121   trait
122
123template <class Key, class T>
124struct __type_traits< STL_NAMESPACE::pair<const Key, T> > {
125  AND_(has_trivial_default_constructor);
126  AND_(has_trivial_copy_constructor);
127  AND_(has_trivial_assignment_operator);
128  AND_(has_trivial_destructor);
129  AND_(is_POD_type);
130};
131
132#undef AND_
133
134#endif   /* #defined UNDERSTANDS_TYPE_TRAITS && _ANDED_TRAITS_ */
135
136_START_GOOGLE_NAMESPACE_
137
138using STL_NAMESPACE::pair;
139
140template <class Key, class T,
141          class HashFcn = HASH_NAMESPACE::hash<Key>,
142          class EqualKey = STL_NAMESPACE::equal_to<Key>,
143          class Alloc = STL_NAMESPACE::allocator<T> >
144class dense_hash_map {
145
146 private:
147  // Apparently select1st is not stl-standard, so we define our own
148  struct SelectKey {
149    const Key& operator()(const pair<const Key, T>& p) const {
150      return p.first;
151    }
152  };
153
154  // The actual data
155  typedef dense_hashtable<pair<const Key, T>, Key, HashFcn,
156                          SelectKey, EqualKey, Alloc> ht;
157  ht rep;
158
159 public:
160  typedef typename ht::key_type key_type;
161  typedef T data_type;
162  typedef T mapped_type;
163  typedef typename ht::value_type value_type;
164  typedef typename ht::hasher hasher;
165  typedef typename ht::key_equal key_equal;
166
167  typedef typename ht::size_type size_type;
168  typedef typename ht::difference_type difference_type;
169  typedef typename ht::pointer pointer;
170  typedef typename ht::const_pointer const_pointer;
171  typedef typename ht::reference reference;
172  typedef typename ht::const_reference const_reference;
173
174  typedef typename ht::iterator iterator;
175  typedef typename ht::const_iterator const_iterator;
176
177  // Iterator functions
178  iterator begin()                    { return rep.begin(); }
179  iterator end()                      { return rep.end(); }
180  const_iterator begin() const        { return rep.begin(); }
181  const_iterator end() const          { return rep.end(); }
182
183
184  // Accessor functions
185  hasher hash_funct() const { return rep.hash_funct(); }
186  key_equal key_eq() const  { return rep.key_eq(); }
187
188
189  // Constructors
190  explicit dense_hash_map(size_type n = 0,
191                          const hasher& hf = hasher(),
192                          const key_equal& eql = key_equal())
193    : rep(n, hf, eql) { }
194 
195  template <class InputIterator>
196  dense_hash_map(InputIterator f, InputIterator l,
197                 size_type n = 0,
198                 const hasher& hf = hasher(),
199                 const key_equal& eql = key_equal()) {
200    rep.insert(f, l);
201  }
202  // We use the default copy constructor
203  // We use the default operator=()
204  // We use the default destructor
205
206  void clear()                        { rep.clear(); }
207  void swap(dense_hash_map& hs)       { rep.swap(hs.rep); }
208
209
210  // Functions concerning size
211  size_type size() const              { return rep.size(); }
212  size_type max_size() const          { return rep.max_size(); }
213  bool empty() const                  { return rep.empty(); }
214  size_type bucket_count() const      { return rep.bucket_count(); }
215  size_type max_bucket_count() const  { return rep.max_bucket_count(); }
216
217  void resize(size_type hint)         { rep.resize(hint); }
218
219
220  // Lookup routines
221  iterator find(const key_type& key)                 { return rep.find(key); }
222  const_iterator find(const key_type& key) const     { return rep.find(key); }
223
224  data_type& operator[](const key_type& key) {       // This is our value-add!
225    return (*((rep.insert(value_type(key, data_type()))).first)).second;
226  }
227
228  size_type count(const key_type& key) const         { return rep.count(key); }
229 
230  pair<iterator, iterator> equal_range(const key_type& key) {
231    return rep.equal_range(key);
232  }
233  pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
234    return rep.equal_range(key);
235  }
236 
237  // Insertion routines
238  pair<iterator, bool> insert(const value_type& obj) { return rep.insert(obj); }
239  template <class InputIterator>
240  void insert(InputIterator f, InputIterator l)      { rep.insert(f, l); }
241  void insert(const_iterator f, const_iterator l)    { rep.insert(f, l); }
242  // required for std::insert_iterator; the passed-in iterator is ignored
243  iterator insert(iterator, const value_type& obj)   { return insert(obj).first; }
244
245
246  // Deletion and empty routines
247  // THESE ARE NON-STANDARD!  I make you specify an "impossible" key
248  // value to identify deleted and empty buckets.  You can change the
249  // deleted key as time goes on, or get rid of it entirely to be insert-only.
250  void set_empty_key(const key_type& key)   {           // YOU MUST CALL THIS!
251    rep.set_empty_key(key);
252  }
253  void set_deleted_key(const key_type& key)   {
254    rep.set_deleted_key(key);
255  }
256  void clear_deleted_key()                    { rep.clear_deleted_key(); }
257
258  // These are standard
259  size_type erase(const key_type& key)               { return rep.erase(key); }
260  void erase(iterator it)                            { rep.erase(it); }
261  void erase(iterator f, iterator l)                 { rep.erase(f, l); }
262
263
264  // Comparison
265  bool operator==(const dense_hash_map& hs) const    { return rep == hs.rep; }
266  bool operator!=(const dense_hash_map& hs) const    { return rep != hs.rep; }
267
268
269  // I/O -- this is an add-on for writing metainformation to disk
270  bool write_metadata(FILE *fp)       { return rep.write_metadata(fp); }
271  bool read_metadata(FILE *fp)        { return rep.read_metadata(fp); }
272  bool write_nopointer_data(FILE *fp) { return rep.write_nopointer_data(fp); }
273  bool read_nopointer_data(FILE *fp)  { return rep.read_nopointer_data(fp); }
274};
275
276// We need a global swap as well
277template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
278inline void swap(dense_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm1,
279                 dense_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm2) {
280  hm1.swap(hm2);
281}
282
283_END_GOOGLE_NAMESPACE_
284
285#endif /* _DENSE_HASH_MAP_H_ */
Note: See TracBrowser for help on using the repository browser.