google_hash 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.1
data/ext/extconf.rb CHANGED
@@ -34,49 +34,51 @@ else
34
34
  unreachable_int = 63
35
35
  end
36
36
 
37
- ruby_key = {:convert_keys_from_ruby => "", :convert_keys_to_ruby => "", :key_type => "VALUE", :unreachable_key => "current_instance"} # TODO NULL is false here?
38
- #long is not useful to us since we don't support BigNum yet
39
- # i.e. long is basically broken till we do
40
- #long_key = {:assert_key_type => 'T_FIXNUM', :convert_keys_from_ruby => "FIX2LONG",
41
- #:convert_keys_to_ruby => "LONG2FIX", :key_type => "long", :unreachable_key => "1<<#{unreachable_int}"}
37
+ ruby_key = {:convert_keys_from_ruby => "", :convert_keys_to_ruby => "", :key_type => "VALUE", :english_key_type => "ruby",
38
+ :extra_hash_params => ", hashrb, eqrb", :unreachable_key => "current_instance"} # TODO NULL is false here?
42
39
  int_key = {:assert_key_type => 'T_FIXNUM', :convert_keys_from_ruby => "FIX2INT",
43
- :convert_keys_to_ruby => "INT2FIX", :key_type => "int", :unreachable_key => "1<<#{unreachable_int}"}
40
+ :convert_keys_to_ruby => "INT2FIX", :key_type => "int", :unreachable_key => "1<<#{unreachable_int}"}
41
+ # "long" is not useful to us since it's the same as int...
42
+ bignum_key = {:assert_key_type => ['T_BIGNUM', 'T_FIXNUM'], :convert_keys_from_ruby => "rb_big2dbl",
43
+ :convert_keys_to_ruby => "rb_dbl2big", :key_type => "double", :unreachable_key => "1<<#{unreachable_int}", # LODO is this a bignum value though?
44
+ :extra_hash_params => ", hashdouble, eqdouble",
45
+ :extra_set_code => "if(TYPE(set_this) == T_FIXNUM)\nset_this = rb_int2big(set_this);",
46
+ :extra_get_code => "if(TYPE(get_this) == T_FIXNUM) \n get_this = rb_int2big(get_this);"
47
+ } # fixnum's can never be zero...
44
48
 
45
49
 
46
- ruby_value = {:value_type => "VALUE"}
47
- #long_value = {:assert_value_type => 'T_FIXNUM', :convert_values_from_ruby => "FIX2LONG",
48
- #:convert_values_to_ruby => "LONG2FIX", :value_type => "long"}
50
+ ruby_value = {:value_type => "VALUE", :english_value_type => "ruby"}
49
51
  int_value = {:assert_value_type => 'T_FIXNUM', :convert_values_from_ruby => "FIX2INT",
50
- :convert_values_to_ruby => "INT2FIX", :value_type => "int"}
52
+ :convert_values_to_ruby => "INT2FIX", :value_type => "int"}
53
+
54
+ #bignum_value = {:assert_value_type => 'T_BIGNUM', :convert_values_from_ruby => "rb_big2dbl",
55
+ #:convert_values_to_ruby => "rb_dbl2big", :value_type => "double", }
51
56
 
52
57
  init_funcs = []
53
58
 
54
- for key in [ruby_key, int_key] do
59
+ for key in [ruby_key, int_key, bignum_key] do
55
60
  for value in [ruby_value, int_value] do
56
61
  options = key.merge(value)
57
62
  for type in ['sparse', 'dense'] do
58
63
 
59
-
60
64
  # create local variables so that the template can look cleaner
61
65
  unreachable_key = options[:unreachable_key]
62
66
  convert_keys_from_ruby = options[:convert_keys_from_ruby]
63
67
  convert_keys_to_ruby = options[:convert_keys_to_ruby]
64
68
  key_type = options[:key_type]
65
69
  value_type = options[:value_type]
66
- english_key_type = options[:key_type] == 'VALUE' ? 'ruby' : options[:key_type]
67
- english_value_type = options[:value_type] == 'VALUE' ? 'ruby' : options[:value_type]
70
+ english_key_type = options[:english_key_type] || options[:key_type]
71
+ english_value_type = options[:english_value_type] || options[:value_type]
68
72
 
