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.
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