google_hash 0.4.0 → 0.5.1

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