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.
Files changed (99) hide show
  1. data/README +61 -27
  2. data/Rakefile +4 -1
  3. data/TODO +5 -0
  4. data/VERSION +1 -1
  5. data/changelog +3 -0
  6. data/ext/extconf.rb +10 -5
  7. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/AUTHORS +0 -0
  8. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/COPYING +0 -0
  9. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/ChangeLog +47 -0
  10. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/INSTALL +0 -0
  11. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/Makefile.am +29 -14
  12. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/Makefile.in +77 -42
  13. data/ext/sparsehash-1.8.1/NEWS +71 -0
  14. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/README +0 -0
  15. data/ext/{sparsehash-1.5.2/README.windows → sparsehash-1.8.1/README_windows.txt} +25 -25
  16. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/TODO +0 -0
  17. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/aclocal.m4 +0 -0
  18. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/compile +0 -0
  19. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/config.guess +0 -0
  20. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/config.sub +0 -0
  21. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/configure +3690 -4560
  22. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/configure.ac +1 -1
  23. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/depcomp +0 -0
  24. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/dense_hash_map.html +65 -5
  25. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/dense_hash_set.html +65 -5
  26. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/designstyle.css +0 -0
  27. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/implementation.html +11 -5
  28. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/index.html +0 -0
  29. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/performance.html +0 -0
  30. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparse_hash_map.html +65 -5
  31. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparse_hash_set.html +65 -5
  32. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/doc/sparsetable.html +0 -0
  33. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/Makefile +0 -0
  34. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/README +0 -0
  35. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/example.c +0 -0
  36. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/libchash.c +0 -0
  37. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/experimental/libchash.h +0 -0
  38. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/google-sparsehash.sln +17 -1
  39. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/install-sh +0 -0
  40. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/acx_pthread.m4 +0 -0
  41. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/google_namespace.m4 +0 -0
  42. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/namespaces.m4 +0 -0
  43. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_hash.m4 +0 -0
  44. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_hash_fun.m4 +0 -0
  45. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/m4/stl_namespace.m4 +0 -0
  46. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/missing +0 -0
  47. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/mkinstalldirs +0 -0
  48. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb.sh +0 -0
  49. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/README +0 -0
  50. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/changelog +24 -0
  51. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/compat +0 -0
  52. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/control +1 -1
  53. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/copyright +0 -0
  54. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/docs +0 -0
  55. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/rules +0 -0
  56. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/sparsehash.dirs +0 -0
  57. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/deb/sparsehash.install +0 -0
  58. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/rpm.sh +0 -0
  59. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/packages/rpm/rpm.spec +1 -1
  60. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/config.h.in +3 -0
  61. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/config.h.include +0 -0
  62. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/dense_hash_map +43 -27
  63. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/dense_hash_set +40 -19
  64. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparse_hash_map +32 -23
  65. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparse_hash_set +31 -21
  66. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsehash/densehashtable.h +481 -298
  67. data/ext/sparsehash-1.8.1/src/google/sparsehash/hashtable-common.h +178 -0
  68. data/ext/sparsehash-1.8.1/src/google/sparsehash/libc_allocator_with_realloc.h +121 -0
  69. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsehash/sparsehashtable.h +404 -233
  70. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/sparsetable +173 -83
  71. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/google/type_traits.h +3 -29
  72. data/ext/sparsehash-1.8.1/src/hash_test_interface.h +1011 -0
  73. data/ext/sparsehash-1.8.1/src/hashtable_test.cc +1733 -0
  74. data/ext/sparsehash-1.8.1/src/libc_allocator_with_realloc_test.cc +129 -0
  75. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/simple_test.cc +1 -1
  76. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/sparsetable_unittest.cc +202 -6
  77. data/ext/sparsehash-1.8.1/src/testutil.h +251 -0
  78. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/time_hash_map.cc +128 -54
  79. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/type_traits_unittest.cc +30 -20
  80. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/config.h +0 -0
  81. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/google/sparsehash/sparseconfig.h +0 -0
  82. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/port.cc +0 -0
  83. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/src/windows/port.h +0 -0
  84. data/ext/sparsehash-1.8.1/vsprojects/hashtable_test/hashtable_test.vcproj +197 -0
  85. data/ext/{sparsehash-1.5.2/vsprojects/hashtable_unittest/hashtable_unittest.vcproj → sparsehash-1.8.1/vsprojects/simple_test/simple_test.vcproj} +9 -8
  86. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj +0 -2
  87. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/time_hash_map/time_hash_map.vcproj +3 -2
  88. data/ext/{sparsehash-1.5.2 → sparsehash-1.8.1}/vsprojects/type_traits_unittest/type_traits_unittest.vcproj +0 -2
  89. data/ext/template/google_hash.cpp.erb +2 -1
  90. data/ext/template/main.cpp.erb +1 -1
  91. data/results.txt +6 -22
  92. data/spec/benchmark.rb +57 -0
  93. data/spec/spec.google_hash.rb +1 -8
  94. metadata +140 -130
  95. data/ext/benchmark.rb +0 -47
  96. data/ext/sparsehash-1.5.2/NEWS +0 -0
  97. data/ext/sparsehash-1.5.2/src/hashtable_unittest.cc +0 -1375
  98. data/ext/sparsehash-1.5.2/src/words +0 -8944
  99. 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 /usr/(local/)?doc/sparsehash-0.1/sparsetable.html
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 it's job. :-)
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 it's job. :-)
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 it's job. :-)
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 value_type* pointer;
648
- typedef const value_type* const_pointer;
649
- typedef table_iterator<sparsegroup<T, GROUP_SIZE> > iterator;
650
- typedef const_table_iterator<sparsegroup<T, GROUP_SIZE> > const_iterator;
651
- typedef table_element_adaptor<sparsegroup<T, GROUP_SIZE> > element_adaptor;
652
- typedef value_type &reference;
653
- typedef const value_type &const_reference;
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
- void* realloc_or_die(void* ptr, size_t num_bytes) {
712
- void* retval = realloc(ptr, num_bytes);
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: failed to allocate %lu bytes for ptr %p",
718
- static_cast<unsigned long>(num_bytes), ptr);
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
- // Valid even for empty group, because NULL+0 is defined to be NULL
731
- value_type* end_it = group + num_buckets;
732
- for (value_type* p = group; p != end_it; ++p)
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
- free(group);
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) { memset(bitmap, 0, sizeof(bitmap)); }
780
- sparsegroup(const sparsegroup& x) : group(0), num_buckets(x.num_buckets) {
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
- value_type* p = allocate_group(x.num_buckets);
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. (Really, we want it to have
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 = (value_type *)
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
- value_type* p = allocate_group(num_buckets + 1);
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) ? true : false; // cast an int to a bool
932
+ return bmtest(i) != 0;
918
933
  }
