google_hash 0.0.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -1
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/ext/benchmark.rb +9 -0
- data/ext/extconf.rb +19 -1
- data/ext/go.bat +1 -0
- data/ext/main.cpp +12 -0
- data/ext/template/go.cpp +114 -0
- data/results.txt +57 -0
- metadata +9 -6
- data/ext/go.cpp +0 -109
- data/ext/test.rb +0 -10
data/README
CHANGED
@@ -2,7 +2,7 @@ This is a ruby gem that wraps google's "sparse" and "dense" hashes.
|
|
2
2
|
|
3
3
|
Current usage:
|
4
4
|
|
5
|
-
a =
|
5
|
+
a = GoogleHashSmall.new
|
6
6
|
a[3] = 'abc' # only accept integers for keys currently.
|
7
7
|
|
8
8
|
The dense hash tends to be a bit faster than ruby's normal hash, and the sparse hash tends to use less RAM.
|
data/Rakefile
CHANGED
@@ -2,10 +2,10 @@ require 'jeweler'
|
|
2
2
|
Jeweler::Tasks.new do |gemspec|
|
3
3
|
gemspec.name = "google_hash"
|
4
4
|
gemspec.summary = "Ruby wrappers to the google hash library"
|
5
|
-
gemspec.description =
|
5
|
+
gemspec.description = gemspec.summary
|
6
6
|
gemspec.email = "rogerdpack@gmail.com"
|
7
7
|
gemspec.homepage = "http://github.com/rdp/ruby_google_hash"
|
8
8
|
gemspec.authors = ["rogerdpack"]
|
9
|
-
gemspec.
|
9
|
+
gemspec.add_dependency('sane')
|
10
10
|
end
|
11
11
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.1
|
data/ext/benchmark.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require './google_hash'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
for name in [GoogleHashSparse, GoogleHashDense, Hash, GoogleHash] do
|
5
|
+
subject = name.new
|
6
|
+
puts name, Benchmark.realtime { 500000.times {|n| subject[n] = 4}}.to_s + " (populate)"
|
7
|
+
puts Benchmark.realtime { subject.each{|k, v| }}.to_s + " (each)", ''
|
8
|
+
|
9
|
+
end
|
data/ext/extconf.rb
CHANGED
@@ -1,15 +1,33 @@
|
|
1
1
|
require 'mkmf'
|
2
|
+
require 'erb'
|
2
3
|
require 'rubygems'
|
3
4
|
require 'sane'
|
4
5
|
|
5
6
|
# build google's lib locally...
|
7
|
+
|
6
8
|
dir = Dir.pwd
|
7
9
|
Dir.chdir 'sparsehash-1.5.2' do
|
8
10
|
dir = dir + '/local_installed'
|
9
11
|
command = "sh configure --prefix=#{dir} && make && make install"
|
10
12
|
puts command
|
11
|
-
|
13
|
+
# only if necessary
|
14
|
+
system command unless File.directory?(dir)
|
12
15
|
end
|
13
16
|
|
14
17
|
$CFLAGS += " -I./local_installed/include "
|
18
|
+
|
19
|
+
if RUBY_VERSION < '1.9'
|
20
|
+
# appears to link using gcc on 1.8 [mingw at least]
|
21
|
+
$LDFLAGS += " -lstdc++ "
|
22
|
+
end
|
23
|
+
|
24
|
+
# create our files...
|
25
|
+
# currently we're int only...hmm...
|
26
|
+
# ltodo 64 bit compat...
|
27
|
+
|
28
|
+
for type, setup_code in {'sparse' => nil, 'dense' => 'set_empty_key(1<<31);' } do
|
29
|
+
template = ERB.new(File.read('template/go.cpp'))
|
30
|
+
File.write(type.to_s + '.cpp', template.result(binding))
|
31
|
+
end
|
32
|
+
|
15
33
|
create_makefile('google_hash')
|
data/ext/go.bat
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby extconf.rb && make clean && make && ruby benchmark.rb
|
data/ext/main.cpp
ADDED
data/ext/template/go.cpp
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
#include <iostream>
|
2
|
+
#include <google/<%= type %>_hash_map>
|
3
|
+
#include <ruby.h>
|
4
|
+
|
5
|
+
using google::<%= type %>_hash_map; // namespace where class lives by default
|
6
|
+
using std::cout;
|
7
|
+
using std::endl;
|
8
|
+
<% if !OS.windows? %>
|
9
|
+
#include <ext/hash_set>
|
10
|
+
<% end %>
|
11
|
+
using __gnu_cxx::hash; // or __gnu_cxx::hash, or maybe tr1::hash, depending on your OS
|
12
|
+
extern "C" {
|
13
|
+
|
14
|
+
struct eqstr
|
15
|
+
{
|
16
|
+
bool operator()(const char* s1, const char* s2) const
|
17
|
+
{
|
18
|
+
return (s1 == s2) || (s1 && s2 && strcmp(s1, s2) == 0);
|
19
|
+
}
|
20
|
+
};
|
21
|
+
|
22
|
+
|
23
|
+
struct eqint
|
24
|
+
{
|
25
|
+
inline bool operator()(int s1, int s2) const
|
26
|
+
{
|
27
|
+
return s1 == s2;
|
28
|
+
}
|
29
|
+
};
|
30
|
+
|
31
|
+
typedef struct {
|
32
|
+
<%= type %>_hash_map<int, VALUE> *hash_map;
|
33
|
+
} RCallback;
|
34
|
+
|
35
|
+
static VALUE rb_cGoogleHash<%= type %>;
|
36
|
+
|
37
|
+
|
38
|
+
static void mark_hash_map_values(RCallback *incoming) {
|
39
|
+
for(<%= type %>_hash_map<int, VALUE>::iterator it = incoming->hash_map->begin(); it != incoming->hash_map->end(); ++it) {
|
40
|
+
rb_gc_mark(it->second);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
static void free_hash_callback(RCallback* cb) {
|
45
|
+
// delete cb->hash_map;
|
46
|
+
}
|
47
|
+
|
48
|
+
static VALUE callback_alloc _((VALUE)); // what does this line do?
|
49
|
+
|
50
|
+
static VALUE
|
51
|
+
callback_alloc( VALUE klass )
|
52
|
+
{
|
53
|
+
VALUE cb;
|
54
|
+
RCallback* cbs;
|
55
|
+
cb = Data_Make_Struct(klass, RCallback, mark_hash_map_values, free_hash_callback, cbs);
|
56
|
+
cbs->hash_map = new <%= type %>_hash_map<int, VALUE>();
|
57
|
+
<% if setup_code %>
|
58
|
+
cbs->hash_map-><%= setup_code %>;
|
59
|
+
<% end %>
|
60
|
+
return cb;
|
61
|
+
}
|
62
|
+
|
63
|
+
#define GetCallbackStruct(obj) (Check_Type(obj, T_DATA), (RCallback*)DATA_PTR(obj))
|
64
|
+
|
65
|
+
static VALUE
|
66
|
+
rb_mri_hash_new(VALUE freshly_created) {
|
67
|
+
|
68
|
+
// we don't actually have anything special to do here...
|
69
|
+
return freshly_created;
|
70
|
+
}
|
71
|
+
|
72
|
+
|
73
|
+
static VALUE rb_ghash_set(VALUE cb, VALUE set_this, VALUE to_this) {
|
74
|
+
if(!(TYPE(set_this) == T_FIXNUM)) {
|
75
|
+
rb_raise(rb_eTypeError, "not valid value");
|
76
|
+
}
|
77
|
+
RCallback* cbs = GetCallbackStruct(cb);
|
78
|
+
(*cbs->hash_map)[FIX2INT(set_this)] = to_this;
|
79
|
+
return to_this; // ltodo test that it returns value...
|
80
|
+
}
|
81
|
+
|
82
|
+
static VALUE rb_ghash_get(VALUE cb, VALUE get_this) {
|
83
|
+
if(!(TYPE(get_this) == T_FIXNUM)) {
|
84
|
+
rb_raise(rb_eTypeError, "not valid value");
|
85
|
+
}
|
86
|
+
RCallback* cbs = GetCallbackStruct(cb);
|
87
|
+
VALUE out = (*cbs->hash_map)[FIX2INT(get_this)];
|
88
|
+
// todo if out == 0 return Qnil
|
89
|
+
return out;
|
90
|
+
}
|
91
|
+
|
92
|
+
static VALUE rb_ghash_each(VALUE cb) {
|
93
|
+
RCallback* incoming = GetCallbackStruct(cb);
|
94
|
+
// TODO assert block given
|
95
|
+
for(<%= type %>_hash_map<int, VALUE>::iterator it = incoming->hash_map->begin(); it != incoming->hash_map->end(); ++it) {
|
96
|
+
rb_yield_values(2, INT2FIX(it->first), it->second);
|
97
|
+
}
|
98
|
+
return cb;
|
99
|
+
|
100
|
+
}
|
101
|
+
|
102
|
+
void init_<%= type %>() {
|
103
|
+
rb_cGoogleHash<%= type %> = rb_define_class("GoogleHash<%= type.capitalize %>", rb_cObject);
|
104
|
+
|
105
|
+
rb_define_alloc_func(rb_cGoogleHash<%= type %>, callback_alloc); // I guess it calls this for us, pre initialize...
|
106
|
+
|
107
|
+
rb_define_method(rb_cGoogleHash<%= type %>, "initialize", RUBY_METHOD_FUNC(rb_mri_hash_new), 0);
|
108
|
+
rb_define_method(rb_cGoogleHash<%= type %>, "[]=", RUBY_METHOD_FUNC(rb_ghash_set), 2);
|
109
|
+
rb_define_method(rb_cGoogleHash<%= type %>, "[]", RUBY_METHOD_FUNC(rb_ghash_get), 1);
|
110
|
+
rb_define_method(rb_cGoogleHash<%= type %>, "each", RUBY_METHOD_FUNC(rb_ghash_each), 0);
|
111
|
+
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
data/results.txt
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
1.9 mingw:
|
2
|
+
|
3
|
+
GoogleHashSparse
|
4
|
+
0.53125 (populate)
|
5
|
+
0.078125 (each)
|
6
|
+
|
7
|
+
GoogleHashDense
|
8
|
+
0.1875 (populate)
|
9
|
+
0.078125 (each)
|
10
|
+
|
11
|
+
Hash
|
12
|
+
0.359375 (populate)
|
13
|
+
1.1875 (each)
|
14
|
+
|
15
|
+
|
16
|
+
ruby 1.8.6 mingw:
|
17
|
+
|
18
|
+
GoogleHashSparse
|
19
|
+
0.625 (populate)
|
20
|
+
0.546875(each)
|
21
|
+
|
22
|
+
GoogleHashDense
|
23
|
+
0.234375(populate)
|
24
|
+
0.421875(each)
|
25
|
+
|
26
|
+
Hash
|
27
|
+
0.5 (populate)
|
28
|
+
0.53125 (each)
|
29
|
+
|
30
|
+
|
31
|
+
1.9.2 linux:
|
32
|
+
|
33
|
+
GoogleHashSparse
|
34
|
+
0.3342118263244629 (populate)
|
35
|
+
0.05078697204589844 (each)
|
36
|
+
|
37
|
+
GoogleHashDense
|
38
|
+
0.14588713645935059 (populate)
|
39
|
+
0.056185007095336914 (each)
|
40
|
+
|
41
|
+
Hash
|
42
|
+
0.34199094772338867 (populate)
|
43
|
+
0.8924679756164551 (each)
|
44
|
+
|
45
|
+
1.8.6 linux:
|
46
|
+
|
47
|
+
GoogleHashSparse
|
48
|
+
0.305501222610474 (populate)
|
49
|
+
0.78859806060791 (each)
|
50
|
+
|
51
|
+
GoogleHashDense
|
52
|
+
0.161197900772095 (populate)
|
53
|
+
0.810173988342285 (each)
|
54
|
+
|
55
|
+
Hash
|
56
|
+
0.269010782241821 (populate)
|
57
|
+
1.00644612312317 (each)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: google_hash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- rogerdpack
|
@@ -9,12 +9,12 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-12-15 00:00:00
|
12
|
+
date: 2009-12-15 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: sane
|
17
|
-
type: :
|
17
|
+
type: :runtime
|
18
18
|
version_requirement:
|
19
19
|
version_requirements: !ruby/object:Gem::Requirement
|
20
20
|
requirements:
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
|
-
description:
|
25
|
+
description: Ruby wrappers to the google hash library
|
26
26
|
email: rogerdpack@gmail.com
|
27
27
|
executables: []
|
28
28
|
|
@@ -34,8 +34,10 @@ files:
|
|
34
34
|
- README
|
35
35
|
- Rakefile
|
36
36
|
- VERSION
|
37
|
+
- ext/benchmark.rb
|
37
38
|
- ext/extconf.rb
|
38
|
-
- ext/go.
|
39
|
+
- ext/go.bat
|
40
|
+
- ext/main.cpp
|
39
41
|
- ext/sparsehash-1.5.2/AUTHORS
|
40
42
|
- ext/sparsehash-1.5.2/COPYING
|
41
43
|
- ext/sparsehash-1.5.2/ChangeLog
|
@@ -113,7 +115,8 @@ files:
|
|
113
115
|
- ext/sparsehash-1.5.2/vsprojects/sparsetable_unittest/sparsetable_unittest.vcproj
|
114
116
|
- ext/sparsehash-1.5.2/vsprojects/time_hash_map/time_hash_map.vcproj
|
115
117
|
- ext/sparsehash-1.5.2/vsprojects/type_traits_unittest/type_traits_unittest.vcproj
|
116
|
-
- ext/
|
118
|
+
- ext/template/go.cpp
|
119
|
+
- results.txt
|
117
120
|
- test/spec.go
|
118
121
|
has_rdoc: true
|
119
122
|
homepage: http://github.com/rdp/ruby_google_hash
|
data/ext/go.cpp
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
#include <iostream>
|
2
|
-
#include <google/sparse_hash_map>
|
3
|
-
#include <ruby.h>
|
4
|
-
|
5
|
-
using google::sparse_hash_map; // namespace where class lives by default
|
6
|
-
using std::cout;
|
7
|
-
using std::endl;
|
8
|
-
using __gnu_cxx::hash; // or __gnu_cxx::hash, or maybe tr1::hash, depending on your OS
|
9
|
-
extern "C" {
|
10
|
-
|
11
|
-
struct eqstr
|
12
|
-
{
|
13
|
-
bool operator()(const char* s1, const char* s2) const
|
14
|
-
{
|
15
|
-
return (s1 == s2) || (s1 && s2 && strcmp(s1, s2) == 0);
|
16
|
-
}
|
17
|
-
};
|
18
|
-
|
19
|
-
|
20
|
-
struct eqint
|
21
|
-
{
|
22
|
-
inline bool operator()(int s1, int s2) const
|
23
|
-
{
|
24
|
-
return s1 == s2;
|
25
|
-
}
|
26
|
-
};
|
27
|
-
|
28
|
-
typedef struct {
|
29
|
-
sparse_hash_map<int, VALUE> *hash_map;
|
30
|
-
} RCallback;
|
31
|
-
|
32
|
-
static VALUE rb_cGoogleHashSmall;
|
33
|
-
|
34
|
-
|
35
|
-
static void mark_hash_map_values(RCallback incoming) {} // TODO, etc.
|
36
|
-
|
37
|
-
static VALUE callback_alloc _((VALUE)); // what does this line do?
|
38
|
-
|
39
|
-
static VALUE
|
40
|
-
callback_alloc( VALUE klass )
|
41
|
-
{
|
42
|
-
VALUE cb;
|
43
|
-
RCallback* cbs;
|
44
|
-
cb = Data_Make_Struct(klass, RCallback, /*mark_mri_callback*/ 0, 0 /*free_mri_callback*/, cbs);
|
45
|
-
cbs->hash_map = new sparse_hash_map<int, VALUE>();
|
46
|
-
sparse_hash_map<int, int> a;
|
47
|
-
a[35] = 47;
|
48
|
-
sparse_hash_map<int, int> *a2 = new sparse_hash_map<int, int>;
|
49
|
-
(*a2)[35] = 37;
|
50
|
-
(*cbs->hash_map)[33] = 35;
|
51
|
-
return cb;
|
52
|
-
}
|
53
|
-
|
54
|
-
#define GetCallbackStruct(obj) (Check_Type(obj, T_DATA), (RCallback*)DATA_PTR(obj))
|
55
|
-
|
56
|
-
static VALUE
|
57
|
-
rb_mri_hash_new(VALUE freshly_created) {
|
58
|
-
|
59
|
-
// we don't actually have anything special to do here...
|
60
|
-
return freshly_created;
|
61
|
-
}
|
62
|
-
|
63
|
-
int main()
|
64
|
-
{
|
65
|
-
sparse_hash_map<const char*, int, hash<const char*>, eqstr> months;
|
66
|
-
|
67
|
-
months["april"] = 30;
|
68
|
-
|
69
|
-
cout << "april -> " << months["april"] << endl;
|
70
|
-
cout << "iterating";
|
71
|
-
for(sparse_hash_map<const char*, int, hash<const char*>, eqstr>::iterator it = months.begin(); it != months.end(); ++it) {
|
72
|
-
cout << it->first;
|
73
|
-
}
|
74
|
-
|
75
|
-
}
|
76
|
-
static VALUE rb_ghash_set(VALUE cb, VALUE set_this, VALUE to_this) {
|
77
|
-
if(!(TYPE(set_this) == T_FIXNUM)) {
|
78
|
-
rb_raise(rb_eTypeError, "not valid value");
|
79
|
-
}
|
80
|
-
RCallback* cbs = GetCallbackStruct(cb);
|
81
|
-
(*cbs->hash_map)[FIX2INT(set_this)] = to_this;
|
82
|
-
return to_this; // ltodo test that it returns value...
|
83
|
-
}
|
84
|
-
|
85
|
-
static VALUE rb_ghash_get(VALUE cb, VALUE get_this) {
|
86
|
-
if(!(TYPE(get_this) == T_FIXNUM)) {
|
87
|
-
rb_raise(rb_eTypeError, "not valid value");
|
88
|
-
}
|
89
|
-
RCallback* cbs = GetCallbackStruct(cb);
|
90
|
-
VALUE out = (*cbs->hash_map)[FIX2INT(get_this)];
|
91
|
-
// todo if out == 0 return Qnil
|
92
|
-
return out;
|
93
|
-
}
|
94
|
-
|
95
|
-
void Init_google_hash() {
|
96
|
-
rb_cGoogleHashSmall = rb_define_class("GoogleHashSmall", rb_cObject);
|
97
|
-
|
98
|
-
rb_define_alloc_func(rb_cGoogleHashSmall, callback_alloc); // I guess it calls this for us, pre initialize...
|
99
|
-
|
100
|
-
rb_define_method(rb_cGoogleHashSmall, "initialize", RUBY_METHOD_FUNC(rb_mri_hash_new), 0);
|
101
|
-
rb_define_method(rb_cGoogleHashSmall, "[]=", RUBY_METHOD_FUNC(rb_ghash_set), 2);
|
102
|
-
rb_define_method(rb_cGoogleHashSmall, "[]", RUBY_METHOD_FUNC(rb_ghash_get), 1);
|
103
|
-
|
104
|
-
|
105
|
-
main();
|
106
|
-
|
107
|
-
}
|
108
|
-
}
|
109
|
-
|
data/ext/test.rb
DELETED