google_hash 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +61 -27
- data/Rakefile +4 -1
- data/TODO +5 -0
- data/VERSION +1 -1
- data/changelog +3 -0
- data/ext/extconf.rb +10 -5
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/AUTHORS +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/COPYING +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/ChangeLog +47 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/INSTALL +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/Makefile.am +29 -14
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/Makefile.in +77 -42
- data/ext/sparsehash-1.8.1/NEWS +71 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/README +0 -0
- data/ext/{sparsehash-1.5.2/README.windows → sparsehash-1.8.1/README_windows.txt} +25 -25
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/TODO +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/aclocal.m4 +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/compile +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/config.guess +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/config.sub +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/configure +3690 -4560
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/configure.ac +1 -1
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/depcomp +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/dense_hash_map.html +65 -5
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/dense_hash_set.html +65 -5
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/designstyle.css +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/implementation.html +11 -5
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/index.html +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/performance.html +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparse_hash_map.html +65 -5
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparse_hash_set.html +65 -5
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparsetable.html +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/Makefile +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/README +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/example.c +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/libchash.c +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/libchash.h +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/google-sparsehash.sln +17 -1
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/install-sh +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/acx_pthread.m4 +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/google_namespace.m4 +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/namespaces.m4 +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_hash.m4 +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_hash_fun.m4 +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_namespace.m4 +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/missing +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/mkinstalldirs +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb.sh +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/README +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/changelog +24 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/compat +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/control +1 -1
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/copyright +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/docs +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/rules +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/sparsehash.dirs +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/sparsehash.install +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/rpm.sh +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/rpm/rpm.spec +1 -1
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/config.h.in +3 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/config.h.include +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/dense_hash_map +43 -27
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/dense_hash_set +40 -19
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparse_hash_map +32 -23
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparse_hash_set +31 -21
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsehash/densehashtable.h +481 -298
- data/ext/sparsehash-1.8.1/src/google/sparsehash/hashtable-common.h +178 -0
- data/ext/sparsehash-1.8.1/src/google/sparsehash/libc_allocator_with_realloc.h +121 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsehash/sparsehashtable.h +404 -233
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsetable +173 -83
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/type_traits.h +3 -29
- data/ext/sparsehash-1.8.1/src/hash_test_interface.h +1011 -0
- data/ext/sparsehash-1.8.1/src/hashtable_test.cc +1733 -0
- data/ext/sparsehash-1.8.1/src/libc_allocator_with_realloc_test.cc +129 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/simple_test.cc +1 -1
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/sparsetable_unittest.cc +202 -6
- data/ext/sparsehash-1.8.1/src/testutil.h +251 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/time_hash_map.cc +128 -54
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/type_traits_unittest.cc +30 -20
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/config.h +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/google/sparsehash/sparseconfig.h +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/port.cc +0 -0
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/port.h +0 -0
- data/ext/sparsehash-1.8.1/vsprojects/hashtable_test/hashtable_test.vcproj +197 -0
- data/ext/{sparsehash-1.5.2/vsprojects/hashtable_unittest/hashtable_unittest.vcproj → sparsehash-1.8.1/vsprojects/simple_test/simple_test.vcproj} +9 -8
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj +0 -2
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/time_hash_map/time_hash_map.vcproj +3 -2
- data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/type_traits_unittest/type_traits_unittest.vcproj +0 -2
- data/ext/template/google_hash.cpp.erb +2 -1
- data/ext/template/main.cpp.erb +1 -1
- data/results.txt +6 -22
- data/spec/benchmark.rb +57 -0
- data/spec/spec.google_hash.rb +1 -8
- metadata +140 -130
- data/ext/benchmark.rb +0 -47
- data/ext/sparsehash-1.5.2/NEWS +0 -0
- data/ext/sparsehash-1.5.2/src/hashtable_unittest.cc +0 -1375
- data/ext/sparsehash-1.5.2/src/words +0 -8944
- data/types.txt +0 -18
|
@@ -50,8 +50,7 @@
|
|
|
50
50
|
// because of this container's memory economy, each insert and delete
|
|
51
51
|
// causes a memory reallocation.
|
|
52
52
|
//
|
|
53
|
-
// See
|
|
54
|
-
// for information about how to use this class.
|
|
53
|
+
// See doc/sparsetable.html for information about how to use this class.
|
|
55
54
|
|
|
56
55
|
#ifndef _SPARSETABLE_H_
|
|
57
56
|
#define _SPARSETABLE_H_
|
|
@@ -73,6 +72,7 @@
|
|
|
73
72
|
#include <algorithm> // equal, lexicographical_compare, swap,...
|
|
74
73
|
#include <memory> // uninitialized_copy
|
|
75
74
|
#include <vector> // a sparsetable is a vector of groups
|
|
75
|
+
#include <google/sparsehash/libc_allocator_with_realloc.h>
|
|
76
76
|
#include <google/type_traits.h> // for true_type, integral_constant, etc.
|
|
77
77
|
|
|
78
78
|
#if STDC_HEADERS
|
|
@@ -83,8 +83,6 @@
|
|
|
83
83
|
#endif
|
|
84
84
|
#endif
|
|
85
85
|
|
|
86
|
-
_START_GOOGLE_NAMESPACE_
|
|
87
|
-
|
|
88
86
|
#ifndef HAVE_U_INT16_T
|
|
89
87
|
# if defined HAVE_UINT16_T
|
|
90
88
|
typedef uint16_t u_int16_t; // true on solaris, possibly other C99 libc's
|
|
@@ -98,6 +96,8 @@ _START_GOOGLE_NAMESPACE_
|
|
|
98
96
|
# endif
|
|
99
97
|
#endif
|
|
100
98
|
|
|
99
|
+
_START_GOOGLE_NAMESPACE_
|
|
100
|
+
|
|
101
101
|
using STL_NAMESPACE::vector;
|
|
102
102
|
using STL_NAMESPACE::uninitialized_copy;
|
|
103
103
|
|
|
@@ -188,7 +188,7 @@ class table_iterator {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
// Arithmetic: we just do arithmetic on pos. We don't even need to
|
|
191
|
-
// do bounds checking, since STL doesn't consider that
|
|
191
|
+
// do bounds checking, since STL doesn't consider that its job. :-)
|
|
192
192
|
iterator& operator+=(size_type t) { pos += t; check(); return *this; }
|
|
193
193
|
iterator& operator-=(size_type t) { pos -= t; check(); return *this; }
|
|
194
194
|
iterator& operator++() { ++pos; check(); return *this; }
|
|
@@ -271,7 +271,7 @@ class const_table_iterator {
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
// Arithmetic: we just do arithmetic on pos. We don't even need to
|
|
274
|
-
// do bounds checking, since STL doesn't consider that
|
|
274
|
+
// do bounds checking, since STL doesn't consider that its job. :-)
|
|
275
275
|
const_iterator& operator+=(size_type t) { pos += t; check(); return *this; }
|
|
276
276
|
const_iterator& operator-=(size_type t) { pos -= t; check(); return *this; }
|
|
277
277
|
const_iterator& operator++() { ++pos; check(); return *this; }
|
|
@@ -388,7 +388,7 @@ class two_d_iterator {
|
|
|
388
388
|
pointer operator->() const { return &(operator*()); }
|
|
389
389
|
|
|
390
390
|
// Arithmetic: we just do arithmetic on pos. We don't even need to
|
|
391
|
-
// do bounds checking, since STL doesn't consider that
|
|
391
|
+
// do bounds checking, since STL doesn't consider that its job. :-)
|
|
392
392
|
// NOTE: this is not amortized constant time! What do we do about it?
|
|
393
393
|
void advance_past_end() { // used when col_current points to end()
|
|
394
394
|
while ( col_current == row_current->TWOD_END_() ) { // end of current row
|
|
@@ -600,7 +600,7 @@ class destructive_two_d_iterator {
|
|
|
600
600
|
#undef TWOD_CONST_ITER_
|
|
601
601
|
|
|
602
602
|
|
|
603
|
-
|
|
603
|
+
|
|
604
604
|
|
|
605
605
|
// SPARSE-TABLE
|
|
606
606
|
// ------------
|
|
@@ -639,18 +639,25 @@ class destructive_two_d_iterator {
|
|
|
639
639
|
add_to |= (static_cast<size_type>(x) << ((offset) % (sizeof(add_to)*8))); \
|
|
640
640
|
} while (0)
|
|
641
641
|
|
|
642
|
-
template <class T, u_int16_t GROUP_SIZE>
|
|
642
|
+
template <class T, u_int16_t GROUP_SIZE, class Alloc>
|
|
643
643
|
class sparsegroup {
|
|
644
|
+
private:
|
|
645
|
+
typedef typename Alloc::template rebind<T>::other value_alloc_type;
|
|
646
|
+
|
|
644
647
|
public:
|
|
645
648
|
// Basic types
|
|
646
649
|
typedef T value_type;
|
|
647
|
-
typedef
|
|
648
|
-
typedef
|
|
649
|
-
typedef
|
|
650
|
-
typedef
|
|
651
|
-
typedef
|
|
652
|
-
|
|
653
|
-
typedef
|
|
650
|
+
typedef Alloc allocator_type;
|
|
651
|
+
typedef typename value_alloc_type::reference reference;
|
|
652
|
+
typedef typename value_alloc_type::const_reference const_reference;
|
|
653
|
+
typedef typename value_alloc_type::pointer pointer;
|
|
654
|
+
typedef typename value_alloc_type::const_pointer const_pointer;
|
|
655
|
+
|
|
656
|
+
typedef table_iterator<sparsegroup<T, GROUP_SIZE, Alloc> > iterator;
|
|
657
|
+
typedef const_table_iterator<sparsegroup<T, GROUP_SIZE, Alloc> >
|
|
658
|
+
const_iterator;
|
|
659
|
+
typedef table_element_adaptor<sparsegroup<T, GROUP_SIZE, Alloc> >
|
|
660
|
+
element_adaptor;
|
|
654
661
|
typedef u_int16_t size_type; // max # of buckets
|
|
655
662
|
typedef int16_t difference_type;
|
|
656
663
|
typedef STL_NAMESPACE::reverse_iterator<const_iterator> const_reverse_iterator;
|
|
@@ -708,37 +715,38 @@ class sparsegroup {
|
|
|
708
715
|
void bmset(size_type i) { bitmap[charbit(i)] |= modbit(i); }
|
|
709
716
|
void bmclear(size_type i) { bitmap[charbit(i)] &= ~modbit(i); }
|
|
710
717
|
|
|
711
|
-
|
|
712
|
-
|
|
718
|
+
pointer allocate_group(size_type n) {
|
|
719
|
+
pointer retval = allocator.allocate(n);
|
|
713
720
|
if (retval == NULL) {
|
|
714
721
|
// We really should use PRIuS here, but I don't want to have to add
|
|
715
722
|
// a whole new configure option, with concomitant macro namespace
|
|
716
723
|
// pollution, just to print this (unlikely) error message. So I cast.
|
|
717
|
-
fprintf(stderr, "FATAL ERROR:
|
|
718
|
-
|
|
724
|
+
fprintf(stderr, "sparsehash: FATAL ERROR: "
|
|
725
|
+
"failed to allocate %lu groups\n",
|
|
726
|
+
static_cast<unsigned long>(n));
|
|
719
727
|
exit(1);
|
|
720
728
|
}
|
|
721
729
|
return retval;
|
|
722
730
|
}
|
|
723
731
|
|
|
724
|
-
value_type* allocate_group(size_t n) {
|
|
725
|
-
return static_cast<value_type*>(realloc_or_die(NULL,
|
|
726
|
-
n * sizeof(value_type)));
|
|
727
|
-
}
|
|
728
|
-
|
|
729
732
|
void free_group() {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
for (
|
|
733
|
+
if (!group) return;
|
|
734
|
+
pointer end_it = group + num_buckets;
|
|
735
|
+
for (pointer p = group; p != end_it; ++p)
|
|
733
736
|
p->~value_type();
|
|
734
|
-
|
|
737
|
+
allocator.deallocate(group, num_buckets);
|
|
735
738
|
group = NULL;
|
|
736
739
|
}
|
|
737
740
|
|
|
738
741
|
public: // get_iter() in sparsetable needs it
|
|
739
742
|
// We need a small function that tells us how many set bits there are
|
|
740
743
|
// in positions 0..i-1 of the bitmap. It uses a big table.
|
|
741
|
-
// We make it static so templates don't allocate lots of these tables
|
|
744
|
+
// We make it static so templates don't allocate lots of these tables.
|
|
745
|
+
// There are lots of ways to do this calculation (called 'popcount').
|
|
746
|
+
// The 8-bit table lookup is one of the fastest, though this
|
|
747
|
+
// implementation suffers from not doing any loop unrolling. See, eg,
|
|
748
|
+
// http://www.dalkescientific.com/writings/diary/archive/2008/07/03/hakmem_and_other_popcounts.html
|
|
749
|
+
// http://gurmeetsingh.wordpress.com/2008/08/05/fast-bit-counting-routines/
|
|
742
750
|
static size_type pos_to_offset(const unsigned char *bm, size_type pos) {
|
|
743
751
|
// We could make these ints. The tradeoff is size (eg does it overwhelm
|
|
744
752
|
// the cache?) vs efficiency in referencing sub-word-sized array elements
|
|
@@ -776,8 +784,11 @@ class sparsegroup {
|
|
|
776
784
|
|
|
777
785
|
public:
|
|
778
786
|
// Constructors -- default and copy -- and destructor
|
|
779
|
-
sparsegroup() : group(0), num_buckets(0) {
|
|
780
|
-
|
|
787
|
+
sparsegroup(allocator_type& a) : allocator(a), group(0), num_buckets(0) {
|
|
788
|
+
memset(bitmap, 0, sizeof(bitmap));
|
|
789
|
+
}
|
|
790
|
+
sparsegroup(const sparsegroup& x)
|
|
791
|
+
: allocator(x.allocator), group(0), num_buckets(x.num_buckets) {
|
|
781
792
|
if ( num_buckets ) {
|
|
782
793
|
group = allocate_group(x.num_buckets);
|
|
783
794
|
uninitialized_copy(x.group, x.group + x.num_buckets, group);
|
|
@@ -794,7 +805,7 @@ class sparsegroup {
|
|
|
794
805
|
if ( x.num_buckets == 0 ) {
|
|
795
806
|
free_group();
|
|
796
807
|
} else {
|
|
797
|
-
|
|
808
|
+
pointer p = allocate_group(x.num_buckets);
|
|
798
809
|
uninitialized_copy(x.group, x.group + x.num_buckets, p);
|
|
799
810
|
free_group();
|
|
800
811
|
group = p;
|
|
@@ -810,6 +821,7 @@ class sparsegroup {
|
|
|
810
821
|
for ( int i = 0; i < sizeof(bitmap) / sizeof(*bitmap); ++i )
|
|
811
822
|
STL_NAMESPACE::swap(bitmap[i], x.bitmap[i]); // swap not defined on arrays
|
|
812
823
|
STL_NAMESPACE::swap(num_buckets, x.num_buckets);
|
|
824
|
+
// we purposefully don't swap the allocator, which may not be swap-able
|
|
813
825
|
}
|
|
814
826
|
|
|
815
827
|
// It's always nice to be able to clear a table without deallocating it
|
|
@@ -864,14 +876,14 @@ class sparsegroup {
|
|
|
864
876
|
|
|
865
877
|
private:
|
|
866
878
|
// Create space at group[offset], assuming value_type has trivial
|
|
867
|
-
// copy constructor and destructor
|
|
879
|
+
// copy constructor and destructor, and the allocator_type is
|
|
880
|
+
// the default libc_allocator_with_alloc. (Really, we want it to have
|
|
868
881
|
// "trivial move", because that's what realloc and memmove both do.
|
|
869
882
|
// But there's no way to capture that using type_traits, so we
|
|
870
883
|
// pretend that move(x, y) is equivalent to "x.~T(); new(x) T(y);"
|
|
871
884
|
// which is pretty much correct, if a bit conservative.)
|
|
872
885
|
void set_aux(size_type offset, true_type) {
|
|
873
|
-
group = (
|
|
874
|
-
realloc_or_die(group, sizeof(*group) * (num_buckets+1));
|
|
886
|
+
group = allocator.realloc_or_die(group, num_buckets+1);
|
|
875
887
|
// This is equivalent to memmove(), but faster on my Intel P4,
|
|
876
888
|
// at least with gcc4.1 -O2 / glibc 2.3.6.
|
|
877
889
|
for (size_type i = num_buckets; i > offset; --i)
|
|
@@ -879,9 +891,10 @@ class sparsegroup {
|
|
|
879
891
|
}
|
|
880
892
|
|
|
881
893
|
// Create space at group[offset], without special assumptions about value_type
|
|
894
|
+
// and allocator_type.
|
|
882
895
|
void set_aux(size_type offset, false_type) {
|
|
883
896
|
// This is valid because 0 <= offset <= num_buckets
|
|
884
|
-
|
|
897
|
+
pointer p = allocate_group(num_buckets + 1);
|
|
885
898
|
uninitialized_copy(group, group + offset, p);
|
|
886
899
|
uninitialized_copy(group + offset, group + num_buckets, p + offset + 1);
|
|
887
900
|
free_group();
|
|
@@ -900,7 +913,9 @@ class sparsegroup {
|
|
|
900
913
|
} else {
|
|
901
914
|
typedef integral_constant<bool,
|
|
902
915
|
(has_trivial_copy<value_type>::value &&
|
|
903
|
-
has_trivial_destructor<value_type>::value
|
|
916
|
+
has_trivial_destructor<value_type>::value &&
|
|
917
|
+
is_same<allocator_type,
|
|
918
|
+
libc_allocator_with_realloc<value_type> >::value)>
|
|
904
919
|
realloc_and_memmove_ok; // we pretend mv(x,y) == "x.~T(); new(x) T(y)"
|
|
905
920
|
set_aux(offset, realloc_and_memmove_ok());
|
|
906
921
|
++num_buckets;
|
|
@@ -914,15 +929,16 @@ class sparsegroup {
|
|
|
914
929
|
|
|
915
930
|
// We let you see if a bucket is non-empty without retrieving it
|
|
916
931
|
bool test(size_type i) const {
|
|
917
|
-
return bmtest(i)
|
|
932
|
+
return bmtest(i) != 0;
|
|
918
933
|
}
|
|
919
934
|
bool test(iterator pos) const {
|
|
920
|
-
return bmtest(pos.pos)
|
|
935
|
+
return bmtest(pos.pos) != 0;
|
|
921
936
|
}
|
|
922
937
|
|
|
923
938
|
private:
|
|
924
939
|
// Shrink the array, assuming value_type has trivial copy
|
|
925
|
-
// constructor and destructor
|
|
940
|
+
// constructor and destructor, and the allocator_type is the default
|
|
941
|
+
// libc_allocator_with_alloc. (Really, we want it to have "trivial
|
|
926
942
|
// move", because that's what realloc and memmove both do. But
|
|
927
943
|
// there's no way to capture that using type_traits, so we pretend
|
|
928
944
|
// that move(x, y) is equivalent to ""x.~T(); new(x) T(y);"
|
|
@@ -936,14 +952,14 @@ class sparsegroup {
|
|
|
936
952
|
assert(num_buckets > 0);
|
|
937
953
|
for (size_type i = offset; i < num_buckets-1; ++i)
|
|
938
954
|
memcpy(group + i, group + i+1, sizeof(*group)); // hopefully inlined!
|
|
939
|
-
group = (
|
|
940
|
-
realloc_or_die(group, sizeof(*group) * (num_buckets-1));
|
|
955
|
+
group = allocator.realloc_or_die(group, num_buckets-1);
|
|
941
956
|
}
|
|
942
957
|
|
|
943
|
-
// Shrink the array, without any special assumptions about value_type
|
|
958
|
+
// Shrink the array, without any special assumptions about value_type and
|
|
959
|
+
// allocator_type.
|
|
944
960
|
void erase_aux(size_type offset, false_type) {
|
|
945
961
|
// This is valid because 0 <= offset < num_buckets. Note the inequality.
|
|
946
|
-
|
|
962
|
+
pointer p = allocate_group(num_buckets - 1);
|
|
947
963
|
uninitialized_copy(group, group + offset, p);
|
|
948
964
|
uninitialized_copy(group + offset + 1, group + num_buckets, p + offset);
|
|
949
965
|
free_group();
|
|
@@ -956,7 +972,7 @@ class sparsegroup {
|
|
|
956
972
|
// TODO(austern): Make this exception safe: handle exceptions from
|
|
957
973
|
// value_type's copy constructor.
|
|
958
974
|
void erase(size_type i) {
|
|
959
|
-
if ( bmtest(i) ) {
|
|
975
|
+
if ( bmtest(i) ) { // trivial to erase empty bucket
|
|
960
976
|
size_type offset = pos_to_offset(bitmap,i); // where we'll find (or insert)
|
|
961
977
|
if ( num_buckets == 1 ) {
|
|
962
978
|
free_group();
|
|
@@ -964,7 +980,10 @@ class sparsegroup {
|
|
|
964
980
|
} else {
|
|
965
981
|
typedef integral_constant<bool,
|
|
966
982
|
(has_trivial_copy<value_type>::value &&
|
|
967
|
-
has_trivial_destructor<value_type>::value
|
|
983
|
+
has_trivial_destructor<value_type>::value &&
|
|
984
|
+
is_same<
|
|
985
|
+
allocator_type,
|
|
986
|
+
libc_allocator_with_realloc<value_type> >::value)>
|
|
968
987
|
realloc_and_memmove_ok; // pretend mv(x,y) == "x.~T(); new(x) T(y)"
|
|
969
988
|
erase_aux(offset, realloc_and_memmove_ok());
|
|
970
989
|
}
|
|
@@ -1054,48 +1073,113 @@ class sparsegroup {
|
|
|
1054
1073
|
bool operator>=(const sparsegroup& x) const { return !(*this < x); }
|
|
1055
1074
|
|
|
1056
1075
|
private:
|
|
1076
|
+
template <class A>
|
|
1077
|
+
class alloc_impl : public A {
|
|
1078
|
+
public:
|
|
1079
|
+
typedef typename A::pointer pointer;
|
|
1080
|
+
typedef typename A::size_type size_type;
|
|
1081
|
+
|
|
1082
|
+
// Convert a normal allocator to one that has realloc_or_die()
|
|
1083
|
+
alloc_impl(const A& a) : A(a) { }
|
|
1084
|
+
|
|
1085
|
+
// realloc_or_die should only be used when using the default
|
|
1086
|
+
// allocator (libc_allocator_with_realloc).
|
|
1087
|
+
pointer realloc_or_die(pointer ptr, size_type n) {
|
|
1088
|
+
fprintf(stderr, "realloc_or_die is only supported for "
|
|
1089
|
+
"libc_allocator_with_realloc");
|
|
1090
|
+
exit(1);
|
|
1091
|
+
return NULL;
|
|
1092
|
+
}
|
|
1093
|
+
};
|
|
1094
|
+
|
|
1095
|
+
// A template specialization of alloc_impl for
|
|
1096
|
+
// libc_allocator_with_realloc that can handle realloc_or_die.
|
|
1097
|
+
template <class A>
|
|
1098
|
+
class alloc_impl<libc_allocator_with_realloc<A> >
|
|
1099
|
+
: public libc_allocator_with_realloc<A> {
|
|
1100
|
+
public:
|
|
1101
|
+
typedef typename libc_allocator_with_realloc<A>::pointer pointer;
|
|
1102
|
+
typedef typename libc_allocator_with_realloc<A>::size_type size_type;
|
|
1103
|
+
|
|
1104
|
+
alloc_impl(const libc_allocator_with_realloc<A>& a)
|
|
1105
|
+
: libc_allocator_with_realloc<A>(a) { }
|
|
1106
|
+
|
|
1107
|
+
pointer realloc_or_die(pointer ptr, size_type n) {
|
|
1108
|
+
pointer retval = this->reallocate(ptr, n);
|
|
1109
|
+
if (retval == NULL) {
|
|
1110
|
+
// We really should use PRIuS here, but I don't want to have to add
|
|
1111
|
+
// a whole new configure option, with concomitant macro namespace
|
|
1112
|
+
// pollution, just to print this (unlikely) error message. So I cast.
|
|
1113
|
+
fprintf(stderr, "sparsehash: FATAL ERROR: failed to reallocate "
|
|
1114
|
+
"%lu elements for ptr %p",
|
|
1115
|
+
static_cast<unsigned long>(n), ptr);
|
|
1116
|
+
exit(1);
|
|
1117
|
+
}
|
|
1118
|
+
return retval;
|
|
1119
|
+
}
|
|
1120
|
+
};
|
|
1121
|
+
|
|
1057
1122
|
// The actual data
|
|
1058
|
-
|
|
1123
|
+
alloc_impl<value_alloc_type> allocator; // allocator for memory
|
|
1124
|
+
pointer group; // (small) array of T's
|
|
1059
1125
|
unsigned char bitmap[(GROUP_SIZE-1)/8 + 1]; // fancy math is so we round up
|
|
1060
1126
|
size_type num_buckets; // limits GROUP_SIZE to 64K
|
|
1061
1127
|
};
|
|
1062
1128
|
|
|
1063
1129
|
// We need a global swap as well
|
|
1064
|
-
template <class T, u_int16_t GROUP_SIZE>
|
|
1065
|
-
inline void swap(sparsegroup<T,GROUP_SIZE> &x,
|
|
1130
|
+
template <class T, u_int16_t GROUP_SIZE, class Alloc>
|
|
1131
|
+
inline void swap(sparsegroup<T,GROUP_SIZE,Alloc> &x,
|
|
1132
|
+
sparsegroup<T,GROUP_SIZE,Alloc> &y) {
|
|
1066
1133
|
x.swap(y);
|
|
1067
1134
|
}
|
|
1068
1135
|
|
|
1069
1136
|
// ---------------------------------------------------------------------------
|
|
1070
1137
|
|
|
1071
1138
|
|
|
1072
|
-
template <class T, u_int16_t GROUP_SIZE = DEFAULT_SPARSEGROUP_SIZE
|
|
1139
|
+
template <class T, u_int16_t GROUP_SIZE = DEFAULT_SPARSEGROUP_SIZE,
|
|
1140
|
+
class Alloc = libc_allocator_with_realloc<T> >
|
|
1073
1141
|
class sparsetable {
|
|
1142
|
+
private:
|
|
1143
|
+
typedef typename Alloc::template rebind<T>::other value_alloc_type;
|
|
1144
|
+
typedef typename Alloc::template rebind<
|
|
1145
|
+
sparsegroup<T, GROUP_SIZE, value_alloc_type> >::other vector_alloc;
|
|
1146
|
+
|
|
1074
1147
|
public:
|
|
1075
1148
|
// Basic types
|
|
1076
1149
|
typedef T value_type; // stolen from stl_vector.h
|
|
1077
|
-
typedef
|
|
1078
|
-
typedef
|
|
1079
|
-
typedef
|
|
1080
|
-
typedef
|
|
1081
|
-
typedef
|
|
1082
|
-
typedef
|
|
1083
|
-
typedef
|
|
1084
|
-
typedef
|
|
1085
|
-
typedef
|
|
1150
|
+
typedef Alloc allocator_type;
|
|
1151
|
+
typedef typename value_alloc_type::size_type size_type;
|
|
1152
|
+
typedef typename value_alloc_type::difference_type difference_type;
|
|
1153
|
+
typedef typename value_alloc_type::reference reference;
|
|
1154
|
+
typedef typename value_alloc_type::const_reference const_reference;
|
|
1155
|
+
typedef typename value_alloc_type::pointer pointer;
|
|
1156
|
+
typedef typename value_alloc_type::const_pointer const_pointer;
|
|
1157
|
+
typedef table_iterator<sparsetable<T, GROUP_SIZE, Alloc> > iterator;
|
|
1158
|
+
typedef const_table_iterator<sparsetable<T, GROUP_SIZE, Alloc> >
|
|
1159
|
+
const_iterator;
|
|
1160
|
+
typedef table_element_adaptor<sparsetable<T, GROUP_SIZE, Alloc> >
|
|
1161
|
+
element_adaptor;
|
|
1086
1162
|
typedef STL_NAMESPACE::reverse_iterator<const_iterator> const_reverse_iterator;
|
|
1087
1163
|
typedef STL_NAMESPACE::reverse_iterator<iterator> reverse_iterator;
|
|
1088
1164
|
|
|
1089
1165
|
// These are our special iterators, that go over non-empty buckets in a
|
|
1090
1166
|
// table. These aren't const only because you can change non-empty bcks.
|
|
1091
|
-
typedef two_d_iterator< vector< sparsegroup<value_type, GROUP_SIZE
|
|
1167
|
+
typedef two_d_iterator< vector< sparsegroup<value_type, GROUP_SIZE,
|
|
1168
|
+
value_alloc_type>,
|
|
1169
|
+
vector_alloc> >
|
|
1092
1170
|
nonempty_iterator;
|
|
1093
|
-
typedef const_two_d_iterator< vector< sparsegroup<value_type,
|
|
1171
|
+
typedef const_two_d_iterator< vector< sparsegroup<value_type,
|
|
1172
|
+
GROUP_SIZE,
|
|
1173
|
+
value_alloc_type>,
|
|
1174
|
+
vector_alloc> >
|
|
1094
1175
|
const_nonempty_iterator;
|
|
1095
1176
|
typedef STL_NAMESPACE::reverse_iterator<nonempty_iterator> reverse_nonempty_iterator;
|
|
1096
1177
|
typedef STL_NAMESPACE::reverse_iterator<const_nonempty_iterator> const_reverse_nonempty_iterator;
|
|
1097
1178
|
// Another special iterator: it frees memory as it iterates (used to resize)
|
|
1098
|
-
typedef destructive_two_d_iterator< vector< sparsegroup<value_type,
|
|
1179
|
+
typedef destructive_two_d_iterator< vector< sparsegroup<value_type,
|
|
1180
|
+
GROUP_SIZE,
|
|
1181
|
+
value_alloc_type>,
|
|
1182
|
+
vector_alloc> >
|
|
1099
1183
|
destructive_iterator;
|
|
1100
1184
|
|
|
1101
1185
|
// Iterator functions
|
|
@@ -1140,16 +1224,13 @@ class sparsetable {
|
|
|
1140
1224
|
return destructive_iterator(groups.begin(), groups.end(), groups.end());
|
|
1141
1225
|
}
|
|
1142
1226
|
|
|
1143
|
-
|
|
1144
|
-
typedef
|
|
1145
|
-
|
|
1146
|
-
typedef typename
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
typedef typename
|
|
1150
|
-
GroupsIterator;
|
|
1151
|
-
typedef typename vector< sparsegroup<value_type, GROUP_SIZE> >::const_iterator
|
|
1152
|
-
GroupsConstIterator;
|
|
1227
|
+
typedef sparsegroup<value_type, GROUP_SIZE, allocator_type> group_type;
|
|
1228
|
+
typedef vector<group_type, vector_alloc > group_vector_type;
|
|
1229
|
+
|
|
1230
|
+
typedef typename group_vector_type::reference GroupsReference;
|
|
1231
|
+
typedef typename group_vector_type::const_reference GroupsConstReference;
|
|
1232
|
+
typedef typename group_vector_type::iterator GroupsIterator;
|
|
1233
|
+
typedef typename group_vector_type::const_iterator GroupsConstIterator;
|
|
1153
1234
|
|
|
1154
1235
|
// How to deal with the proper group
|
|
1155
1236
|
static size_type num_groups(size_type num) { // how many to hold num buckets
|
|
@@ -1171,9 +1252,12 @@ class sparsetable {
|
|
|
1171
1252
|
|
|
1172
1253
|
public:
|
|
1173
1254
|
// Constructors -- default, normal (when you specify size), and copy
|
|
1174
|
-
sparsetable(size_type sz = 0)
|
|
1175
|
-
|
|
1176
|
-
|
|
1255
|
+
sparsetable(size_type sz = 0, Alloc alloc = Alloc())
|
|
1256
|
+
: groups(vector_alloc(alloc)),
|
|
1257
|
+
table_size(sz), num_buckets(0), allocator(alloc) {
|
|
1258
|
+
groups.resize(num_groups(sz), group_type(allocator));
|
|
1259
|
+
}
|
|
1260
|
+
// We can get away with using the default copy constructor,
|
|
1177
1261
|
// and default destructor, and hence the default operator=. Huzzah!
|
|
1178
1262
|
|
|
1179
1263
|
// Many STL algorithms use swap instead of copy constructors
|
|
@@ -1192,19 +1276,23 @@ class sparsetable {
|
|
|
1192
1276
|
num_buckets = 0;
|
|
1193
1277
|
}
|
|
1194
1278
|
|
|
1279
|
+
// ACCESSOR FUNCTIONS for the things we templatize on, basically
|
|
1280
|
+
allocator_type get_allocator() const { return allocator; }
|
|
1281
|
+
|
|
1282
|
+
|
|
1195
1283
|
// Functions that tell you about size.
|
|
1196
1284
|
// NOTE: empty() is non-intuitive! It does not tell you the number
|
|
1197
1285
|
// of not-empty buckets (use num_nonempty() for that). Instead
|
|
1198
1286
|
// it says whether you've allocated any buckets or not.
|
|
1199
1287
|
size_type size() const { return table_size; }
|
|
1200
|
-
size_type max_size() const { return
|
|
1288
|
+
size_type max_size() const { return allocator.max_size(); }
|
|
1201
1289
|
bool empty() const { return table_size == 0; }
|
|
1202
1290
|
// We also may want to know how many *used* buckets there are
|
|
1203
1291
|
size_type num_nonempty() const { return num_buckets; }
|
|
1204
1292
|
|
|
1205
1293
|
// OK, we'll let you resize one of these puppies
|
|
1206
1294
|
void resize(size_type new_size) {
|
|
1207
|
-
groups.resize(num_groups(new_size));
|
|
1295
|
+
groups.resize(num_groups(new_size), group_type(allocator));
|
|
1208
1296
|
if ( new_size < table_size) { // lower num_buckets, clear last group
|
|
1209
1297
|
if ( pos_in_group(new_size) > 0 ) // need to clear inside last group
|
|
1210
1298
|
groups.back().erase(groups.back().begin() + pos_in_group(new_size),
|
|
@@ -1449,14 +1537,16 @@ class sparsetable {
|
|
|
1449
1537
|
|
|
1450
1538
|
private:
|
|
1451
1539
|
// The actual data
|
|
1452
|
-
|
|
1453
|
-
size_type table_size;
|
|
1454
|
-
size_type num_buckets;
|
|
1540
|
+
group_vector_type groups; // our list of groups
|
|
1541
|
+
size_type table_size; // how many buckets they want
|
|
1542
|
+
size_type num_buckets; // number of non-empty buckets
|
|
1543
|
+
allocator_type allocator; // just passed in to sparsegroup
|
|
1455
1544
|
};
|
|
1456
1545
|
|
|
1457
1546
|
// We need a global swap as well
|
|
1458
|
-
template <class T, u_int16_t GROUP_SIZE>
|
|
1459
|
-
inline void swap(sparsetable<T,GROUP_SIZE> &x,
|
|
1547
|
+
template <class T, u_int16_t GROUP_SIZE, class Alloc>
|
|
1548
|
+
inline void swap(sparsetable<T,GROUP_SIZE,Alloc> &x,
|
|
1549
|
+
sparsetable<T,GROUP_SIZE,Alloc> &y) {
|
|
1460
1550
|
x.swap(y);
|
|
1461
1551
|
}
|
|
1462
1552
|
|