919
934
  bool test(iterator pos) const {
920
- return bmtest(pos.pos) ? true : false;
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. (Really, we want it to have "trivial
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 = (value_type *)
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
- value_type* p = allocate_group(num_buckets - 1);
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) ) { // trivial to erase empty bucket
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
- value_type *group; // (small) array of T's
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, sparsegroup<T,GROUP_SIZE> &y) {
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 value_type* pointer;
1078
- typedef const value_type* const_pointer;
1079
- typedef table_iterator<sparsetable<T, GROUP_SIZE> > iterator;
1080
- typedef const_table_iterator<sparsetable<T, GROUP_SIZE> > const_iterator;
1081
- typedef table_element_adaptor<sparsetable<T, GROUP_SIZE> > element_adaptor;
1082
- typedef value_type &reference;
1083
- typedef const value_type &const_reference;
1084
- typedef size_t size_type;
1085
- typedef ptrdiff_t difference_type;
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, GROUP_SIZE> > >
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, GROUP_SIZE> > >
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
- private:
1144
- typedef typename vector< sparsegroup<value_type, GROUP_SIZE> >::reference
1145
- GroupsReference;
1146
- typedef typename
1147
- vector< sparsegroup<value_type, GROUP_SIZE> >::const_reference
1148
- GroupsConstReference;
1149
- typedef typename vector< sparsegroup<value_type, GROUP_SIZE> >::iterator
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
- : groups(num_groups(sz)), table_size(sz), num_buckets(0) { }
1176
- // We'll can get away with using the default copy constructor,
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 size_type(-1); }
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
- vector< sparsegroup<value_type, GROUP_SIZE> > groups; // our list of groups
1453
- size_type table_size; // how many buckets they want
1454
- size_type num_buckets; // number of non-empty 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, sparsetable<T,GROUP_SIZE> &y) {
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