mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 23:21:59 +00:00
dbms: using in-tree sparsehash library [#METR-17973].
This commit is contained in:
parent
345b4b91f7
commit
9590002294
2
contrib/libsparsehash/AUTHORS
Normal file
2
contrib/libsparsehash/AUTHORS
Normal file
@ -0,0 +1,2 @@
|
||||
google-sparsehash@googlegroups.com
|
||||
|
28
contrib/libsparsehash/COPYING
Normal file
28
contrib/libsparsehash/COPYING
Normal file
@ -0,0 +1,28 @@
|
||||
Copyright (c) 2005, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
188
contrib/libsparsehash/NEWS
Normal file
188
contrib/libsparsehash/NEWS
Normal file
@ -0,0 +1,188 @@
|
||||
== 23 Ferbruary 2012 ==
|
||||
|
||||
A backwards incompatibility arose from flattening the include headers
|
||||
structure for the <google> folder.
|
||||
|
||||
This is now fixed in 2.0.2. You only need to upgrade if you had previously
|
||||
included files from the <google/sparsehash> folder.
|
||||
|
||||
== 1 February 2012 ==
|
||||
|
||||
A minor bug related to the namespace switch from google to sparsehash
|
||||
stopped the build from working when perftools is also installed.
|
||||
|
||||
This is now fixed in 2.0.1. You only need to upgrade if you have perftools
|
||||
installed.
|
||||
|
||||
== 31 January 2012 ==
|
||||
|
||||
I've just released sparsehash 2.0.
|
||||
|
||||
The `google-sparsehash` project has been renamed to `sparsehash`. I
|
||||
(csilvers) am stepping down as maintainer, to be replaced by the team
|
||||
of Donovan Hide and Geoff Pike. Welcome to the team, Donovan and
|
||||
Geoff! Donovan has been an active contributor to sparsehash bug
|
||||
reports and discussions in the past, and Geoff has been closely
|
||||
involved with sparsehash inside Google (in addition to writing the
|
||||
[http://code.google.com/p/cityhash CityHash hash function]). The two
|
||||
of them together should be a formidable force. For good.
|
||||
|
||||
I bumped the major version number up to 2 to reflect the new community
|
||||
ownership of the project. All the
|
||||
[http://sparsehash.googlecode.com/svn/tags/sparsehash-2.0/ChangeLog changes]
|
||||
are related to the renaming.
|
||||
|
||||
The only functional change from sparsehash 1.12 is that I've renamed
|
||||
the `google/` include-directory to be `sparsehash/` instead. New code
|
||||
should `#include <sparsehash/sparse_hash_map>`/etc. I've kept the old
|
||||
names around as forwarding headers to the new, so `#include
|
||||
<google/sparse_hash_map>` will continue to work.
|
||||
|
||||
Note that the classes and functions remain in the `google` C++
|
||||
namespace (I didn't change that to `sparsehash` as well); I think
|
||||
that's a trickier transition, and can happen in a future release.
|
||||
|
||||
|
||||
=== 18 January 2011 ===
|
||||
|
||||
The `google-sparsehash` Google Code page has been renamed to
|
||||
`sparsehash`, in preparation for the project being renamed to
|
||||
`sparsehash`. In the coming weeks, I'll be stepping down as
|
||||
maintainer for the sparsehash project, and as part of that Google is
|
||||
relinquishing ownership of the project; it will now be entirely
|
||||
community run. The name change reflects that shift.
|
||||
|
||||
|
||||
=== 20 December 2011 ===
|
||||
|
||||
I've just released sparsehash 1.12. This release features improved
|
||||
I/O (serialization) support. Support is finally added to serialize
|
||||
and unserialize `dense_hash_map`/`set`, paralleling the existing code
|
||||
for `sparse_hash_map`/`set`. In addition, the serialization API has
|
||||
gotten simpler, with a single `serialize()` method to write to disk,
|
||||
and an `unserialize()` method to read from disk. Finally, support has
|
||||
gotten more generic, with built-in support for both C `FILE*`s and C++
|
||||
streams, and an extension mechanism to support arbitrary sources and
|
||||
sinks.
|
||||
|
||||
There are also more minor changes, including minor bugfixes, an
|
||||
improved deleted-key test, and a minor addition to the `sparsetable`
|
||||
API. See the [http://google-sparsehash.googlecode.com/svn/tags/sparsehash-1.12/ChangeLog ChangeLog]
|
||||
for full details.
|
||||
|
||||
=== 23 June 2011 ===
|
||||
|
||||
I've just released sparsehash 1.11. The major user-visible change is
|
||||
that the default behavior is improved -- using the hash_map/set is
|
||||
faster -- for hashtables where the key is a pointer. We now notice
|
||||
that case and ignore the low 2-3 bits (which are almost always 0 for
|
||||
pointers) when hashing.
|
||||
|
||||
Another user-visible change is we've removed the tests for whether the
|
||||
STL (vector, pair, etc) is defined in the 'std' namespace. gcc 2.95
|
||||
is the most recent compiler I know of to put STL types and functions
|
||||
in the global namespace. If you need to use such an old compiler, do
|
||||
not update to the latest sparsehash release.
|
||||
|
||||
We've also changed the internal tools we use to integrate
|
||||
Googler-supplied patches to sparsehash into the opensource release.
|
||||
These new tools should result in more frequent updates with better
|
||||
change descriptions. They will also result in future ChangeLog
|
||||
entries being much more verbose (for better or for worse).
|
||||
|
||||
A full list of changes is described in
|
||||
[http://google-sparsehash.googlecode.com/svn/tags/sparsehash-1.11/ChangeLog ChangeLog].
|
||||
|
||||
=== 21 January 2011 ===
|
||||
|
||||
I've just released sparsehash 1.10. This fixes a performance
|
||||
regression in sparsehash 1.8, where sparse_hash_map would copy
|
||||
hashtable keys by value even when the key was explicitly a reference.
|
||||
It also fixes compiler warnings from MSVC 10, which uses some c++0x
|
||||
features that did not interact well with sparsehash.
|
||||
|
||||
There is no reason to upgrade unless you use references for your
|
||||
hashtable keys, or compile with MSVC 10. A full list of changes is
|
||||
described in
|
||||
[http://google-sparsehash.googlecode.com/svn/tags/sparsehash-1.10/ChangeLog ChangeLog].
|
||||
|
||||
|
||||
=== 24 September 2010 ===
|
||||
|
||||
I've just released sparsehash 1.9. This fixes a size regression in
|
||||
sparsehash 1.8, where the new allocator would take up space in
|
||||
`sparse_hash_map`, doubling the sparse_hash_map overhead (from 1-2
|
||||
bits per bucket to 3 or so). All users are encouraged to upgrade.
|
||||
|
||||
This change also marks enums as being Plain Old Data, which can speed
|
||||
up hashtables with enum keys and/or values. A full list of changes is
|
||||
described in
|
||||
[http://google-sparsehash.googlecode.com/svn/tags/sparsehash-1.9/ChangeLog ChangeLog].
|
||||
|
||||
=== 29 July 2010 ===
|
||||
|
||||
I've just released sparsehash 1.8. This includes improved support for
|
||||
`Allocator`, including supporting the allocator constructor arg and
|
||||
`get_allocator()` access method.
|
||||
|
||||
To work around a bug in gcc 4.0.x, I've renamed the static variables
|
||||
`HT_OCCUPANCY_FLT` and `HT_SHRINK_FLT` to `HT_OCCUPANCY_PCT` and
|
||||
`HT_SHRINK_PCT`, and changed their type from float to int. This
|
||||
should not be a user-visible change, since these variables are only
|
||||
used in the internal hashtable classes (sparsehash clients should use
|
||||
`max_load_factor()` and `min_load_factor()` instead of modifying these
|
||||
static variables), but if you do access these constants, you will need
|
||||
to change your code.
|
||||
|
||||
Internally, the biggest change is a revamp of the test suite. It now
|
||||
has more complete coverage, and a more capable timing tester. There
|
||||
are other, more minor changes as well. A full list of changes is
|
||||
described in the
|
||||
[http://google-sparsehash.googlecode.com/svn/tags/sparsehash-1.8/ChangeLog ChangeLog].
|
||||
|
||||
=== 31 March 2010 ===
|
||||
|
||||
I've just released sparsehash 1.7. The major news here is the
|
||||
addition of `Allocator` support. Previously, these hashtable classes
|
||||
would just ignore the `Allocator` template parameter. They now
|
||||
respect it, and even inherit `size_type`, `pointer`, etc. from the
|
||||
allocator class. By default, they use a special allocator we provide
|
||||
that uses libc `malloc` and `free` to allocate. The hash classes
|
||||
notice when this special allocator is being used, and use `realloc`
|
||||
when it can. This means that the default allocator is significantly
|
||||
faster than custom allocators are likely to be (since realloc-like
|
||||
functionality is not supported by STL allocators).
|
||||
|
||||
There are a few more minor changes as well. A full list of changes is
|
||||
described in the
|
||||
[http://google-sparsehash.googlecode.com/svn/tags/sparsehash-1.7/ChangeLog ChangeLog].
|
||||
|
||||
=== 11 January 2010 ===
|
||||
|
||||
I've just released sparsehash 1.6. The API has widened a bit with the
|
||||
addition of `deleted_key()` and `empty_key()`, which let you query
|
||||
what values these keys have. A few rather obscure bugs have been
|
||||
fixed (such as an error when copying one hashtable into another when
|
||||
the empty_keys differ). A full list of changes is described in the
|
||||
[http://google-sparsehash.googlecode.com/svn/tags/sparsehash-1.6/ChangeLog ChangeLog].
|
||||
|
||||
=== 9 May 2009 ===
|
||||
|
||||
I've just released sparsehash 1.5.1. Hot on the heels of sparsehash
|
||||
1.5, this release fixes a longstanding bug in the sparsehash code,
|
||||
where `equal_range` would always return an empty range. It now works
|
||||
as documented. All sparsehash users are encouraged to upgrade.
|
||||
|
||||
=== 7 May 2009 ===
|
||||
|
||||
I've just released sparsehash 1.5. This release introduces tr1
|
||||
compatibility: I've added `rehash`, `begin(i)`, and other methods that
|
||||
are expected to be part of the `unordered_map` API once `tr1` in
|
||||
introduced. This allows `sparse_hash_map`, `dense_hash_map`,
|
||||
`sparse_hash_set`, and `dense_hash_set` to be (almost) drop-in
|
||||
replacements for `unordered_map` and `unordered_set`.
|
||||
|
||||
There is no need to upgrade unless you need this functionality, or
|
||||
need one of the other, more minor, changes described in the
|
||||
[http://google-sparsehash.googlecode.com/svn/tags/sparsehash-1.5/ChangeLog ChangeLog].
|
||||
|
143
contrib/libsparsehash/README
Normal file
143
contrib/libsparsehash/README
Normal file
@ -0,0 +1,143 @@
|
||||
This directory contains several hash-map implementations, similar in
|
||||
API to SGI's hash_map class, but with different performance
|
||||
characteristics. sparse_hash_map uses very little space overhead, 1-2
|
||||
bits per entry. dense_hash_map is very fast, particulary on lookup.
|
||||
(sparse_hash_set and dense_hash_set are the set versions of these
|
||||
routines.) On the other hand, these classes have requirements that
|
||||
may not make them appropriate for all applications.
|
||||
|
||||
All these implementation use a hashtable with internal quadratic
|
||||
probing. This method is space-efficient -- there is no pointer
|
||||
overhead -- and time-efficient for good hash functions.
|
||||
|
||||
COMPILING
|
||||
---------
|
||||
To compile test applications with these classes, run ./configure
|
||||
followed by make. To install these header files on your system, run
|
||||
'make install'. (On Windows, the instructions are different; see
|
||||
README_windows.txt.) See INSTALL for more details.
|
||||
|
||||
This code should work on any modern C++ system. It has been tested on
|
||||
Linux (Ubuntu, Fedora, RedHat, Debian), Solaris 10 x86, FreeBSD 6.0,
|
||||
OS X 10.3 and 10.4, and Windows under both VC++7 and VC++8.
|
||||
|
||||
USING
|
||||
-----
|
||||
See the html files in the doc directory for small example programs
|
||||
that use these classes. It's enough to just include the header file:
|
||||
|
||||
#include <sparsehash/sparse_hash_map> // or sparse_hash_set, dense_hash_map, ...
|
||||
google::sparse_hash_set<int, int> number_mapper;
|
||||
|
||||
and use the class the way you would other hash-map implementations.
|
||||
(Though see "API" below for caveats.)
|
||||
|
||||
By default (you can change it via a flag to ./configure), these hash
|
||||
implementations are defined in the google namespace.
|
||||
|
||||
API
|
||||
---
|
||||
The API for sparse_hash_map, dense_hash_map, sparse_hash_set, and
|
||||
dense_hash_set, are a superset of the API of SGI's hash_map class.
|
||||
See doc/sparse_hash_map.html, et al., for more information about the
|
||||
API.
|
||||
|
||||
The usage of these classes differ from SGI's hash_map, and other
|
||||
hashtable implementations, in the following major ways:
|
||||
|
||||
1) dense_hash_map requires you to set aside one key value as the
|
||||
'empty bucket' value, set via the set_empty_key() method. This
|
||||
*MUST* be called before you can use the dense_hash_map. It is
|
||||
illegal to insert any elements into a dense_hash_map whose key is
|
||||
equal to the empty-key.
|
||||
|
||||
2) For both dense_hash_map and sparse_hash_map, if you wish to delete
|
||||
elements from the hashtable, you must set aside a key value as the
|
||||
'deleted bucket' value, set via the set_deleted_key() method. If
|
||||
your hash-map is insert-only, there is no need to call this
|
||||
method. If you call set_deleted_key(), it is illegal to insert any
|
||||
elements into a dense_hash_map or sparse_hash_map whose key is
|
||||
equal to the deleted-key.
|
||||
|
||||
3) These hash-map implementation support I/O. See below.
|
||||
|
||||
There are also some smaller differences:
|
||||
|
||||
1) The constructor takes an optional argument that specifies the
|
||||
number of elements you expect to insert into the hashtable. This
|
||||
differs from SGI's hash_map implementation, which takes an optional
|
||||
number of buckets.
|
||||
|
||||
2) erase() does not immediately reclaim memory. As a consequence,
|
||||
erase() does not invalidate any iterators, making loops like this
|
||||
correct:
|
||||
for (it = ht.begin(); it != ht.end(); ++it)
|
||||
if (...) ht.erase(it);
|
||||
As another consequence, a series of erase() calls can leave your
|
||||
hashtable using more memory than it needs to. The hashtable will
|
||||
automatically compact at the next call to insert(), but to
|
||||
manually compact a hashtable, you can call
|
||||
ht.resize(0)
|
||||
|
||||
I/O
|
||||
---
|
||||
In addition to the normal hash-map operations, sparse_hash_map can
|
||||
read and write hashtables to disk. (dense_hash_map also has the API,
|
||||
but it has not yet been implemented, and writes will always fail.)
|
||||
|
||||
In the simplest case, writing a hashtable is as easy as calling two
|
||||
methods on the hashtable:
|
||||
ht.write_metadata(fp);
|
||||
ht.write_nopointer_data(fp);
|
||||
|
||||
Reading in this data is equally simple:
|
||||
google::sparse_hash_map<...> ht;
|
||||
ht.read_metadata(fp);
|
||||
ht.read_nopointer_data(fp);
|
||||
|
||||
The above is sufficient if the key and value do not contain any
|
||||
pointers: they are basic C types or agglomorations of basic C types.
|
||||
If the key and/or value do contain pointers, you can still store the
|
||||
hashtable by replacing write_nopointer_data() with a custom writing
|
||||
routine. See sparse_hash_map.html et al. for more information.
|
||||
|
||||
SPARSETABLE
|
||||
-----------
|
||||
In addition to the hash-map and hash-set classes, this package also
|
||||
provides sparsetable.h, an array implementation that uses space
|
||||
proportional to the number of elements in the array, rather than the
|
||||
maximum element index. It uses very little space overhead: 1 bit per
|
||||
entry. See doc/sparsetable.html for the API.
|
||||
|
||||
RESOURCE USAGE
|
||||
--------------
|
||||
* sparse_hash_map has memory overhead of about 2 bits per hash-map
|
||||
entry.
|
||||
* dense_hash_map has a factor of 2-3 memory overhead: if your
|
||||
hashtable data takes X bytes, dense_hash_map will use 3X-4X memory
|
||||
total.
|
||||
|
||||
Hashtables tend to double in size when resizing, creating an
|
||||
additional 50% space overhead. dense_hash_map does in fact have a
|
||||
significant "high water mark" memory use requirement.
|
||||
sparse_hash_map, however, is written to need very little space
|
||||
overhead when resizing: only a few bits per hashtable entry.
|
||||
|
||||
PERFORMANCE
|
||||
-----------
|
||||
You can compile and run the included file time_hash_map.cc to examine
|
||||
the performance of sparse_hash_map, dense_hash_map, and your native
|
||||
hash_map implementation on your system. One test against the
|
||||
SGI hash_map implementation gave the following timing information for
|
||||
a simple find() call:
|
||||
SGI hash_map: 22 ns
|
||||
dense_hash_map: 13 ns
|
||||
sparse_hash_map: 117 ns
|
||||
SGI map: 113 ns
|
||||
|
||||
See doc/performance.html for more detailed charts on resource usage
|
||||
and performance data.
|
||||
|
||||
---
|
||||
16 March 2005
|
||||
(Last updated: 12 September 2010)
|
369
contrib/libsparsehash/sparsehash/dense_hash_map
Normal file
369
contrib/libsparsehash/sparsehash/dense_hash_map
Normal file
@ -0,0 +1,369 @@
|
||||
// Copyright (c) 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ----
|
||||
//
|
||||
// This is just a very thin wrapper over densehashtable.h, just
|
||||
// like sgi stl's stl_hash_map is a very thin wrapper over
|
||||
// stl_hashtable. The major thing we define is operator[], because
|
||||
// we have a concept of a data_type which stl_hashtable doesn't
|
||||
// (it only has a key and a value).
|
||||
//
|
||||
// NOTE: this is exactly like sparse_hash_map.h, with the word
|
||||
// "sparse" replaced by "dense", except for the addition of
|
||||
// set_empty_key().
|
||||
//
|
||||
// YOU MUST CALL SET_EMPTY_KEY() IMMEDIATELY AFTER CONSTRUCTION.
|
||||
//
|
||||
// Otherwise your program will die in mysterious ways. (Note if you
|
||||
// use the constructor that takes an InputIterator range, you pass in
|
||||
// the empty key in the constructor, rather than after. As a result,
|
||||
// this constructor differs from the standard STL version.)
|
||||
//
|
||||
// In other respects, we adhere mostly to the STL semantics for
|
||||
// hash-map. One important exception is that insert() may invalidate
|
||||
// iterators entirely -- STL semantics are that insert() may reorder
|
||||
// iterators, but they all still refer to something valid in the
|
||||
// hashtable. Not so for us. Likewise, insert() may invalidate
|
||||
// pointers into the hashtable. (Whether insert invalidates iterators
|
||||
// and pointers depends on whether it results in a hashtable resize).
|
||||
// On the plus side, delete() doesn't invalidate iterators or pointers
|
||||
// at all, or even change the ordering of elements.
|
||||
//
|
||||
// Here are a few "power user" tips:
|
||||
//
|
||||
// 1) set_deleted_key():
|
||||
// If you want to use erase() you *must* call set_deleted_key(),
|
||||
// in addition to set_empty_key(), after construction.
|
||||
// The deleted and empty keys must differ.
|
||||
//
|
||||
// 2) resize(0):
|
||||
// When an item is deleted, its memory isn't freed right
|
||||
// away. This allows you to iterate over a hashtable,
|
||||
// and call erase(), without invalidating the iterator.
|
||||
// To force the memory to be freed, call resize(0).
|
||||
// For tr1 compatibility, this can also be called as rehash(0).
|
||||
//
|
||||
// 3) min_load_factor(0.0)
|
||||
// Setting the minimum load factor to 0.0 guarantees that
|
||||
// the hash table will never shrink.
|
||||
//
|
||||
// Roughly speaking:
|
||||
// (1) dense_hash_map: fastest, uses the most memory unless entries are small
|
||||
// (2) sparse_hash_map: slowest, uses the least memory
|
||||
// (3) hash_map / unordered_map (STL): in the middle
|
||||
//
|
||||
// Typically I use sparse_hash_map when I care about space and/or when
|
||||
// I need to save the hashtable on disk. I use hash_map otherwise. I
|
||||
// don't personally use dense_hash_set ever; some people use it for
|
||||
// small sets with lots of lookups.
|
||||
//
|
||||
// - dense_hash_map has, typically, about 78% memory overhead (if your
|
||||
// data takes up X bytes, the hash_map uses .78X more bytes in overhead).
|
||||
// - sparse_hash_map has about 4 bits overhead per entry.
|
||||
// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
|
||||
// especially, inserts. See time_hash_map.cc for details.
|
||||
//
|
||||
// See /usr/(local/)?doc/sparsehash-*/dense_hash_map.html
|
||||
// for information about how to use this class.
|
||||
|
||||
#ifndef _DENSE_HASH_MAP_H_
|
||||
#define _DENSE_HASH_MAP_H_
|
||||
|
||||
#include <sparsehash/internal/sparseconfig.h>
|
||||
#include <algorithm> // needed by stl_alloc
|
||||
#include <functional> // for equal_to<>, select1st<>, etc
|
||||
#include <memory> // for alloc
|
||||
#include <utility> // for pair<>
|
||||
#include <sparsehash/internal/densehashtable.h> // IWYU pragma: export
|
||||
#include <sparsehash/internal/libc_allocator_with_realloc.h>
|
||||
#include HASH_FUN_H // for hash<>
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
template <class Key, class T,
|
||||
class HashFcn = SPARSEHASH_HASH<Key>, // defined in sparseconfig.h
|
||||
class EqualKey = std::equal_to<Key>,
|
||||
class Alloc = libc_allocator_with_realloc<std::pair<const Key, T> > >
|
||||
class dense_hash_map {
|
||||
private:
|
||||
// Apparently select1st is not stl-standard, so we define our own
|
||||
struct SelectKey {
|
||||
typedef const Key& result_type;
|
||||
const Key& operator()(const std::pair<const Key, T>& p) const {
|
||||
return p.first;
|
||||
}
|
||||
};
|
||||
struct SetKey {
|
||||
void operator()(std::pair<const Key, T>* value, const Key& new_key) const {
|
||||
*const_cast<Key*>(&value->first) = new_key;
|
||||
// It would be nice to clear the rest of value here as well, in
|
||||
// case it's taking up a lot of memory. We do this by clearing
|
||||
// the value. This assumes T has a zero-arg constructor!
|
||||
value->second = T();
|
||||
}
|
||||
};
|
||||
// For operator[].
|
||||
struct DefaultValue {
|
||||
std::pair<const Key, T> operator()(const Key& key) {
|
||||
return std::make_pair(key, T());
|
||||
}
|
||||
};
|
||||
|
||||
// The actual data
|
||||
typedef dense_hashtable<std::pair<const Key, T>, Key, HashFcn, SelectKey,
|
||||
SetKey, EqualKey, Alloc> ht;
|
||||
ht rep;
|
||||
|
||||
public:
|
||||
typedef typename ht::key_type key_type;
|
||||
typedef T data_type;
|
||||
typedef T mapped_type;
|
||||
typedef typename ht::value_type value_type;
|
||||
typedef typename ht::hasher hasher;
|
||||
typedef typename ht::key_equal key_equal;
|
||||
typedef Alloc allocator_type;
|
||||
|
||||
typedef typename ht::size_type size_type;
|
||||
typedef typename ht::difference_type difference_type;
|
||||
typedef typename ht::pointer pointer;
|
||||
typedef typename ht::const_pointer const_pointer;
|
||||
typedef typename ht::reference reference;
|
||||
typedef typename ht::const_reference const_reference;
|
||||
|
||||
typedef typename ht::iterator iterator;
|
||||
typedef typename ht::const_iterator const_iterator;
|
||||
typedef typename ht::local_iterator local_iterator;
|
||||
typedef typename ht::const_local_iterator const_local_iterator;
|
||||
|
||||
// Iterator functions
|
||||
iterator begin() { return rep.begin(); }
|
||||
iterator end() { return rep.end(); }
|
||||
const_iterator begin() const { return rep.begin(); }
|
||||
const_iterator end() const { return rep.end(); }
|
||||
|
||||
|
||||
// These come from tr1's unordered_map. For us, a bucket has 0 or 1 elements.
|
||||
local_iterator begin(size_type i) { return rep.begin(i); }
|
||||
local_iterator end(size_type i) { return rep.end(i); }
|
||||
const_local_iterator begin(size_type i) const { return rep.begin(i); }
|
||||
const_local_iterator end(size_type i) const { return rep.end(i); }
|
||||
|
||||
// Accessor functions
|
||||
allocator_type get_allocator() const { return rep.get_allocator(); }
|
||||
hasher hash_funct() const { return rep.hash_funct(); }
|
||||
hasher hash_function() const { return hash_funct(); }
|
||||
key_equal key_eq() const { return rep.key_eq(); }
|
||||
|
||||
|
||||
// Constructors
|
||||
explicit dense_hash_map(size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
dense_hash_map(InputIterator f, InputIterator l,
|
||||
const key_type& empty_key_val,
|
||||
size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
|
||||
set_empty_key(empty_key_val);
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// We use the default copy constructor
|
||||
// We use the default operator=()
|
||||
// We use the default destructor
|
||||
|
||||
void clear() { rep.clear(); }
|
||||
// This clears the hash map without resizing it down to the minimum
|
||||
// bucket count, but rather keeps the number of buckets constant
|
||||
void clear_no_resize() { rep.clear_no_resize(); }
|
||||
void swap(dense_hash_map& hs) { rep.swap(hs.rep); }
|
||||
|
||||
|
||||
// Functions concerning size
|
||||
size_type size() const { return rep.size(); }
|
||||
size_type max_size() const { return rep.max_size(); }
|
||||
bool empty() const { return rep.empty(); }
|
||||
size_type bucket_count() const { return rep.bucket_count(); }
|
||||
size_type max_bucket_count() const { return rep.max_bucket_count(); }
|
||||
|
||||
// These are tr1 methods. bucket() is the bucket the key is or would be in.
|
||||
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
|
||||
size_type bucket(const key_type& key) const { return rep.bucket(key); }
|
||||
float load_factor() const {
|
||||
return size() * 1.0f / bucket_count();
|
||||
}
|
||||
float max_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return grow;
|
||||
}
|
||||
void max_load_factor(float new_grow) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(shrink, new_grow);
|
||||
}
|
||||
// These aren't tr1 methods but perhaps ought to be.
|
||||
float min_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return shrink;
|
||||
}
|
||||
void min_load_factor(float new_shrink) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(new_shrink, grow);
|
||||
}
|
||||
// Deprecated; use min_load_factor() or max_load_factor() instead.
|
||||
void set_resizing_parameters(float shrink, float grow) {
|
||||
rep.set_resizing_parameters(shrink, grow);
|
||||
}
|
||||
|
||||
void resize(size_type hint) { rep.resize(hint); }
|
||||
void rehash(size_type hint) { resize(hint); } // the tr1 name
|
||||
|
||||
// Lookup routines
|
||||
iterator find(const key_type& key) { return rep.find(key); }
|
||||
const_iterator find(const key_type& key) const { return rep.find(key); }
|
||||
|
||||
data_type& operator[](const key_type& key) { // This is our value-add!
|
||||
// If key is in the hashtable, returns find(key)->second,
|
||||
// otherwise returns insert(value_type(key, T()).first->second.
|
||||
// Note it does not create an empty T unless the find fails.
|
||||
return rep.template find_or_insert<DefaultValue>(key).second;
|
||||
}
|
||||
|
||||
size_type count(const key_type& key) const { return rep.count(key); }
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type& key) {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
std::pair<const_iterator, const_iterator> equal_range(const key_type& key)
|
||||
const {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
|
||||
|
||||
// Insertion routines
|
||||
std::pair<iterator, bool> insert(const value_type& obj) {
|
||||
return rep.insert(obj);
|
||||
}
|
||||
template <class InputIterator> void insert(InputIterator f, InputIterator l) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
void insert(const_iterator f, const_iterator l) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// Required for std::insert_iterator; the passed-in iterator is ignored.
|
||||
iterator insert(iterator, const value_type& obj) {
|
||||
return insert(obj).first;
|
||||
}
|
||||
|
||||
// Deletion and empty routines
|
||||
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
|
||||
// value to identify deleted and empty buckets. You can change the
|
||||
// deleted key as time goes on, or get rid of it entirely to be insert-only.
|
||||
void set_empty_key(const key_type& key) { // YOU MUST CALL THIS!
|
||||
rep.set_empty_key(value_type(key, data_type())); // rep wants a value
|
||||
}
|
||||
key_type empty_key() const {
|
||||
return rep.empty_key().first; // rep returns a value
|
||||
}
|
||||
|
||||
void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
|
||||
void clear_deleted_key() { rep.clear_deleted_key(); }
|
||||
key_type deleted_key() const { return rep.deleted_key(); }
|
||||
|
||||
// These are standard
|
||||
size_type erase(const key_type& key) { return rep.erase(key); }
|
||||
void erase(iterator it) { rep.erase(it); }
|
||||
void erase(iterator f, iterator l) { rep.erase(f, l); }
|
||||
|
||||
|
||||
// Comparison
|
||||
bool operator==(const dense_hash_map& hs) const { return rep == hs.rep; }
|
||||
bool operator!=(const dense_hash_map& hs) const { return rep != hs.rep; }
|
||||
|
||||
|
||||
// I/O -- this is an add-on for writing hash map to disk
|
||||
//
|
||||
// For maximum flexibility, this does not assume a particular
|
||||
// file type (though it will probably be a FILE *). We just pass
|
||||
// the fp through to rep.
|
||||
|
||||
// If your keys and values are simple enough, you can pass this
|
||||
// serializer to serialize()/unserialize(). "Simple enough" means
|
||||
// value_type is a POD type that contains no pointers. Note,
|
||||
// however, we don't try to normalize endianness.
|
||||
typedef typename ht::NopointerSerializer NopointerSerializer;
|
||||
|
||||
// serializer: a class providing operator()(OUTPUT*, const value_type&)
|
||||
// (writing value_type to OUTPUT). You can specify a
|
||||
// NopointerSerializer object if appropriate (see above).
|
||||
// fp: either a FILE*, OR an ostream*/subclass_of_ostream*, OR a
|
||||
// pointer to a class providing size_t Write(const void*, size_t),
|
||||
// which writes a buffer into a stream (which fp presumably
|
||||
// owns) and returns the number of bytes successfully written.
|
||||
// Note basic_ostream<not_char> is not currently supported.
|
||||
template <typename ValueSerializer, typename OUTPUT>
|
||||
bool serialize(ValueSerializer serializer, OUTPUT* fp) {
|
||||
return rep.serialize(serializer, fp);
|
||||
}
|
||||
|
||||
// serializer: a functor providing operator()(INPUT*, value_type*)
|
||||
// (reading from INPUT and into value_type). You can specify a
|
||||
// NopointerSerializer object if appropriate (see above).
|
||||
// fp: either a FILE*, OR an istream*/subclass_of_istream*, OR a
|
||||
// pointer to a class providing size_t Read(void*, size_t),
|
||||
// which reads into a buffer from a stream (which fp presumably
|
||||
// owns) and returns the number of bytes successfully read.
|
||||
// Note basic_istream<not_char> is not currently supported.
|
||||
// NOTE: Since value_type is std::pair<const Key, T>, ValueSerializer
|
||||
// may need to do a const cast in order to fill in the key.
|
||||
template <typename ValueSerializer, typename INPUT>
|
||||
bool unserialize(ValueSerializer serializer, INPUT* fp) {
|
||||
return rep.unserialize(serializer, fp);
|
||||
}
|
||||
};
|
||||
|
||||
// We need a global swap as well
|
||||
template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
|
||||
inline void swap(dense_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm1,
|
||||
dense_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm2) {
|
||||
hm1.swap(hm2);
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif /* _DENSE_HASH_MAP_H_ */
|
338
contrib/libsparsehash/sparsehash/dense_hash_set
Normal file
338
contrib/libsparsehash/sparsehash/dense_hash_set
Normal file
@ -0,0 +1,338 @@
|
||||
// Copyright (c) 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
//
|
||||
// This is just a very thin wrapper over densehashtable.h, just
|
||||
// like sgi stl's stl_hash_set is a very thin wrapper over
|
||||
// stl_hashtable. The major thing we define is operator[], because
|
||||
// we have a concept of a data_type which stl_hashtable doesn't
|
||||
// (it only has a key and a value).
|
||||
//
|
||||
// This is more different from dense_hash_map than you might think,
|
||||
// because all iterators for sets are const (you obviously can't
|
||||
// change the key, and for sets there is no value).
|
||||
//
|
||||
// NOTE: this is exactly like sparse_hash_set.h, with the word
|
||||
// "sparse" replaced by "dense", except for the addition of
|
||||
// set_empty_key().
|
||||
//
|
||||
// YOU MUST CALL SET_EMPTY_KEY() IMMEDIATELY AFTER CONSTRUCTION.
|
||||
//
|
||||
// Otherwise your program will die in mysterious ways. (Note if you
|
||||
// use the constructor that takes an InputIterator range, you pass in
|
||||
// the empty key in the constructor, rather than after. As a result,
|
||||
// this constructor differs from the standard STL version.)
|
||||
//
|
||||
// In other respects, we adhere mostly to the STL semantics for
|
||||
// hash-map. One important exception is that insert() may invalidate
|
||||
// iterators entirely -- STL semantics are that insert() may reorder
|
||||
// iterators, but they all still refer to something valid in the
|
||||
// hashtable. Not so for us. Likewise, insert() may invalidate
|
||||
// pointers into the hashtable. (Whether insert invalidates iterators
|
||||
// and pointers depends on whether it results in a hashtable resize).
|
||||
// On the plus side, delete() doesn't invalidate iterators or pointers
|
||||
// at all, or even change the ordering of elements.
|
||||
//
|
||||
// Here are a few "power user" tips:
|
||||
//
|
||||
// 1) set_deleted_key():
|
||||
// If you want to use erase() you must call set_deleted_key(),
|
||||
// in addition to set_empty_key(), after construction.
|
||||
// The deleted and empty keys must differ.
|
||||
//
|
||||
// 2) resize(0):
|
||||
// When an item is deleted, its memory isn't freed right
|
||||
// away. This allows you to iterate over a hashtable,
|
||||
// and call erase(), without invalidating the iterator.
|
||||
// To force the memory to be freed, call resize(0).
|
||||
// For tr1 compatibility, this can also be called as rehash(0).
|
||||
//
|
||||
// 3) min_load_factor(0.0)
|
||||
// Setting the minimum load factor to 0.0 guarantees that
|
||||
// the hash table will never shrink.
|
||||
//
|
||||
// Roughly speaking:
|
||||
// (1) dense_hash_set: fastest, uses the most memory unless entries are small
|
||||
// (2) sparse_hash_set: slowest, uses the least memory
|
||||
// (3) hash_set / unordered_set (STL): in the middle
|
||||
//
|
||||
// Typically I use sparse_hash_set when I care about space and/or when
|
||||
// I need to save the hashtable on disk. I use hash_set otherwise. I
|
||||
// don't personally use dense_hash_set ever; some people use it for
|
||||
// small sets with lots of lookups.
|
||||
//
|
||||
// - dense_hash_set has, typically, about 78% memory overhead (if your
|
||||
// data takes up X bytes, the hash_set uses .78X more bytes in overhead).
|
||||
// - sparse_hash_set has about 4 bits overhead per entry.
|
||||
// - sparse_hash_set can be 3-7 times slower than the others for lookup and,
|
||||
// especially, inserts. See time_hash_map.cc for details.
|
||||
//
|
||||
// See /usr/(local/)?doc/sparsehash-*/dense_hash_set.html
|
||||
// for information about how to use this class.
|
||||
|
||||
#ifndef _DENSE_HASH_SET_H_
|
||||
#define _DENSE_HASH_SET_H_
|
||||
|
||||
#include <sparsehash/internal/sparseconfig.h>
|
||||
#include <algorithm> // needed by stl_alloc
|
||||
#include <functional> // for equal_to<>, select1st<>, etc
|
||||
#include <memory> // for alloc
|
||||
#include <utility> // for pair<>
|
||||
#include <sparsehash/internal/densehashtable.h> // IWYU pragma: export
|
||||
#include <sparsehash/internal/libc_allocator_with_realloc.h>
|
||||
#include HASH_FUN_H // for hash<>
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
template <class Value,
|
||||
class HashFcn = SPARSEHASH_HASH<Value>, // defined in sparseconfig.h
|
||||
class EqualKey = std::equal_to<Value>,
|
||||
class Alloc = libc_allocator_with_realloc<Value> >
|
||||
class dense_hash_set {
|
||||
private:
|
||||
// Apparently identity is not stl-standard, so we define our own
|
||||
struct Identity {
|
||||
typedef const Value& result_type;
|
||||
const Value& operator()(const Value& v) const { return v; }
|
||||
};
|
||||
struct SetKey {
|
||||
void operator()(Value* value, const Value& new_key) const {
|
||||
*value = new_key;
|
||||
}
|
||||
};
|
||||
|
||||
// The actual data
|
||||
typedef dense_hashtable<Value, Value, HashFcn, Identity, SetKey,
|
||||
EqualKey, Alloc> ht;
|
||||
ht rep;
|
||||
|
||||
public:
|
||||
typedef typename ht::key_type key_type;
|
||||
typedef typename ht::value_type value_type;
|
||||
typedef typename ht::hasher hasher;
|
||||
typedef typename ht::key_equal key_equal;
|
||||
typedef Alloc allocator_type;
|
||||
|
||||
typedef typename ht::size_type size_type;
|
||||
typedef typename ht::difference_type difference_type;
|
||||
typedef typename ht::const_pointer pointer;
|
||||
typedef typename ht::const_pointer const_pointer;
|
||||
typedef typename ht::const_reference reference;
|
||||
typedef typename ht::const_reference const_reference;
|
||||
|
||||
typedef typename ht::const_iterator iterator;
|
||||
typedef typename ht::const_iterator const_iterator;
|
||||
typedef typename ht::const_local_iterator local_iterator;
|
||||
typedef typename ht::const_local_iterator const_local_iterator;
|
||||
|
||||
|
||||
// Iterator functions -- recall all iterators are const
|
||||
iterator begin() const { return rep.begin(); }
|
||||
iterator end() const { return rep.end(); }
|
||||
|
||||
// These come from tr1's unordered_set. For us, a bucket has 0 or 1 elements.
|
||||
local_iterator begin(size_type i) const { return rep.begin(i); }
|
||||
local_iterator end(size_type i) const { return rep.end(i); }
|
||||
|
||||
|
||||
// Accessor functions
|
||||
allocator_type get_allocator() const { return rep.get_allocator(); }
|
||||
hasher hash_funct() const { return rep.hash_funct(); }
|
||||
hasher hash_function() const { return hash_funct(); } // tr1 name
|
||||
key_equal key_eq() const { return rep.key_eq(); }
|
||||
|
||||
|
||||
// Constructors
|
||||
explicit dense_hash_set(size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
dense_hash_set(InputIterator f, InputIterator l,
|
||||
const key_type& empty_key_val,
|
||||
size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
|
||||
set_empty_key(empty_key_val);
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// We use the default copy constructor
|
||||
// We use the default operator=()
|
||||
// We use the default destructor
|
||||
|
||||
void clear() { rep.clear(); }
|
||||
// This clears the hash set without resizing it down to the minimum
|
||||
// bucket count, but rather keeps the number of buckets constant
|
||||
void clear_no_resize() { rep.clear_no_resize(); }
|
||||
void swap(dense_hash_set& hs) { rep.swap(hs.rep); }
|
||||
|
||||
|
||||
// Functions concerning size
|
||||
size_type size() const { return rep.size(); }
|
||||
size_type max_size() const { return rep.max_size(); }
|
||||
bool empty() const { return rep.empty(); }
|
||||
size_type bucket_count() const { return rep.bucket_count(); }
|
||||
size_type max_bucket_count() const { return rep.max_bucket_count(); }
|
||||
|
||||
// These are tr1 methods. bucket() is the bucket the key is or would be in.
|
||||
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
|
||||
size_type bucket(const key_type& key) const { return rep.bucket(key); }
|
||||
float load_factor() const {
|
||||
return size() * 1.0f / bucket_count();
|
||||
}
|
||||
float max_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return grow;
|
||||
}
|
||||
void max_load_factor(float new_grow) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(shrink, new_grow);
|
||||
}
|
||||
// These aren't tr1 methods but perhaps ought to be.
|
||||
float min_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return shrink;
|
||||
}
|
||||
void min_load_factor(float new_shrink) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(new_shrink, grow);
|
||||
}
|
||||
// Deprecated; use min_load_factor() or max_load_factor() instead.
|
||||
void set_resizing_parameters(float shrink, float grow) {
|
||||
rep.set_resizing_parameters(shrink, grow);
|
||||
}
|
||||
|
||||
void resize(size_type hint) { rep.resize(hint); }
|
||||
void rehash(size_type hint) { resize(hint); } // the tr1 name
|
||||
|
||||
// Lookup routines
|
||||
iterator find(const key_type& key) const { return rep.find(key); }
|
||||
|
||||
size_type count(const key_type& key) const { return rep.count(key); }
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type& key) const {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
|
||||
|
||||
// Insertion routines
|
||||
std::pair<iterator, bool> insert(const value_type& obj) {
|
||||
std::pair<typename ht::iterator, bool> p = rep.insert(obj);
|
||||
return std::pair<iterator, bool>(p.first, p.second); // const to non-const
|
||||
}
|
||||
template <class InputIterator> void insert(InputIterator f, InputIterator l) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
void insert(const_iterator f, const_iterator l) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// Required for std::insert_iterator; the passed-in iterator is ignored.
|
||||
iterator insert(iterator, const value_type& obj) {
|
||||
return insert(obj).first;
|
||||
}
|
||||
|
||||
// Deletion and empty routines
|
||||
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
|
||||
// value to identify deleted and empty buckets. You can change the
|
||||
// deleted key as time goes on, or get rid of it entirely to be insert-only.
|
||||
void set_empty_key(const key_type& key) { rep.set_empty_key(key); }
|
||||
key_type empty_key() const { return rep.empty_key(); }
|
||||
|
||||
void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
|
||||
void clear_deleted_key() { rep.clear_deleted_key(); }
|
||||
key_type deleted_key() const { return rep.deleted_key(); }
|
||||
|
||||
// These are standard
|
||||
size_type erase(const key_type& key) { return rep.erase(key); }
|
||||
void erase(iterator it) { rep.erase(it); }
|
||||
void erase(iterator f, iterator l) { rep.erase(f, l); }
|
||||
|
||||
|
||||
// Comparison
|
||||
bool operator==(const dense_hash_set& hs) const { return rep == hs.rep; }
|
||||
bool operator!=(const dense_hash_set& hs) const { return rep != hs.rep; }
|
||||
|
||||
|
||||
// I/O -- this is an add-on for writing metainformation to disk
|
||||
//
|
||||
// For maximum flexibility, this does not assume a particular
|
||||
// file type (though it will probably be a FILE *). We just pass
|
||||
// the fp through to rep.
|
||||
|
||||
// If your keys and values are simple enough, you can pass this
|
||||
// serializer to serialize()/unserialize(). "Simple enough" means
|
||||
// value_type is a POD type that contains no pointers. Note,
|
||||
// however, we don't try to normalize endianness.
|
||||
typedef typename ht::NopointerSerializer NopointerSerializer;
|
||||
|
||||
// serializer: a class providing operator()(OUTPUT*, const value_type&)
|
||||
// (writing value_type to OUTPUT). You can specify a
|
||||
// NopointerSerializer object if appropriate (see above).
|
||||
// fp: either a FILE*, OR an ostream*/subclass_of_ostream*, OR a
|
||||
// pointer to a class providing size_t Write(const void*, size_t),
|
||||
// which writes a buffer into a stream (which fp presumably
|
||||
// owns) and returns the number of bytes successfully written.
|
||||
// Note basic_ostream<not_char> is not currently supported.
|
||||
template <typename ValueSerializer, typename OUTPUT>
|
||||
bool serialize(ValueSerializer serializer, OUTPUT* fp) {
|
||||
return rep.serialize(serializer, fp);
|
||||
}
|
||||
|
||||
// serializer: a functor providing operator()(INPUT*, value_type*)
|
||||
// (reading from INPUT and into value_type). You can specify a
|
||||
// NopointerSerializer object if appropriate (see above).
|
||||
// fp: either a FILE*, OR an istream*/subclass_of_istream*, OR a
|
||||
// pointer to a class providing size_t Read(void*, size_t),
|
||||
// which reads into a buffer from a stream (which fp presumably
|
||||
// owns) and returns the number of bytes successfully read.
|
||||
// Note basic_istream<not_char> is not currently supported.
|
||||
template <typename ValueSerializer, typename INPUT>
|
||||
bool unserialize(ValueSerializer serializer, INPUT* fp) {
|
||||
return rep.unserialize(serializer, fp);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Val, class HashFcn, class EqualKey, class Alloc>
|
||||
inline void swap(dense_hash_set<Val, HashFcn, EqualKey, Alloc>& hs1,
|
||||
dense_hash_set<Val, HashFcn, EqualKey, Alloc>& hs2) {
|
||||
hs1.swap(hs2);
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif /* _DENSE_HASH_SET_H_ */
|
1319
contrib/libsparsehash/sparsehash/internal/densehashtable.h
Normal file
1319
contrib/libsparsehash/sparsehash/internal/densehashtable.h
Normal file
File diff suppressed because it is too large
Load Diff
381
contrib/libsparsehash/sparsehash/internal/hashtable-common.h
Normal file
381
contrib/libsparsehash/sparsehash/internal/hashtable-common.h
Normal file
@ -0,0 +1,381 @@
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
//
|
||||
// Provides classes shared by both sparse and dense hashtable.
|
||||
//
|
||||
// sh_hashtable_settings has parameters for growing and shrinking
|
||||
// a hashtable. It also packages zero-size functor (ie. hasher).
|
||||
//
|
||||
// Other functions and classes provide common code for serializing
|
||||
// and deserializing hashtables to a stream (such as a FILE*).
|
||||
|
||||
#ifndef UTIL_GTL_HASHTABLE_COMMON_H_
|
||||
#define UTIL_GTL_HASHTABLE_COMMON_H_
|
||||
|
||||
#include <sparsehash/internal/sparseconfig.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h> // for size_t
|
||||
#include <iosfwd>
|
||||
#include <stdexcept> // For length_error
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
template <bool> struct SparsehashCompileAssert { };
|
||||
#define SPARSEHASH_COMPILE_ASSERT(expr, msg) \
|
||||
typedef SparsehashCompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
|
||||
|
||||
namespace sparsehash_internal {
|
||||
|
||||
// Adaptor methods for reading/writing data from an INPUT or OUPTUT
|
||||
// variable passed to serialize() or unserialize(). For now we
|
||||
// have implemented INPUT/OUTPUT for FILE*, istream*/ostream* (note
|
||||
// they are pointers, unlike typical use), or else a pointer to
|
||||
// something that supports a Read()/Write() method.
|
||||
//
|
||||
// For technical reasons, we implement read_data/write_data in two
|
||||
// stages. The actual work is done in *_data_internal, which takes
|
||||
// the stream argument twice: once as a template type, and once with
|
||||
// normal type information. (We only use the second version.) We do
|
||||
// this because of how C++ picks what function overload to use. If we
|
||||
// implemented this the naive way:
|
||||
// bool read_data(istream* is, const void* data, size_t length);
|
||||
// template<typename T> read_data(T* fp, const void* data, size_t length);
|
||||
// C++ would prefer the second version for every stream type except
|
||||
// istream. However, we want C++ to prefer the first version for
|
||||
// streams that are *subclasses* of istream, such as istringstream.
|
||||
// This is not possible given the way template types are resolved. So
|
||||
// we split the stream argument in two, one of which is templated and
|
||||
// one of which is not. The specialized functions (like the istream
|
||||
// version above) ignore the template arg and use the second, 'type'
|
||||
// arg, getting subclass matching as normal. The 'catch-all'
|
||||
// functions (the second version above) use the template arg to deduce
|
||||
// the type, and use a second, void* arg to achieve the desired
|
||||
// 'catch-all' semantics.
|
||||
|
||||
// ----- low-level I/O for FILE* ----
|
||||
|
||||
template<typename Ignored>
|
||||
inline bool read_data_internal(Ignored*, FILE* fp,
|
||||
void* data, size_t length) {
|
||||
return fread(data, length, 1, fp) == 1;
|
||||
}
|
||||
|
||||
template<typename Ignored>
|
||||
inline bool write_data_internal(Ignored*, FILE* fp,
|
||||
const void* data, size_t length) {
|
||||
return fwrite(data, length, 1, fp) == 1;
|
||||
}
|
||||
|
||||
// ----- low-level I/O for iostream ----
|
||||
|
||||
// We want the caller to be responsible for #including <iostream>, not
|
||||
// us, because iostream is a big header! According to the standard,
|
||||
// it's only legal to delay the instantiation the way we want to if
|
||||
// the istream/ostream is a template type. So we jump through hoops.
|
||||
template<typename ISTREAM>
|
||||
inline bool read_data_internal_for_istream(ISTREAM* fp,
|
||||
void* data, size_t length) {
|
||||
return fp->read(reinterpret_cast<char*>(data), length).good();
|
||||
}
|
||||
template<typename Ignored>
|
||||
inline bool read_data_internal(Ignored*, std::istream* fp,
|
||||
void* data, size_t length) {
|
||||
return read_data_internal_for_istream(fp, data, length);
|
||||
}
|
||||
|
||||
template<typename OSTREAM>
|
||||
inline bool write_data_internal_for_ostream(OSTREAM* fp,
|
||||
const void* data, size_t length) {
|
||||
return fp->write(reinterpret_cast<const char*>(data), length).good();
|
||||
}
|
||||
template<typename Ignored>
|
||||
inline bool write_data_internal(Ignored*, std::ostream* fp,
|
||||
const void* data, size_t length) {
|
||||
return write_data_internal_for_ostream(fp, data, length);
|
||||
}
|
||||
|
||||
// ----- low-level I/O for custom streams ----
|
||||
|
||||
// The INPUT type needs to support a Read() method that takes a
|
||||
// buffer and a length and returns the number of bytes read.
|
||||
template <typename INPUT>
|
||||
inline bool read_data_internal(INPUT* fp, void*,
|
||||
void* data, size_t length) {
|
||||
return static_cast<size_t>(fp->Read(data, length)) == length;
|
||||
}
|
||||
|
||||
// The OUTPUT type needs to support a Write() operation that takes
|
||||
// a buffer and a length and returns the number of bytes written.
|
||||
template <typename OUTPUT>
|
||||
inline bool write_data_internal(OUTPUT* fp, void*,
|
||||
const void* data, size_t length) {
|
||||
return static_cast<size_t>(fp->Write(data, length)) == length;
|
||||
}
|
||||
|
||||
// ----- low-level I/O: the public API ----
|
||||
|
||||
template <typename INPUT>
|
||||
inline bool read_data(INPUT* fp, void* data, size_t length) {
|
||||
return read_data_internal(fp, fp, data, length);
|
||||
}
|
||||
|
||||
template <typename OUTPUT>
|
||||
inline bool write_data(OUTPUT* fp, const void* data, size_t length) {
|
||||
return write_data_internal(fp, fp, data, length);
|
||||
}
|
||||
|
||||
// Uses read_data() and write_data() to read/write an integer.
|
||||
// length is the number of bytes to read/write (which may differ
|
||||
// from sizeof(IntType), allowing us to save on a 32-bit system
|
||||
// and load on a 64-bit system). Excess bytes are taken to be 0.
|
||||
// INPUT and OUTPUT must match legal inputs to read/write_data (above).
|
||||
template <typename INPUT, typename IntType>
|
||||
bool read_bigendian_number(INPUT* fp, IntType* value, size_t length) {
|
||||
*value = 0;
|
||||
unsigned char byte;
|
||||
// We require IntType to be unsigned or else the shifting gets all screwy.
|
||||
SPARSEHASH_COMPILE_ASSERT(static_cast<IntType>(-1) > static_cast<IntType>(0),
|
||||
serializing_int_requires_an_unsigned_type);
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
if (!read_data(fp, &byte, sizeof(byte))) return false;
|
||||
*value |= static_cast<IntType>(byte) << ((length - 1 - i) * 8);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename OUTPUT, typename IntType>
|
||||
bool write_bigendian_number(OUTPUT* fp, IntType value, size_t length) {
|
||||
unsigned char byte;
|
||||
// We require IntType to be unsigned or else the shifting gets all screwy.
|
||||
SPARSEHASH_COMPILE_ASSERT(static_cast<IntType>(-1) > static_cast<IntType>(0),
|
||||
serializing_int_requires_an_unsigned_type);
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
byte = (sizeof(value) <= length-1 - i)
|
||||
? 0 : static_cast<unsigned char>((value >> ((length-1 - i) * 8)) & 255);
|
||||
if (!write_data(fp, &byte, sizeof(byte))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// If your keys and values are simple enough, you can pass this
|
||||
// serializer to serialize()/unserialize(). "Simple enough" means
|
||||
// value_type is a POD type that contains no pointers. Note,
|
||||
// however, we don't try to normalize endianness.
|
||||
// This is the type used for NopointerSerializer.
|
||||
template <typename value_type> struct pod_serializer {
|
||||
template <typename INPUT>
|
||||
bool operator()(INPUT* fp, value_type* value) const {
|
||||
return read_data(fp, value, sizeof(*value));
|
||||
}
|
||||
|
||||
template <typename OUTPUT>
|
||||
bool operator()(OUTPUT* fp, const value_type& value) const {
|
||||
return write_data(fp, &value, sizeof(value));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Settings contains parameters for growing and shrinking the table.
|
||||
// It also packages zero-size functor (ie. hasher).
|
||||
//
|
||||
// It does some munging of the hash value in cases where we think
|
||||
// (fear) the original hash function might not be very good. In
|
||||
// particular, the default hash of pointers is the identity hash,
|
||||
// so probably all the low bits are 0. We identify when we think
|
||||
// we're hashing a pointer, and chop off the low bits. Note this
|
||||
// isn't perfect: even when the key is a pointer, we can't tell
|
||||
// for sure that the hash is the identity hash. If it's not, this
|
||||
// is needless work (and possibly, though not likely, harmful).
|
||||
|
||||
template<typename Key, typename HashFunc,
|
||||
typename SizeType, int HT_MIN_BUCKETS>
|
||||
class sh_hashtable_settings : public HashFunc {
|
||||
public:
|
||||
typedef Key key_type;
|
||||
typedef HashFunc hasher;
|
||||
typedef SizeType size_type;
|
||||
|
||||
public:
|
||||
sh_hashtable_settings(const hasher& hf,
|
||||
const float ht_occupancy_flt,
|
||||
const float ht_empty_flt)
|
||||
: hasher(hf),
|
||||
enlarge_threshold_(0),
|
||||
shrink_threshold_(0),
|
||||
consider_shrink_(false),
|
||||
use_empty_(false),
|
||||
use_deleted_(false),
|
||||
num_ht_copies_(0) {
|
||||
set_enlarge_factor(ht_occupancy_flt);
|
||||
set_shrink_factor(ht_empty_flt);
|
||||
}
|
||||
|
||||
size_type hash(const key_type& v) const {
|
||||
// We munge the hash value when we don't trust hasher::operator().
|
||||
return hash_munger<Key>::MungedHash(hasher::operator()(v));
|
||||
}
|
||||
|
||||
float enlarge_factor() const {
|
||||
return enlarge_factor_;
|
||||
}
|
||||
void set_enlarge_factor(float f) {
|
||||
enlarge_factor_ = f;
|
||||
}
|
||||
float shrink_factor() const {
|
||||
return shrink_factor_;
|
||||
}
|
||||
void set_shrink_factor(float f) {
|
||||
shrink_factor_ = f;
|
||||
}
|
||||
|
||||
size_type enlarge_threshold() const {
|
||||
return enlarge_threshold_;
|
||||
}
|
||||
void set_enlarge_threshold(size_type t) {
|
||||
enlarge_threshold_ = t;
|
||||
}
|
||||
size_type shrink_threshold() const {
|
||||
return shrink_threshold_;
|
||||
}
|
||||
void set_shrink_threshold(size_type t) {
|
||||
shrink_threshold_ = t;
|
||||
}
|
||||
|
||||
size_type enlarge_size(size_type x) const {
|
||||
return static_cast<size_type>(x * enlarge_factor_);
|
||||
}
|
||||
size_type shrink_size(size_type x) const {
|
||||
return static_cast<size_type>(x * shrink_factor_);
|
||||
}
|
||||
|
||||
bool consider_shrink() const {
|
||||
return consider_shrink_;
|
||||
}
|
||||
void set_consider_shrink(bool t) {
|
||||
consider_shrink_ = t;
|
||||
}
|
||||
|
||||
bool use_empty() const {
|
||||
return use_empty_;
|
||||
}
|
||||
void set_use_empty(bool t) {
|
||||
use_empty_ = t;
|
||||
}
|
||||
|
||||
bool use_deleted() const {
|
||||
return use_deleted_;
|
||||
}
|
||||
void set_use_deleted(bool t) {
|
||||
use_deleted_ = t;
|
||||
}
|
||||
|
||||
size_type num_ht_copies() const {
|
||||
return static_cast<size_type>(num_ht_copies_);
|
||||
}
|
||||
void inc_num_ht_copies() {
|
||||
++num_ht_copies_;
|
||||
}
|
||||
|
||||
// Reset the enlarge and shrink thresholds
|
||||
void reset_thresholds(size_type num_buckets) {
|
||||
set_enlarge_threshold(enlarge_size(num_buckets));
|
||||
set_shrink_threshold(shrink_size(num_buckets));
|
||||
// whatever caused us to reset already considered
|
||||
set_consider_shrink(false);
|
||||
}
|
||||
|
||||
// Caller is resposible for calling reset_threshold right after
|
||||
// set_resizing_parameters.
|
||||
void set_resizing_parameters(float shrink, float grow) {
|
||||
assert(shrink >= 0.0);
|
||||
assert(grow <= 1.0);
|
||||
if (shrink > grow/2.0f)
|
||||
shrink = grow / 2.0f; // otherwise we thrash hashtable size
|
||||
set_shrink_factor(shrink);
|
||||
set_enlarge_factor(grow);
|
||||
}
|
||||
|
||||
// This is the smallest size a hashtable can be without being too crowded
|
||||
// If you like, you can give a min #buckets as well as a min #elts
|
||||
size_type min_buckets(size_type num_elts, size_type min_buckets_wanted) {
|
||||
float enlarge = enlarge_factor();
|
||||
size_type sz = HT_MIN_BUCKETS; // min buckets allowed
|
||||
while ( sz < min_buckets_wanted ||
|
||||
num_elts >= static_cast<size_type>(sz * enlarge) ) {
|
||||
// This just prevents overflowing size_type, since sz can exceed
|
||||
// max_size() here.
|
||||
if (static_cast<size_type>(sz * 2) < sz) {
|
||||
throw std::length_error("resize overflow"); // protect against overflow
|
||||
}
|
||||
sz *= 2;
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
private:
|
||||
template<class HashKey> class hash_munger {
|
||||
public:
|
||||
static size_t MungedHash(size_t hash) {
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
// This matches when the hashtable key is a pointer.
|
||||
template<class HashKey> class hash_munger<HashKey*> {
|
||||
public:
|
||||
static size_t MungedHash(size_t hash) {
|
||||
// TODO(csilvers): consider rotating instead:
|
||||
// static const int shift = (sizeof(void *) == 4) ? 2 : 3;
|
||||
// return (hash << (sizeof(hash) * 8) - shift)) | (hash >> shift);
|
||||
// This matters if we ever change sparse/dense_hash_* to compare
|
||||
// hashes before comparing actual values. It's speedy on x86.
|
||||
return hash / sizeof(void*); // get rid of known-0 bits
|
||||
}
|
||||
};
|
||||
|
||||
size_type enlarge_threshold_; // table.size() * enlarge_factor
|
||||
size_type shrink_threshold_; // table.size() * shrink_factor
|
||||
float enlarge_factor_; // how full before resize
|
||||
float shrink_factor_; // how empty before resize
|
||||
// consider_shrink=true if we should try to shrink before next insert
|
||||
bool consider_shrink_;
|
||||
bool use_empty_; // used only by densehashtable, not sparsehashtable
|
||||
bool use_deleted_; // false until delkey has been set
|
||||
// num_ht_copies is a counter incremented every Copy/Move
|
||||
unsigned int num_ht_copies_;
|
||||
};
|
||||
|
||||
} // namespace sparsehash_internal
|
||||
|
||||
#undef SPARSEHASH_COMPILE_ASSERT
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif // UTIL_GTL_HASHTABLE_COMMON_H_
|
@ -0,0 +1,119 @@
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
|
||||
#ifndef UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_
|
||||
#define UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_
|
||||
|
||||
#include <sparsehash/internal/sparseconfig.h>
|
||||
#include <stdlib.h> // for malloc/realloc/free
|
||||
#include <stddef.h> // for ptrdiff_t
|
||||
#include <new> // for placement new
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
template<class T>
|
||||
class libc_allocator_with_realloc {
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
|
||||
libc_allocator_with_realloc() {}
|
||||
libc_allocator_with_realloc(const libc_allocator_with_realloc&) {}
|
||||
~libc_allocator_with_realloc() {}
|
||||
|
||||
pointer address(reference r) const { return &r; }
|
||||
const_pointer address(const_reference r) const { return &r; }
|
||||
|
||||
pointer allocate(size_type n, const_pointer = 0) {
|
||||
return static_cast<pointer>(malloc(n * sizeof(value_type)));
|
||||
}
|
||||
void deallocate(pointer p, size_type) {
|
||||
free(p);
|
||||
}
|
||||
pointer reallocate(pointer p, size_type n) {
|
||||
return static_cast<pointer>(realloc(p, n * sizeof(value_type)));
|
||||
}
|
||||
|
||||
size_type max_size() const {
|
||||
return static_cast<size_type>(-1) / sizeof(value_type);
|
||||
}
|
||||
|
||||
void construct(pointer p, const value_type& val) {
|
||||
new(p) value_type(val);
|
||||
}
|
||||
void destroy(pointer p) { p->~value_type(); }
|
||||
|
||||
template <class U>
|
||||
libc_allocator_with_realloc(const libc_allocator_with_realloc<U>&) {}
|
||||
|
||||
template<class U>
|
||||
struct rebind {
|
||||
typedef libc_allocator_with_realloc<U> other;
|
||||
};
|
||||
};
|
||||
|
||||
// libc_allocator_with_realloc<void> specialization.
|
||||
template<>
|
||||
class libc_allocator_with_realloc<void> {
|
||||
public:
|
||||
typedef void value_type;
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
|
||||
template<class U>
|
||||
struct rebind {
|
||||
typedef libc_allocator_with_realloc<U> other;
|
||||
};
|
||||
};
|
||||
|
||||
template<class T>
|
||||
inline bool operator==(const libc_allocator_with_realloc<T>&,
|
||||
const libc_allocator_with_realloc<T>&) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline bool operator!=(const libc_allocator_with_realloc<T>&,
|
||||
const libc_allocator_with_realloc<T>&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif // UTIL_GTL_LIBC_ALLOCATOR_WITH_REALLOC_H_
|
46
contrib/libsparsehash/sparsehash/internal/sparseconfig.h
Normal file
46
contrib/libsparsehash/sparsehash/internal/sparseconfig.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* NOTE: This file is for internal use only.
|
||||
* Do not use these #defines in your own program!
|
||||
*/
|
||||
|
||||
/* Namespace for Google classes */
|
||||
#define GOOGLE_NAMESPACE ::google
|
||||
|
||||
/* the location of the header defining hash functions */
|
||||
#define HASH_FUN_H <functional>
|
||||
|
||||
/* the namespace of the hash<> function */
|
||||
#define HASH_NAMESPACE std
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `long long'. */
|
||||
#define HAVE_LONG_LONG 1
|
||||
|
||||
/* Define to 1 if you have the `memcpy' function. */
|
||||
#define HAVE_MEMCPY 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `uint16_t'. */
|
||||
#define HAVE_UINT16_T 1
|
||||
|
||||
/* Define to 1 if the system has the type `u_int16_t'. */
|
||||
#define HAVE_U_INT16_T 1
|
||||
|
||||
/* Define to 1 if the system has the type `__uint16'. */
|
||||
/* #undef HAVE___UINT16 */
|
||||
|
||||
/* The system-provided hash function including the namespace. */
|
||||
#define SPARSEHASH_HASH HASH_NAMESPACE::hash
|
||||
|
||||
/* Stops putting the code inside the Google namespace */
|
||||
#define _END_GOOGLE_NAMESPACE_ }
|
||||
|
||||
/* Puts following code inside the Google namespace */
|
||||
#define _START_GOOGLE_NAMESPACE_ namespace google {
|
1247
contrib/libsparsehash/sparsehash/internal/sparsehashtable.h
Normal file
1247
contrib/libsparsehash/sparsehash/internal/sparsehashtable.h
Normal file
File diff suppressed because it is too large
Load Diff
363
contrib/libsparsehash/sparsehash/sparse_hash_map
Normal file
363
contrib/libsparsehash/sparsehash/sparse_hash_map
Normal file
@ -0,0 +1,363 @@
|
||||
// Copyright (c) 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
//
|
||||
// This is just a very thin wrapper over sparsehashtable.h, just
|
||||
// like sgi stl's stl_hash_map is a very thin wrapper over
|
||||
// stl_hashtable. The major thing we define is operator[], because
|
||||
// we have a concept of a data_type which stl_hashtable doesn't
|
||||
// (it only has a key and a value).
|
||||
//
|
||||
// We adhere mostly to the STL semantics for hash-map. One important
|
||||
// exception is that insert() may invalidate iterators entirely -- STL
|
||||
// semantics are that insert() may reorder iterators, but they all
|
||||
// still refer to something valid in the hashtable. Not so for us.
|
||||
// Likewise, insert() may invalidate pointers into the hashtable.
|
||||
// (Whether insert invalidates iterators and pointers depends on
|
||||
// whether it results in a hashtable resize). On the plus side,
|
||||
// delete() doesn't invalidate iterators or pointers at all, or even
|
||||
// change the ordering of elements.
|
||||
//
|
||||
// Here are a few "power user" tips:
|
||||
//
|
||||
// 1) set_deleted_key():
|
||||
// Unlike STL's hash_map, if you want to use erase() you
|
||||
// *must* call set_deleted_key() after construction.
|
||||
//
|
||||
// 2) resize(0):
|
||||
// When an item is deleted, its memory isn't freed right
|
||||
// away. This is what allows you to iterate over a hashtable
|
||||
// and call erase() without invalidating the iterator.
|
||||
// To force the memory to be freed, call resize(0).
|
||||
// For tr1 compatibility, this can also be called as rehash(0).
|
||||
//
|
||||
// 3) min_load_factor(0.0)
|
||||
// Setting the minimum load factor to 0.0 guarantees that
|
||||
// the hash table will never shrink.
|
||||
//
|
||||
// Roughly speaking:
|
||||
// (1) dense_hash_map: fastest, uses the most memory unless entries are small
|
||||
// (2) sparse_hash_map: slowest, uses the least memory
|
||||
// (3) hash_map / unordered_map (STL): in the middle
|
||||
//
|
||||
// Typically I use sparse_hash_map when I care about space and/or when
|
||||
// I need to save the hashtable on disk. I use hash_map otherwise. I
|
||||
// don't personally use dense_hash_map ever; some people use it for
|
||||
// small maps with lots of lookups.
|
||||
//
|
||||
// - dense_hash_map has, typically, about 78% memory overhead (if your
|
||||
// data takes up X bytes, the hash_map uses .78X more bytes in overhead).
|
||||
// - sparse_hash_map has about 4 bits overhead per entry.
|
||||
// - sparse_hash_map can be 3-7 times slower than the others for lookup and,
|
||||
// especially, inserts. See time_hash_map.cc for details.
|
||||
//
|
||||
// See /usr/(local/)?doc/sparsehash-*/sparse_hash_map.html
|
||||
// for information about how to use this class.
|
||||
|
||||
#ifndef _SPARSE_HASH_MAP_H_
|
||||
#define _SPARSE_HASH_MAP_H_
|
||||
|
||||
#include <sparsehash/internal/sparseconfig.h>
|
||||
#include <algorithm> // needed by stl_alloc
|
||||
#include <functional> // for equal_to<>, select1st<>, etc
|
||||
#include <memory> // for alloc
|
||||
#include <utility> // for pair<>
|
||||
#include <sparsehash/internal/libc_allocator_with_realloc.h>
|
||||
#include <sparsehash/internal/sparsehashtable.h> // IWYU pragma: export
|
||||
#include HASH_FUN_H // for hash<>
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
template <class Key, class T,
|
||||
class HashFcn = SPARSEHASH_HASH<Key>, // defined in sparseconfig.h
|
||||
class EqualKey = std::equal_to<Key>,
|
||||
class Alloc = libc_allocator_with_realloc<std::pair<const Key, T> > >
|
||||
class sparse_hash_map {
|
||||
private:
|
||||
// Apparently select1st is not stl-standard, so we define our own
|
||||
struct SelectKey {
|
||||
typedef const Key& result_type;
|
||||
const Key& operator()(const std::pair<const Key, T>& p) const {
|
||||
return p.first;
|
||||
}
|
||||
};
|
||||
struct SetKey {
|
||||
void operator()(std::pair<const Key, T>* value, const Key& new_key) const {
|
||||
*const_cast<Key*>(&value->first) = new_key;
|
||||
// It would be nice to clear the rest of value here as well, in
|
||||
// case it's taking up a lot of memory. We do this by clearing
|
||||
// the value. This assumes T has a zero-arg constructor!
|
||||
value->second = T();
|
||||
}
|
||||
};
|
||||
// For operator[].
|
||||
struct DefaultValue {
|
||||
std::pair<const Key, T> operator()(const Key& key) {
|
||||
return std::make_pair(key, T());
|
||||
}
|
||||
};
|
||||
|
||||
// The actual data
|
||||
typedef sparse_hashtable<std::pair<const Key, T>, Key, HashFcn, SelectKey,
|
||||
SetKey, EqualKey, Alloc> ht;
|
||||
ht rep;
|
||||
|
||||
public:
|
||||
typedef typename ht::key_type key_type;
|
||||
typedef T data_type;
|
||||
typedef T mapped_type;
|
||||
typedef typename ht::value_type value_type;
|
||||
typedef typename ht::hasher hasher;
|
||||
typedef typename ht::key_equal key_equal;
|
||||
typedef Alloc allocator_type;
|
||||
|
||||
typedef typename ht::size_type size_type;
|
||||
typedef typename ht::difference_type difference_type;
|
||||
typedef typename ht::pointer pointer;
|
||||
typedef typename ht::const_pointer const_pointer;
|
||||
typedef typename ht::reference reference;
|
||||
typedef typename ht::const_reference const_reference;
|
||||
|
||||
typedef typename ht::iterator iterator;
|
||||
typedef typename ht::const_iterator const_iterator;
|
||||
typedef typename ht::local_iterator local_iterator;
|
||||
typedef typename ht::const_local_iterator const_local_iterator;
|
||||
|
||||
// Iterator functions
|
||||
iterator begin() { return rep.begin(); }
|
||||
iterator end() { return rep.end(); }
|
||||
const_iterator begin() const { return rep.begin(); }
|
||||
const_iterator end() const { return rep.end(); }
|
||||
|
||||
// These come from tr1's unordered_map. For us, a bucket has 0 or 1 elements.
|
||||
local_iterator begin(size_type i) { return rep.begin(i); }
|
||||
local_iterator end(size_type i) { return rep.end(i); }
|
||||
const_local_iterator begin(size_type i) const { return rep.begin(i); }
|
||||
const_local_iterator end(size_type i) const { return rep.end(i); }
|
||||
|
||||
// Accessor functions
|
||||
allocator_type get_allocator() const { return rep.get_allocator(); }
|
||||
hasher hash_funct() const { return rep.hash_funct(); }
|
||||
hasher hash_function() const { return hash_funct(); }
|
||||
key_equal key_eq() const { return rep.key_eq(); }
|
||||
|
||||
|
||||
// Constructors
|
||||
explicit sparse_hash_map(size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
sparse_hash_map(InputIterator f, InputIterator l,
|
||||
size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, SelectKey(), SetKey(), alloc) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// We use the default copy constructor
|
||||
// We use the default operator=()
|
||||
// We use the default destructor
|
||||
|
||||
void clear() { rep.clear(); }
|
||||
void swap(sparse_hash_map& hs) { rep.swap(hs.rep); }
|
||||
|
||||
|
||||
// Functions concerning size
|
||||
size_type size() const { return rep.size(); }
|
||||
size_type max_size() const { return rep.max_size(); }
|
||||
bool empty() const { return rep.empty(); }
|
||||
size_type bucket_count() const { return rep.bucket_count(); }
|
||||
size_type max_bucket_count() const { return rep.max_bucket_count(); }
|
||||
|
||||
// These are tr1 methods. bucket() is the bucket the key is or would be in.
|
||||
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
|
||||
size_type bucket(const key_type& key) const { return rep.bucket(key); }
|
||||
float load_factor() const {
|
||||
return size() * 1.0f / bucket_count();
|
||||
}
|
||||
float max_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return grow;
|
||||
}
|
||||
void max_load_factor(float new_grow) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(shrink, new_grow);
|
||||
}
|
||||
// These aren't tr1 methods but perhaps ought to be.
|
||||
float min_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return shrink;
|
||||
}
|
||||
void min_load_factor(float new_shrink) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(new_shrink, grow);
|
||||
}
|
||||
// Deprecated; use min_load_factor() or max_load_factor() instead.
|
||||
void set_resizing_parameters(float shrink, float grow) {
|
||||
rep.set_resizing_parameters(shrink, grow);
|
||||
}
|
||||
|
||||
void resize(size_type hint) { rep.resize(hint); }
|
||||
void rehash(size_type hint) { resize(hint); } // the tr1 name
|
||||
|
||||
// Lookup routines
|
||||
iterator find(const key_type& key) { return rep.find(key); }
|
||||
const_iterator find(const key_type& key) const { return rep.find(key); }
|
||||
|
||||
data_type& operator[](const key_type& key) { // This is our value-add!
|
||||
// If key is in the hashtable, returns find(key)->second,
|
||||
// otherwise returns insert(value_type(key, T()).first->second.
|
||||
// Note it does not create an empty T unless the find fails.
|
||||
return rep.template find_or_insert<DefaultValue>(key).second;
|
||||
}
|
||||
|
||||
size_type count(const key_type& key) const { return rep.count(key); }
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type& key) {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
std::pair<const_iterator, const_iterator> equal_range(const key_type& key)
|
||||
const {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
|
||||
// Insertion routines
|
||||
std::pair<iterator, bool> insert(const value_type& obj) {
|
||||
return rep.insert(obj);
|
||||
}
|
||||
template <class InputIterator> void insert(InputIterator f, InputIterator l) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
void insert(const_iterator f, const_iterator l) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// Required for std::insert_iterator; the passed-in iterator is ignored.
|
||||
iterator insert(iterator, const value_type& obj) {
|
||||
return insert(obj).first;
|
||||
}
|
||||
|
||||
// Deletion routines
|
||||
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
|
||||
// value to identify deleted buckets. You can change the key as
|
||||
// time goes on, or get rid of it entirely to be insert-only.
|
||||
void set_deleted_key(const key_type& key) {
|
||||
rep.set_deleted_key(key);
|
||||
}
|
||||
void clear_deleted_key() { rep.clear_deleted_key(); }
|
||||
key_type deleted_key() const { return rep.deleted_key(); }
|
||||
|
||||
// These are standard
|
||||
size_type erase(const key_type& key) { return rep.erase(key); }
|
||||
void erase(iterator it) { rep.erase(it); }
|
||||
void erase(iterator f, iterator l) { rep.erase(f, l); }
|
||||
|
||||
|
||||
// Comparison
|
||||
bool operator==(const sparse_hash_map& hs) const { return rep == hs.rep; }
|
||||
bool operator!=(const sparse_hash_map& hs) const { return rep != hs.rep; }
|
||||
|
||||
|
||||
// I/O -- this is an add-on for writing metainformation to disk
|
||||
//
|
||||
// For maximum flexibility, this does not assume a particular
|
||||
// file type (though it will probably be a FILE *). We just pass
|
||||
// the fp through to rep.
|
||||
|
||||
// If your keys and values are simple enough, you can pass this
|
||||
// serializer to serialize()/unserialize(). "Simple enough" means
|
||||
// value_type is a POD type that contains no pointers. Note,
|
||||
// however, we don't try to normalize endianness.
|
||||
typedef typename ht::NopointerSerializer NopointerSerializer;
|
||||
|
||||
// serializer: a class providing operator()(OUTPUT*, const value_type&)
|
||||
// (writing value_type to OUTPUT). You can specify a
|
||||
// NopointerSerializer object if appropriate (see above).
|
||||
// fp: either a FILE*, OR an ostream*/subclass_of_ostream*, OR a
|
||||
// pointer to a class providing size_t Write(const void*, size_t),
|
||||
// which writes a buffer into a stream (which fp presumably
|
||||
// owns) and returns the number of bytes successfully written.
|
||||
// Note basic_ostream<not_char> is not currently supported.
|
||||
template <typename ValueSerializer, typename OUTPUT>
|
||||
bool serialize(ValueSerializer serializer, OUTPUT* fp) {
|
||||
return rep.serialize(serializer, fp);
|
||||
}
|
||||
|
||||
// serializer: a functor providing operator()(INPUT*, value_type*)
|
||||
// (reading from INPUT and into value_type). You can specify a
|
||||
// NopointerSerializer object if appropriate (see above).
|
||||
// fp: either a FILE*, OR an istream*/subclass_of_istream*, OR a
|
||||
// pointer to a class providing size_t Read(void*, size_t),
|
||||
// which reads into a buffer from a stream (which fp presumably
|
||||
// owns) and returns the number of bytes successfully read.
|
||||
// Note basic_istream<not_char> is not currently supported.
|
||||
// NOTE: Since value_type is std::pair<const Key, T>, ValueSerializer
|
||||
// may need to do a const cast in order to fill in the key.
|
||||
// NOTE: if Key or T are not POD types, the serializer MUST use
|
||||
// placement-new to initialize their values, rather than a normal
|
||||
// equals-assignment or similar. (The value_type* passed into the
|
||||
// serializer points to garbage memory.)
|
||||
template <typename ValueSerializer, typename INPUT>
|
||||
bool unserialize(ValueSerializer serializer, INPUT* fp) {
|
||||
return rep.unserialize(serializer, fp);
|
||||
}
|
||||
|
||||
// The four methods below are DEPRECATED.
|
||||
// Use serialize() and unserialize() for new code.
|
||||
template <typename OUTPUT>
|
||||
bool write_metadata(OUTPUT *fp) { return rep.write_metadata(fp); }
|
||||
|
||||
template <typename INPUT>
|
||||
bool read_metadata(INPUT *fp) { return rep.read_metadata(fp); }
|
||||
|
||||
template <typename OUTPUT>
|
||||
bool write_nopointer_data(OUTPUT *fp) { return rep.write_nopointer_data(fp); }
|
||||
|
||||
template <typename INPUT>
|
||||
bool read_nopointer_data(INPUT *fp) { return rep.read_nopointer_data(fp); }
|
||||
};
|
||||
|
||||
// We need a global swap as well
|
||||
template <class Key, class T, class HashFcn, class EqualKey, class Alloc>
|
||||
inline void swap(sparse_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm1,
|
||||
sparse_hash_map<Key, T, HashFcn, EqualKey, Alloc>& hm2) {
|
||||
hm1.swap(hm2);
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif /* _SPARSE_HASH_MAP_H_ */
|
338
contrib/libsparsehash/sparsehash/sparse_hash_set
Normal file
338
contrib/libsparsehash/sparsehash/sparse_hash_set
Normal file
@ -0,0 +1,338 @@
|
||||
// Copyright (c) 2005, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
//
|
||||
// This is just a very thin wrapper over sparsehashtable.h, just
|
||||
// like sgi stl's stl_hash_set is a very thin wrapper over
|
||||
// stl_hashtable. The major thing we define is operator[], because
|
||||
// we have a concept of a data_type which stl_hashtable doesn't
|
||||
// (it only has a key and a value).
|
||||
//
|
||||
// This is more different from sparse_hash_map than you might think,
|
||||
// because all iterators for sets are const (you obviously can't
|
||||
// change the key, and for sets there is no value).
|
||||
//
|
||||
// We adhere mostly to the STL semantics for hash-map. One important
|
||||
// exception is that insert() may invalidate iterators entirely -- STL
|
||||
// semantics are that insert() may reorder iterators, but they all
|
||||
// still refer to something valid in the hashtable. Not so for us.
|
||||
// Likewise, insert() may invalidate pointers into the hashtable.
|
||||
// (Whether insert invalidates iterators and pointers depends on
|
||||
// whether it results in a hashtable resize). On the plus side,
|
||||
// delete() doesn't invalidate iterators or pointers at all, or even
|
||||
// change the ordering of elements.
|
||||
//
|
||||
// Here are a few "power user" tips:
|
||||
//
|
||||
// 1) set_deleted_key():
|
||||
// Unlike STL's hash_map, if you want to use erase() you
|
||||
// *must* call set_deleted_key() after construction.
|
||||
//
|
||||
// 2) resize(0):
|
||||
// When an item is deleted, its memory isn't freed right
|
||||
// away. This allows you to iterate over a hashtable,
|
||||
// and call erase(), without invalidating the iterator.
|
||||
// To force the memory to be freed, call resize(0).
|
||||
// For tr1 compatibility, this can also be called as rehash(0).
|
||||
//
|
||||
// 3) min_load_factor(0.0)
|
||||
// Setting the minimum load factor to 0.0 guarantees that
|
||||
// the hash table will never shrink.
|
||||
//
|
||||
// Roughly speaking:
|
||||
// (1) dense_hash_set: fastest, uses the most memory unless entries are small
|
||||
// (2) sparse_hash_set: slowest, uses the least memory
|
||||
// (3) hash_set / unordered_set (STL): in the middle
|
||||
//
|
||||
// Typically I use sparse_hash_set when I care about space and/or when
|
||||
// I need to save the hashtable on disk. I use hash_set otherwise. I
|
||||
// don't personally use dense_hash_set ever; some people use it for
|
||||
// small sets with lots of lookups.
|
||||
//
|
||||
// - dense_hash_set has, typically, about 78% memory overhead (if your
|
||||
// data takes up X bytes, the hash_set uses .78X more bytes in overhead).
|
||||
// - sparse_hash_set has about 4 bits overhead per entry.
|
||||
// - sparse_hash_set can be 3-7 times slower than the others for lookup and,
|
||||
// especially, inserts. See time_hash_map.cc for details.
|
||||
//
|
||||
// See /usr/(local/)?doc/sparsehash-*/sparse_hash_set.html
|
||||
// for information about how to use this class.
|
||||
|
||||
#ifndef _SPARSE_HASH_SET_H_
|
||||
#define _SPARSE_HASH_SET_H_
|
||||
|
||||
#include <sparsehash/internal/sparseconfig.h>
|
||||
#include <algorithm> // needed by stl_alloc
|
||||
#include <functional> // for equal_to<>
|
||||
#include <memory> // for alloc (which we don't use)
|
||||
#include <utility> // for pair<>
|
||||
#include <sparsehash/internal/libc_allocator_with_realloc.h>
|
||||
#include <sparsehash/internal/sparsehashtable.h> // IWYU pragma: export
|
||||
#include HASH_FUN_H // for hash<>
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
template <class Value,
|
||||
class HashFcn = SPARSEHASH_HASH<Value>, // defined in sparseconfig.h
|
||||
class EqualKey = std::equal_to<Value>,
|
||||
class Alloc = libc_allocator_with_realloc<Value> >
|
||||
class sparse_hash_set {
|
||||
private:
|
||||
// Apparently identity is not stl-standard, so we define our own
|
||||
struct Identity {
|
||||
typedef const Value& result_type;
|
||||
const Value& operator()(const Value& v) const { return v; }
|
||||
};
|
||||
struct SetKey {
|
||||
void operator()(Value* value, const Value& new_key) const {
|
||||
*value = new_key;
|
||||
}
|
||||
};
|
||||
|
||||
typedef sparse_hashtable<Value, Value, HashFcn, Identity, SetKey,
|
||||
EqualKey, Alloc> ht;
|
||||
ht rep;
|
||||
|
||||
public:
|
||||
typedef typename ht::key_type key_type;
|
||||
typedef typename ht::value_type value_type;
|
||||
typedef typename ht::hasher hasher;
|
||||
typedef typename ht::key_equal key_equal;
|
||||
typedef Alloc allocator_type;
|
||||
|
||||
typedef typename ht::size_type size_type;
|
||||
typedef typename ht::difference_type difference_type;
|
||||
typedef typename ht::const_pointer pointer;
|
||||
typedef typename ht::const_pointer const_pointer;
|
||||
typedef typename ht::const_reference reference;
|
||||
typedef typename ht::const_reference const_reference;
|
||||
|
||||
typedef typename ht::const_iterator iterator;
|
||||
typedef typename ht::const_iterator const_iterator;
|
||||
typedef typename ht::const_local_iterator local_iterator;
|
||||
typedef typename ht::const_local_iterator const_local_iterator;
|
||||
|
||||
|
||||
// Iterator functions -- recall all iterators are const
|
||||
iterator begin() const { return rep.begin(); }
|
||||
iterator end() const { return rep.end(); }
|
||||
|
||||
// These come from tr1's unordered_set. For us, a bucket has 0 or 1 elements.
|
||||
local_iterator begin(size_type i) const { return rep.begin(i); }
|
||||
local_iterator end(size_type i) const { return rep.end(i); }
|
||||
|
||||
|
||||
// Accessor functions
|
||||
allocator_type get_allocator() const { return rep.get_allocator(); }
|
||||
hasher hash_funct() const { return rep.hash_funct(); }
|
||||
hasher hash_function() const { return hash_funct(); } // tr1 name
|
||||
key_equal key_eq() const { return rep.key_eq(); }
|
||||
|
||||
|
||||
// Constructors
|
||||
explicit sparse_hash_set(size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
sparse_hash_set(InputIterator f, InputIterator l,
|
||||
size_type expected_max_items_in_table = 0,
|
||||
const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& alloc = allocator_type())
|
||||
: rep(expected_max_items_in_table, hf, eql, Identity(), SetKey(), alloc) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// We use the default copy constructor
|
||||
// We use the default operator=()
|
||||
// We use the default destructor
|
||||
|
||||
void clear() { rep.clear(); }
|
||||
void swap(sparse_hash_set& hs) { rep.swap(hs.rep); }
|
||||
|
||||
|
||||
// Functions concerning size
|
||||
size_type size() const { return rep.size(); }
|
||||
size_type max_size() const { return rep.max_size(); }
|
||||
bool empty() const { return rep.empty(); }
|
||||
size_type bucket_count() const { return rep.bucket_count(); }
|
||||
size_type max_bucket_count() const { return rep.max_bucket_count(); }
|
||||
|
||||
// These are tr1 methods. bucket() is the bucket the key is or would be in.
|
||||
size_type bucket_size(size_type i) const { return rep.bucket_size(i); }
|
||||
size_type bucket(const key_type& key) const { return rep.bucket(key); }
|
||||
float load_factor() const {
|
||||
return size() * 1.0f / bucket_count();
|
||||
}
|
||||
float max_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return grow;
|
||||
}
|
||||
void max_load_factor(float new_grow) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(shrink, new_grow);
|
||||
}
|
||||
// These aren't tr1 methods but perhaps ought to be.
|
||||
float min_load_factor() const {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
return shrink;
|
||||
}
|
||||
void min_load_factor(float new_shrink) {
|
||||
float shrink, grow;
|
||||
rep.get_resizing_parameters(&shrink, &grow);
|
||||
rep.set_resizing_parameters(new_shrink, grow);
|
||||
}
|
||||
// Deprecated; use min_load_factor() or max_load_factor() instead.
|
||||
void set_resizing_parameters(float shrink, float grow) {
|
||||
rep.set_resizing_parameters(shrink, grow);
|
||||
}
|
||||
|
||||
void resize(size_type hint) { rep.resize(hint); }
|
||||
void rehash(size_type hint) { resize(hint); } // the tr1 name
|
||||
|
||||
// Lookup routines
|
||||
iterator find(const key_type& key) const { return rep.find(key); }
|
||||
|
||||
size_type count(const key_type& key) const { return rep.count(key); }
|
||||
|
||||
std::pair<iterator, iterator> equal_range(const key_type& key) const {
|
||||
return rep.equal_range(key);
|
||||
}
|
||||
|
||||
|
||||
// Insertion routines
|
||||
std::pair<iterator, bool> insert(const value_type& obj) {
|
||||
std::pair<typename ht::iterator, bool> p = rep.insert(obj);
|
||||
return std::pair<iterator, bool>(p.first, p.second); // const to non-const
|
||||
}
|
||||
template <class InputIterator> void insert(InputIterator f, InputIterator l) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
void insert(const_iterator f, const_iterator l) {
|
||||
rep.insert(f, l);
|
||||
}
|
||||
// Required for std::insert_iterator; the passed-in iterator is ignored.
|
||||
iterator insert(iterator, const value_type& obj) {
|
||||
return insert(obj).first;
|
||||
}
|
||||
|
||||
// Deletion routines
|
||||
// THESE ARE NON-STANDARD! I make you specify an "impossible" key
|
||||
// value to identify deleted buckets. You can change the key as
|
||||
// time goes on, or get rid of it entirely to be insert-only.
|
||||
void set_deleted_key(const key_type& key) { rep.set_deleted_key(key); }
|
||||
void clear_deleted_key() { rep.clear_deleted_key(); }
|
||||
key_type deleted_key() const { return rep.deleted_key(); }
|
||||
|
||||
// These are standard
|
||||
size_type erase(const key_type& key) { return rep.erase(key); }
|
||||
void erase(iterator it) { rep.erase(it); }
|
||||
void erase(iterator f, iterator l) { rep.erase(f, l); }
|
||||
|
||||
|
||||
// Comparison
|
||||
bool operator==(const sparse_hash_set& hs) const { return rep == hs.rep; }
|
||||
bool operator!=(const sparse_hash_set& hs) const { return rep != hs.rep; }
|
||||
|
||||
|
||||
// I/O -- this is an add-on for writing metainformation to disk
|
||||
//
|
||||
// For maximum flexibility, this does not assume a particular
|
||||
// file type (though it will probably be a FILE *). We just pass
|
||||
// the fp through to rep.
|
||||
|
||||
// If your keys and values are simple enough, you can pass this
|
||||
// serializer to serialize()/unserialize(). "Simple enough" means
|
||||
// value_type is a POD type that contains no pointers. Note,
|
||||
// however, we don't try to normalize endianness.
|
||||
typedef typename ht::NopointerSerializer NopointerSerializer;
|
||||
|
||||
// serializer: a class providing operator()(OUTPUT*, const value_type&)
|
||||
// (writing value_type to OUTPUT). You can specify a
|
||||
// NopointerSerializer object if appropriate (see above).
|
||||
// fp: either a FILE*, OR an ostream*/subclass_of_ostream*, OR a
|
||||
// pointer to a class providing size_t Write(const void*, size_t),
|
||||
// which writes a buffer into a stream (which fp presumably
|
||||
// owns) and returns the number of bytes successfully written.
|
||||
// Note basic_ostream<not_char> is not currently supported.
|
||||
template <typename ValueSerializer, typename OUTPUT>
|
||||
bool serialize(ValueSerializer serializer, OUTPUT* fp) {
|
||||
return rep.serialize(serializer, fp);
|
||||
}
|
||||
|
||||
// serializer: a functor providing operator()(INPUT*, value_type*)
|
||||
// (reading from INPUT and into value_type). You can specify a
|
||||
// NopointerSerializer object if appropriate (see above).
|
||||
// fp: either a FILE*, OR an istream*/subclass_of_istream*, OR a
|
||||
// pointer to a class providing size_t Read(void*, size_t),
|
||||
// which reads into a buffer from a stream (which fp presumably
|
||||
// owns) and returns the number of bytes successfully read.
|
||||
// Note basic_istream<not_char> is not currently supported.
|
||||
// NOTE: Since value_type is const Key, ValueSerializer
|
||||
// may need to do a const cast in order to fill in the key.
|
||||
// NOTE: if Key is not a POD type, the serializer MUST use
|
||||
// placement-new to initialize its value, rather than a normal
|
||||
// equals-assignment or similar. (The value_type* passed into
|
||||
// the serializer points to garbage memory.)
|
||||
template <typename ValueSerializer, typename INPUT>
|
||||
bool unserialize(ValueSerializer serializer, INPUT* fp) {
|
||||
return rep.unserialize(serializer, fp);
|
||||
}
|
||||
|
||||
// The four methods below are DEPRECATED.
|
||||
// Use serialize() and unserialize() for new code.
|
||||
template <typename OUTPUT>
|
||||
bool write_metadata(OUTPUT *fp) { return rep.write_metadata(fp); }
|
||||
|
||||
template <typename INPUT>
|
||||
bool read_metadata(INPUT *fp) { return rep.read_metadata(fp); }
|
||||
|
||||
template <typename OUTPUT>
|
||||
bool write_nopointer_data(OUTPUT *fp) { return rep.write_nopointer_data(fp); }
|
||||
|
||||
template <typename INPUT>
|
||||
bool read_nopointer_data(INPUT *fp) { return rep.read_nopointer_data(fp); }
|
||||
};
|
||||
|
||||
template <class Val, class HashFcn, class EqualKey, class Alloc>
|
||||
inline void swap(sparse_hash_set<Val, HashFcn, EqualKey, Alloc>& hs1,
|
||||
sparse_hash_set<Val, HashFcn, EqualKey, Alloc>& hs2) {
|
||||
hs1.swap(hs2);
|
||||
}
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif /* _SPARSE_HASH_SET_H_ */
|
1820
contrib/libsparsehash/sparsehash/sparsetable
Normal file
1820
contrib/libsparsehash/sparsehash/sparsetable
Normal file
File diff suppressed because it is too large
Load Diff
134
contrib/libsparsehash/sparsehash/template_util.h
Normal file
134
contrib/libsparsehash/sparsehash/template_util.h
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright 2005 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ----
|
||||
//
|
||||
// Template metaprogramming utility functions.
|
||||
//
|
||||
// This code is compiled directly on many platforms, including client
|
||||
// platforms like Windows, Mac, and embedded systems. Before making
|
||||
// any changes here, make sure that you're not breaking any platforms.
|
||||
//
|
||||
//
|
||||
// The names choosen here reflect those used in tr1 and the boost::mpl
|
||||
// library, there are similar operations used in the Loki library as
|
||||
// well. I prefer the boost names for 2 reasons:
|
||||
// 1. I think that portions of the Boost libraries are more likely to
|
||||
// be included in the c++ standard.
|
||||
// 2. It is not impossible that some of the boost libraries will be
|
||||
// included in our own build in the future.
|
||||
// Both of these outcomes means that we may be able to directly replace
|
||||
// some of these with boost equivalents.
|
||||
//
|
||||
#ifndef BASE_TEMPLATE_UTIL_H_
|
||||
#define BASE_TEMPLATE_UTIL_H_
|
||||
|
||||
#include <sparsehash/internal/sparseconfig.h>
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
// Types small_ and big_ are guaranteed such that sizeof(small_) <
|
||||
// sizeof(big_)
|
||||
typedef char small_;
|
||||
|
||||
struct big_ {
|
||||
char dummy[2];
|
||||
};
|
||||
|
||||
// Identity metafunction.
|
||||
template <class T>
|
||||
struct identity_ {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
// integral_constant, defined in tr1, is a wrapper for an integer
|
||||
// value. We don't really need this generality; we could get away
|
||||
// with hardcoding the integer type to bool. We use the fully
|
||||
// general integer_constant for compatibility with tr1.
|
||||
|
||||
template<class T, T v>
|
||||
struct integral_constant {
|
||||
static const T value = v;
|
||||
typedef T value_type;
|
||||
typedef integral_constant<T, v> type;
|
||||
};
|
||||
|
||||
template <class T, T v> const T integral_constant<T, v>::value;
|
||||
|
||||
|
||||
// Abbreviations: true_type and false_type are structs that represent boolean
|
||||
// true and false values. Also define the boost::mpl versions of those names,
|
||||
// true_ and false_.
|
||||
typedef integral_constant<bool, true> true_type;
|
||||
typedef integral_constant<bool, false> false_type;
|
||||
typedef true_type true_;
|
||||
typedef false_type false_;
|
||||
|
||||
// if_ is a templatized conditional statement.
|
||||
// if_<cond, A, B> is a compile time evaluation of cond.
|
||||
// if_<>::type contains A if cond is true, B otherwise.
|
||||
template<bool cond, typename A, typename B>
|
||||
struct if_{
|
||||
typedef A type;
|
||||
};
|
||||
|
||||
template<typename A, typename B>
|
||||
struct if_<false, A, B> {
|
||||
typedef B type;
|
||||
};
|
||||
|
||||
|
||||
// type_equals_ is a template type comparator, similar to Loki IsSameType.
|
||||
// type_equals_<A, B>::value is true iff "A" is the same type as "B".
|
||||
//
|
||||
// New code should prefer base::is_same, defined in base/type_traits.h.
|
||||
// It is functionally identical, but is_same is the standard spelling.
|
||||
template<typename A, typename B>
|
||||
struct type_equals_ : public false_ {
|
||||
};
|
||||
|
||||
template<typename A>
|
||||
struct type_equals_<A, A> : public true_ {
|
||||
};
|
||||
|
||||
// and_ is a template && operator.
|
||||
// and_<A, B>::value evaluates "A::value && B::value".
|
||||
template<typename A, typename B>
|
||||
struct and_ : public integral_constant<bool, (A::value && B::value)> {
|
||||
};
|
||||
|
||||
// or_ is a template || operator.
|
||||
// or_<A, B>::value evaluates "A::value || B::value".
|
||||
template<typename A, typename B>
|
||||
struct or_ : public integral_constant<bool, (A::value || B::value)> {
|
||||
};
|
||||
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
#endif // BASE_TEMPLATE_UTIL_H_
|
342
contrib/libsparsehash/sparsehash/type_traits.h
Normal file
342
contrib/libsparsehash/sparsehash/type_traits.h
Normal file
@ -0,0 +1,342 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ----
|
||||
//
|
||||
// This code is compiled directly on many platforms, including client
|
||||
// platforms like Windows, Mac, and embedded systems. Before making
|
||||
// any changes here, make sure that you're not breaking any platforms.
|
||||
//
|
||||
// Define a small subset of tr1 type traits. The traits we define are:
|
||||
// is_integral
|
||||
// is_floating_point
|
||||
// is_pointer
|
||||
// is_enum
|
||||
// is_reference
|
||||
// is_pod
|
||||
// has_trivial_constructor
|
||||
// has_trivial_copy
|
||||
// has_trivial_assign
|
||||
// has_trivial_destructor
|
||||
// remove_const
|
||||
// remove_volatile
|
||||
// remove_cv
|
||||
// remove_reference
|
||||
// add_reference
|
||||
// remove_pointer
|
||||
// is_same
|
||||
// is_convertible
|
||||
// We can add more type traits as required.
|
||||
|
||||
#ifndef BASE_TYPE_TRAITS_H_
|
||||
#define BASE_TYPE_TRAITS_H_
|
||||
|
||||
#include <sparsehash/internal/sparseconfig.h>
|
||||
#include <utility> // For pair
|
||||
|
||||
#include <sparsehash/template_util.h> // For true_type and false_type
|
||||
|
||||
_START_GOOGLE_NAMESPACE_
|
||||
|
||||
template <class T> struct is_integral;
|
||||
template <class T> struct is_floating_point;
|
||||
template <class T> struct is_pointer;
|
||||
// MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least)
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
|
||||
// is_enum uses is_convertible, which is not available on MSVC.
|
||||
template <class T> struct is_enum;
|
||||
#endif
|
||||
template <class T> struct is_reference;
|
||||
template <class T> struct is_pod;
|
||||
template <class T> struct has_trivial_constructor;
|
||||
template <class T> struct has_trivial_copy;
|
||||
template <class T> struct has_trivial_assign;
|
||||
template <class T> struct has_trivial_destructor;
|
||||
template <class T> struct remove_const;
|
||||
template <class T> struct remove_volatile;
|
||||
template <class T> struct remove_cv;
|
||||
template <class T> struct remove_reference;
|
||||
template <class T> struct add_reference;
|
||||
template <class T> struct remove_pointer;
|
||||
template <class T, class U> struct is_same;
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
|
||||
template <class From, class To> struct is_convertible;
|
||||
#endif
|
||||
|
||||
// is_integral is false except for the built-in integer types. A
|
||||
// cv-qualified type is integral if and only if the underlying type is.
|
||||
template <class T> struct is_integral : false_type { };
|
||||
template<> struct is_integral<bool> : true_type { };
|
||||
template<> struct is_integral<char> : true_type { };
|
||||
template<> struct is_integral<unsigned char> : true_type { };
|
||||
template<> struct is_integral<signed char> : true_type { };
|
||||
#if defined(_MSC_VER)
|
||||
// wchar_t is not by default a distinct type from unsigned short in
|
||||
// Microsoft C.
|
||||
// See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx
|
||||
template<> struct is_integral<__wchar_t> : true_type { };
|
||||
#else
|
||||
template<> struct is_integral<wchar_t> : true_type { };
|
||||
#endif
|
||||
template<> struct is_integral<short> : true_type { };
|
||||
template<> struct is_integral<unsigned short> : true_type { };
|
||||
template<> struct is_integral<int> : true_type { };
|
||||
template<> struct is_integral<unsigned int> : true_type { };
|
||||
template<> struct is_integral<long> : true_type { };
|
||||
template<> struct is_integral<unsigned long> : true_type { };
|
||||
#ifdef HAVE_LONG_LONG
|
||||
template<> struct is_integral<long long> : true_type { };
|
||||
template<> struct is_integral<unsigned long long> : true_type { };
|
||||
#endif
|
||||
template <class T> struct is_integral<const T> : is_integral<T> { };
|
||||
template <class T> struct is_integral<volatile T> : is_integral<T> { };
|
||||
template <class T> struct is_integral<const volatile T> : is_integral<T> { };
|
||||
|
||||
// is_floating_point is false except for the built-in floating-point types.
|
||||
// A cv-qualified type is integral if and only if the underlying type is.
|
||||
template <class T> struct is_floating_point : false_type { };
|
||||
template<> struct is_floating_point<float> : true_type { };
|
||||
template<> struct is_floating_point<double> : true_type { };
|
||||
template<> struct is_floating_point<long double> : true_type { };
|
||||
template <class T> struct is_floating_point<const T>
|
||||
: is_floating_point<T> { };
|
||||
template <class T> struct is_floating_point<volatile T>
|
||||
: is_floating_point<T> { };
|
||||
template <class T> struct is_floating_point<const volatile T>
|
||||
: is_floating_point<T> { };
|
||||
|
||||
// is_pointer is false except for pointer types. A cv-qualified type (e.g.
|
||||
// "int* const", as opposed to "int const*") is cv-qualified if and only if
|
||||
// the underlying type is.
|
||||
template <class T> struct is_pointer : false_type { };
|
||||
template <class T> struct is_pointer<T*> : true_type { };
|
||||
template <class T> struct is_pointer<const T> : is_pointer<T> { };
|
||||
template <class T> struct is_pointer<volatile T> : is_pointer<T> { };
|
||||
template <class T> struct is_pointer<const volatile T> : is_pointer<T> { };
|
||||
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <class T> struct is_class_or_union {
|
||||
template <class U> static small_ tester(void (U::*)());
|
||||
template <class U> static big_ tester(...);
|
||||
static const bool value = sizeof(tester<T>(0)) == sizeof(small_);
|
||||
};
|
||||
|
||||
// is_convertible chokes if the first argument is an array. That's why
|
||||
// we use add_reference here.
|
||||
template <bool NotUnum, class T> struct is_enum_impl
|
||||
: is_convertible<typename add_reference<T>::type, int> { };
|
||||
|
||||
template <class T> struct is_enum_impl<true, T> : false_type { };
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Specified by TR1 [4.5.1] primary type categories.
|
||||
|
||||
// Implementation note:
|
||||
//
|
||||
// Each type is either void, integral, floating point, array, pointer,
|
||||
// reference, member object pointer, member function pointer, enum,
|
||||
// union or class. Out of these, only integral, floating point, reference,
|
||||
// class and enum types are potentially convertible to int. Therefore,
|
||||
// if a type is not a reference, integral, floating point or class and
|
||||
// is convertible to int, it's a enum. Adding cv-qualification to a type
|
||||
// does not change whether it's an enum.
|
||||
//
|
||||
// Is-convertible-to-int check is done only if all other checks pass,
|
||||
// because it can't be used with some types (e.g. void or classes with
|
||||
// inaccessible conversion operators).
|
||||
template <class T> struct is_enum
|
||||
: internal::is_enum_impl<
|
||||
is_same<T, void>::value ||
|
||||
is_integral<T>::value ||
|
||||
is_floating_point<T>::value ||
|
||||
is_reference<T>::value ||
|
||||
internal::is_class_or_union<T>::value,
|
||||
T> { };
|
||||
|
||||
template <class T> struct is_enum<const T> : is_enum<T> { };
|
||||
template <class T> struct is_enum<volatile T> : is_enum<T> { };
|
||||
template <class T> struct is_enum<const volatile T> : is_enum<T> { };
|
||||
|
||||
#endif
|
||||
|
||||
// is_reference is false except for reference types.
|
||||
template<typename T> struct is_reference : false_type {};
|
||||
template<typename T> struct is_reference<T&> : true_type {};
|
||||
|
||||
|
||||
// We can't get is_pod right without compiler help, so fail conservatively.
|
||||
// We will assume it's false except for arithmetic types, enumerations,
|
||||
// pointers and cv-qualified versions thereof. Note that std::pair<T,U>
|
||||
// is not a POD even if T and U are PODs.
|
||||
template <class T> struct is_pod
|
||||
: integral_constant<bool, (is_integral<T>::value ||
|
||||
is_floating_point<T>::value ||
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
|
||||
// is_enum is not available on MSVC.
|
||||
is_enum<T>::value ||
|
||||
#endif
|
||||
is_pointer<T>::value)> { };
|
||||
template <class T> struct is_pod<const T> : is_pod<T> { };
|
||||
template <class T> struct is_pod<volatile T> : is_pod<T> { };
|
||||
template <class T> struct is_pod<const volatile T> : is_pod<T> { };
|
||||
|
||||
|
||||
// We can't get has_trivial_constructor right without compiler help, so
|
||||
// fail conservatively. We will assume it's false except for: (1) types
|
||||
// for which is_pod is true. (2) std::pair of types with trivial
|
||||
// constructors. (3) array of a type with a trivial constructor.
|
||||
// (4) const versions thereof.
|
||||
template <class T> struct has_trivial_constructor : is_pod<T> { };
|
||||
template <class T, class U> struct has_trivial_constructor<std::pair<T, U> >
|
||||
: integral_constant<bool,
|
||||
(has_trivial_constructor<T>::value &&
|
||||
has_trivial_constructor<U>::value)> { };
|
||||
template <class A, int N> struct has_trivial_constructor<A[N]>
|
||||
: has_trivial_constructor<A> { };
|
||||
template <class T> struct has_trivial_constructor<const T>
|
||||
: has_trivial_constructor<T> { };
|
||||
|
||||
// We can't get has_trivial_copy right without compiler help, so fail
|
||||
// conservatively. We will assume it's false except for: (1) types
|
||||
// for which is_pod is true. (2) std::pair of types with trivial copy
|
||||
// constructors. (3) array of a type with a trivial copy constructor.
|
||||
// (4) const versions thereof.
|
||||
template <class T> struct has_trivial_copy : is_pod<T> { };
|
||||
template <class T, class U> struct has_trivial_copy<std::pair<T, U> >
|
||||
: integral_constant<bool,
|
||||
(has_trivial_copy<T>::value &&
|
||||
has_trivial_copy<U>::value)> { };
|
||||
template <class A, int N> struct has_trivial_copy<A[N]>
|
||||
: has_trivial_copy<A> { };
|
||||
template <class T> struct has_trivial_copy<const T> : has_trivial_copy<T> { };
|
||||
|
||||
// We can't get has_trivial_assign right without compiler help, so fail
|
||||
// conservatively. We will assume it's false except for: (1) types
|
||||
// for which is_pod is true. (2) std::pair of types with trivial copy
|
||||
// constructors. (3) array of a type with a trivial assign constructor.
|
||||
template <class T> struct has_trivial_assign : is_pod<T> { };
|
||||
template <class T, class U> struct has_trivial_assign<std::pair<T, U> >
|
||||
: integral_constant<bool,
|
||||
(has_trivial_assign<T>::value &&
|
||||
has_trivial_assign<U>::value)> { };
|
||||
template <class A, int N> struct has_trivial_assign<A[N]>
|
||||
: has_trivial_assign<A> { };
|
||||
|
||||
// We can't get has_trivial_destructor right without compiler help, so
|
||||
// fail conservatively. We will assume it's false except for: (1) types
|
||||
// for which is_pod is true. (2) std::pair of types with trivial
|
||||
// destructors. (3) array of a type with a trivial destructor.
|
||||
// (4) const versions thereof.
|
||||
template <class T> struct has_trivial_destructor : is_pod<T> { };
|
||||
template <class T, class U> struct has_trivial_destructor<std::pair<T, U> >
|
||||
: integral_constant<bool,
|
||||
(has_trivial_destructor<T>::value &&
|
||||
has_trivial_destructor<U>::value)> { };
|
||||
template <class A, int N> struct has_trivial_destructor<A[N]>
|
||||
: has_trivial_destructor<A> { };
|
||||
template <class T> struct has_trivial_destructor<const T>
|
||||
: has_trivial_destructor<T> { };
|
||||
|
||||
// Specified by TR1 [4.7.1]
|
||||
template<typename T> struct remove_const { typedef T type; };
|
||||
template<typename T> struct remove_const<T const> { typedef T type; };
|
||||
template<typename T> struct remove_volatile { typedef T type; };
|
||||
template<typename T> struct remove_volatile<T volatile> { typedef T type; };
|
||||
template<typename T> struct remove_cv {
|
||||
typedef typename remove_const<typename remove_volatile<T>::type>::type type;
|
||||
};
|
||||
|
||||
|
||||
// Specified by TR1 [4.7.2] Reference modifications.
|
||||
template<typename T> struct remove_reference { typedef T type; };
|
||||
template<typename T> struct remove_reference<T&> { typedef T type; };
|
||||
|
||||
template <typename T> struct add_reference { typedef T& type; };
|
||||
template <typename T> struct add_reference<T&> { typedef T& type; };
|
||||
|
||||
// Specified by TR1 [4.7.4] Pointer modifications.
|
||||
template<typename T> struct remove_pointer { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T*> { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T* const> { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T* volatile> { typedef T type; };
|
||||
template<typename T> struct remove_pointer<T* const volatile> {
|
||||
typedef T type; };
|
||||
|
||||
// Specified by TR1 [4.6] Relationships between types
|
||||
template<typename T, typename U> struct is_same : public false_type { };
|
||||
template<typename T> struct is_same<T, T> : public true_type { };
|
||||
|
||||
// Specified by TR1 [4.6] Relationships between types
|
||||
#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3)
|
||||
namespace internal {
|
||||
|
||||
// This class is an implementation detail for is_convertible, and you
|
||||
// don't need to know how it works to use is_convertible. For those
|
||||
// who care: we declare two different functions, one whose argument is
|
||||
// of type To and one with a variadic argument list. We give them
|
||||
// return types of different size, so we can use sizeof to trick the
|
||||
// compiler into telling us which function it would have chosen if we
|
||||
// had called it with an argument of type From. See Alexandrescu's
|
||||
// _Modern C++ Design_ for more details on this sort of trick.
|
||||
|
||||
template <typename From, typename To>
|
||||
struct ConvertHelper {
|
||||
static small_ Test(To);
|
||||
static big_ Test(...);
|
||||
static From Create();
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
// Inherits from true_type if From is convertible to To, false_type otherwise.
|
||||
template <typename From, typename To>
|
||||
struct is_convertible
|
||||
: integral_constant<bool,
|
||||
sizeof(internal::ConvertHelper<From, To>::Test(
|
||||
internal::ConvertHelper<From, To>::Create()))
|
||||
== sizeof(small_)> {
|
||||
};
|
||||
#endif
|
||||
|
||||
_END_GOOGLE_NAMESPACE_
|
||||
|
||||
// Right now these macros are no-ops, and mostly just document the fact
|
||||
// these types are PODs, for human use. They may be made more contentful
|
||||
// later. The typedef is just to make it legal to put a semicolon after
|
||||
// these macros.
|
||||
#define DECLARE_POD(TypeName) typedef int Dummy_Type_For_DECLARE_POD
|
||||
#define DECLARE_NESTED_POD(TypeName) DECLARE_POD(TypeName)
|
||||
#define PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT(TemplateName) \
|
||||
typedef int Dummy_Type_For_PROPAGATE_POD_FROM_TEMPLATE_ARGUMENT
|
||||
#define ENFORCE_POD(TypeName) typedef int Dummy_Type_For_ENFORCE_POD
|
||||
|
||||
#endif // BASE_TYPE_TRAITS_H_
|
Loading…
Reference in New Issue
Block a user