google_hash 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|