69
- assert_key_type = options[:assert_key_type]
73
+
74
+ assert_key_type = [options[:assert_key_type]].flatten[0]
75
+ assert_key_type2 = [options[:assert_key_type]].flatten[1]
70
76
  convert_values_from_ruby = options[:convert_values_from_ruby]
71
77
  convert_values_to_ruby = options[:convert_values_to_ruby]
72
78
  assert_value_type = options[:assert_value_type]
73
79
 
74
- if options[:key_type] == 'VALUE'
75
- extra_hash_params = ", hashrb, eqrb"
76
- else
77
- extra_hash_params = nil
78
- end
79
-
80
+ extra_hash_params = options[:extra_hash_params]
81
+
80
82
  template = ERB.new(File.read('template/google_hash.cpp.erb'))
81
83
  descriptor = type + '_' + english_key_type + '_to_' + english_value_type;
82
84
  File.write(descriptor + '.cpp', template.result(binding))
data/ext/go.bat CHANGED
@@ -1,3 +1,6 @@
1
1
  rm *.cpp
2
2
  rm *.o
3
- ruby extconf.rb && make clean && make && ruby ..\spec\spec.google_hash.rb
3
+ rm *.so
4
+ ruby extconf.rb
5
+ call make
6
+ spec.bat
@@ -11,6 +11,7 @@ using std::endl;
11
11
  #include <ext/hash_set>
12
12
  <% end %>
13
13
  using __gnu_cxx::hash; // or __gnu_cxx::hash, or maybe tr1::hash, depending on your OS
14
+
14
15
  extern "C" {
15
16
 
16
17
  // some helpers
@@ -40,6 +41,37 @@ struct eqint
40
41
 
41
42
  static ID id_eql, id_hash;
42
43
 
44
+ <% if key_type == 'double' %>
45
+
46
+ struct eqdouble
47
+
48
+ {
49
+
50
+ bool operator()(const double &f1, const double &f2) const
51
+
52
+ {
53
+
54
+ return f1 == f2;
55
+
56
+ }
57
+
58
+ };
59
+
60
+
61
+ extern hash<int> inthash;
62
+
63
+ struct hashdouble {
64
+
65
+ size_t operator ()(const double& foo) const {
66
+
67
+ return inthash((int)foo);
68
+
69
+ }
70
+
71
+ };
72
+
73
+ <% end %>
74
+
43
75
  <% if key_type == 'VALUE' %>
44
76
  static hash<const char*> H;
45
77
 
@@ -103,33 +135,27 @@ struct hashrb
103
135
  switch (TYPE(hval)) {
104
136
  case T_FIXNUM:
105
137
  return hval;
106
- <% unless RUBY_VERSION < '1.9' %>
107
138
  case T_BIGNUM:
108
139
  return LONG2FIX(((long*)(RBIGNUM_DIGITS(hval)))[0]);
109
- <% end %>
110
-
111
140
  default:
112
141
  hval = rb_to_int(hval);
113
142
  goto retry;
114
- }
115
-
143
+ }
116
144
  }
117
145
  };
118
146
 
119
147
  <% end %>
120
148
 
121
- /* we end up not needing this...or at least not using it, I don't know if it would be faster than using the default or not
122
- */
123
-
124
149
 
125
150
  typedef struct {
126
151
  <%= type %>_hash_map< <%= key_type %>, <%= value_type %> <%= extra_hash_params %> > *hash_map;
127
152
  } RCallback;
128
153
 
