google_hash 0.0.0 → 0.1.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/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