129
-
130
154
  static void mark_hash_map_values(RCallback *incoming) {
131
155
  <% if value_type == 'VALUE' || key_type == 'VALUE' %>
132
-
156
+
157
+ // only need to iterate if we store *real* Ruby values
158
+
133
159
  for(<%= type %>_hash_map< <%= key_type %>, <%= value_type %> <%= extra_hash_params %> >::iterator it = incoming->hash_map->begin(); it != incoming->hash_map->end(); ++it) {
134
160
 
135
161
  <% if value_type == 'VALUE' %>
@@ -180,16 +206,18 @@ rb_mri_hash_new(VALUE freshly_created) {
180
206
  static VALUE rb_ghash_set(VALUE cb, VALUE set_this, VALUE to_this) {
181
207
  <% if assert_key_type %>
182
208
  if(!(TYPE(set_this) == <%= assert_key_type %>)) {
183
- rb_raise(rb_eTypeError, "not valid key #{assert_key_type}");
209
+ <%= "if(!(TYPE(set_this) == #{assert_key_type2}))" if assert_key_type2 %>
210
+ rb_raise(rb_eTypeError, "not valid key (expected <%= assert_key_type %>)");
184
211
  }
185
212
  <% end %>
186
213
 
187
214
  <% if assert_value_type %>
188
215
  if(!(TYPE(to_this) == <%= assert_value_type %>)) {
189
- rb_raise(rb_eTypeError, "not valid value #{assert_value_type}");
216
+ rb_raise(rb_eTypeError, "not valid value <%=assert_value_type%>");
190
217
  }
191
218
  <% end %>
192
219
 
220
+ <%= options[:extra_set_code] %>
193
221
 
194
222
  RCallback* cbs = GetCallbackStruct(cb);
195
223
  (*cbs->hash_map)[ <%= convert_keys_from_ruby %>(set_this)] = <%= convert_values_from_ruby %>(to_this);
@@ -197,13 +225,15 @@ static VALUE rb_ghash_set(VALUE cb, VALUE set_this, VALUE to_this) {
197
225
  }
198
226
 
199
227
  static VALUE rb_ghash_get(VALUE cb, VALUE get_this) {
200
- // TODO optionally not assert [?]
228
+ // TODO optionally not type check assert anywhere [?]
201
229
  <% if assert_key_type %>
202
230
  if(!(TYPE(get_this) == <%= assert_key_type %>)) {
203
- rb_raise(rb_eTypeError, "not valid key #{assert_key_type}");
231
+ <%= "if(!(TYPE(get_this) == #{assert_key_type2}))" if assert_key_type2 %>
232
+ rb_raise(rb_eTypeError, "not valid get key (expected <%=assert_key_type%>)");
204
233
  }
205
234
  <% end %>
206
235
  RCallback* cbs = GetCallbackStruct(cb);
236
+ <%= options[:extra_get_code] %>
207
237
 
208
238
  <%= type %>_hash_map< <%= key_type %>, <%= value_type %> <%= extra_hash_params %> >::iterator out = cbs->hash_map->find(<%= convert_keys_from_ruby %>(get_this));
209
239
 
@@ -241,7 +271,7 @@ static VALUE rb_ghash_keys(VALUE cb) {
241
271
  }
242
272
 
243
273
 
244
- // only yields for now :)
274
+ // only does yields (blocks) for now :)
245
275
 
246
276
  static VALUE rb_ghash_combination_2(VALUE cb) {
247
277
  RCallback* incoming = GetCallbackStruct(cb);
@@ -13,7 +13,6 @@ void Init_google_hash() {
13
13
  <% end %>
14
14
 
15
15
  rb_eval_string("GoogleHash = GoogleHashDenseRubyToRuby"); // give a default
16
- printf("I set it!");
17
16
  }
18
17
 
19
18
  }
@@ -1,12 +1,16 @@
1
1
  require 'rubygems' if RUBY_VERSION < '1.9'
2
2
  require 'sane'
3
3
  require_relative '../ext/google_hash.so'
4
- require 'spec/autorun'
4
+ begin
5
+ require 'spec/autorun'
6
+ rescue LoadError
7
+ require 'rspec' # rspec2
8
+ end
5
9
 
6
10
  describe "google_hash" do
7
11
 
8
12
  before do
9
- @subject = GoogleHashSparseLongToRuby.new
13
+ @subject = GoogleHashSparseIntToRuby.new
10
14
  end
11
15
 
12
16
  it "should be instantiable" do
@@ -141,7 +145,6 @@ describe "google_hash" do
141
145
  assert sum == 1 + 2 + 1 + 3 + 2 + 3
142
146
  end
143
147
 
144
-
145
148
  it "should have an Array for values, keys" do
146
149
  @subject[33] = 34
147
150
  @subject.keys.should == [33]
@@ -149,22 +152,82 @@ describe "google_hash" do
149
152
  end
150
153
 
151
154
  it "should work with all Longs" do
152
- a = GoogleHashDenseLongToLong.new
155
+ a = GoogleHashDenseIntToInt.new
153
156
  a[3] = 4
154
157
  a[3].should == 4
155
158
  end
156
159
 
157
160
  it "should raise on errant values" do
158
- a = GoogleHashDenseLongToLong.new
161
+ a = GoogleHashDenseIntToInt.new
159
162
  proc { a[3] = 'abc'}.should raise_error
160
- end
163
+ end
161
164
 
162
- it "should have an Enumerator for values, keys, on demand"
165
+ it "should do bignum values as doubles" do
166
+ a = GoogleHashDenseDoubleToInt.new
167
+ a[10000000000000000000] = 1
168
+ a[10000000000000000000].should == 1
169
+ end
163
170
 
164
- it "should have a block for values, keys, on demand"
171
+ it "should not leak" do
172
+ a = GoogleHashDenseIntToInt.new
173
+ 100_000.times {
174
+ a[1] = 1
175
+ a[1]
176
+ a.each{|k, v|}
177
+ a.delete(1) rescue nil
178
+ }
179
+ OS.rss_bytes.should be < 25_000_000
180
+ end
165
181
 
166
- it "should have real sets"
182
+ it "should do int values as doubles" do
183
+ a = GoogleHashDenseDoubleToInt.new
184
+ a[1] = 1
185
+ a[1].should == 1
186
+ end
187
+
188
+ it "should do float values as doubles" do
189
+ a = GoogleHashDenseDoubleToInt.new
190
+ a[1.0] = 1
191
+ a[1.0].should == 1
192
+ end
167
193
 
168
- it "should skip GC when native to native"
194
+ it "should do bignum to doubles et al" do
195
+ pending
196
+ a = GoogleHashDenseDoubleToDouble.new
197
+ a[10000000000000000000] = 1
198
+ a[10000000000000000000].should == 1
199
+ a[1] = 10000000000000000000
200
+ a[1].should == 10000000000000000000
201
+ a[10000000000000000000] = 10000000000000000000
202
+ a[10000000000000000000].should == 10000000000000000000
203
+ end
204
+
205
+ it "should have really real bignums" do
206
+ pending
207
+ fail 'same as above plus'
208
+ a = GoogleHashDenseBignumToRuby.new
209
+ a[10000000000000000000] = 'abc'
210
+ end
211
+
212
+ it 'should be able to delete bignums without leaking' do
213
+ pending
214
+ a = GoogleHashDenseBignumToBignum.new
215
+ 100_000.times {
216
+ a[10000000000000000000] = 1
217
+ a.size.should == 1
218
+ a.delete[10000000000000000000]
219
+ a.size.should == 0
220
+ }
221
+ assert OS.rss_bytes < 100_000
222
+ end
223
+
224
+ it "should have an Enumerator for values, keys, an on demand, getNext enumerator object..."
225
+
226
+ it "should have a block access for values, keys"
227
+
228
+ it "should have sets, too, not just hashes"
229
+
230
+ it "should skip GC when native to native" do
231
+ end
169
232
 
170
233
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google_hash
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
- - 4
9
- - 0
10
- version: 0.4.0
7
+ - 5
8
+ - 1
9
+ version: 0.5.1
11
10
  platform: ruby
12
11
  authors:
13
12
  - rogerdpack
@@ -26,7 +25,6 @@ dependencies:
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
29
- hash: 3
30
28
  segments:
31
29
  - 0
32
30
  version: "0"
@@ -144,7 +142,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
144
142
  requirements:
145
143
  - - ">="
146
144
  - !ruby/object:Gem::Version
147
- hash: 3
148
145
  segments:
149
146
  - 0
150
147
  version: "0"
@@ -153,7 +150,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
150
  requirements:
154
151
  - - ">="
155
152
  - !ruby/object:Gem::Version
156
- hash: 3
157
153
  segments:
158
154
  - 0
159
155
  version: "0"