rb_lovely 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6257def0a1d18050a37cfe61c6b6a07ebcc557b4
4
+ data.tar.gz: 8500185c4d547bf45bd83ba3ecdc48dddae95ebb
5
+ SHA512:
6
+ metadata.gz: 8618d167887a777da7b37f2389555678528f3b5b919b44a39dec8686b0aa66805b3e9885c92f3f7cd3af075252125fd6f620d7777d3a4dae73ebf11d9ab5384e
7
+ data.tar.gz: 411c88e8103e448542c8d39c8d5dbbcd9c5753529b21d2d021321bf4e8724da60276e9a9c53fa8b0be219285800d0455c111035b33960794fbe7d159083837a4
@@ -0,0 +1,22 @@
1
+ #ifndef RB_LOVELY_SETS_SET_HPP
2
+ #define RB_LOVELY_SETS_SET_HPP
3
+
4
+ #include "ruby_util.hpp"
5
+
6
+ namespace rb_lovely {
7
+
8
+ template <class T>
9
+ VALUE containerLength(VALUE self) {
10
+ T* set = rubyCast<T>(self);
11
+ return INT2NUM(set->size());
12
+ }
13
+
14
+ template <class T>
15
+ static void initSet(VALUE rbSet) {
16
+ rb_define_method(rbSet, "length", RUBY_METHOD_FUNC(containerLength<T>), 0);
17
+ }
18
+
19
+ auto toS = [](VALUE val) { return RSTRING_PTR(rb_funcall(val, to_sSym, 0)); };
20
+
21
+ }
22
+ #endif
@@ -0,0 +1,7 @@
1
+ require 'mkmf'
2
+ $CPPFLAGS += ' -std=c++0x'
3
+ with_cflags('-x c++') do
4
+ # needed for SortedHash, optional
5
+ have_header('boost/multi_index_container.hpp')
6
+ end
7
+ create_makefile('rb_lovely')
@@ -0,0 +1,34 @@
1
+ #include "ruby_util.hpp"
2
+
3
+ namespace rb_lovely {
4
+ // extern stuff from ruby_util
5
+ VALUE rbMod;
6
+ VALUE cmpMethSym;
7
+ VALUE equalitySym;
8
+ VALUE to_sSym;
9
+ VALUE hashSym;
10
+ }
11
+
12
+ extern "C" {
13
+ using namespace rb_lovely;
14
+
15
+ extern void Init_rb_lovely_sorted_set();
16
+ #ifdef HAVE_BOOST_MULTI_INDEX_CONTAINER_HPP
17
+ extern void Init_rb_lovely_hybrid_set();
18
+ #endif
19
+
20
+ void Init_rb_lovely() {
21
+ ruby_init();
22
+ ruby_init_loadpath();
23
+
24
+ initRubyUtil();
25
+
26
+ Init_rb_lovely_sorted_set();
27
+ #ifdef HAVE_BOOST_MULTI_INDEX_CONTAINER_HPP
28
+ Init_rb_lovely_hybrid_set();
29
+ #endif
30
+
31
+ // i saw this somewhere... but it dumps core... so um...
32
+ // ruby_finalize();
33
+ }
34
+ }
@@ -0,0 +1,39 @@
1
+ #ifndef RB_LOVELY_SETS_UTIL_HPP
2
+ #define RB_LOVELY_SETS_UTIL_HPP
3
+ #include "ruby.h"
4
+
5
+ namespace rb_lovely {
6
+
7
+ extern VALUE rbMod;
8
+ extern VALUE cmpMethSym;
9
+ extern VALUE equalitySym;
10
+ extern VALUE to_sSym;
11
+ extern VALUE hashSym;
12
+
13
+ template <class T>
14
+ void rubyDelete(T *obj) {
15
+ delete obj;
16
+ }
17
+
18
+ template <class T>
19
+ T *rubyCast(VALUE rbObj) {
20
+ T *obj;
21
+ Data_Get_Struct(rbObj, T, obj);
22
+ return obj;
23
+ }
24
+
25
+ template <class T>
26
+ VALUE rubyAlloc(VALUE klass) {
27
+ return Data_Wrap_Struct(klass, 0, rubyDelete<T>, new T);
28
+ }
29
+
30
+ static void initRubyUtil() {
31
+ rbMod = rb_define_module("RbLovely");
32
+ cmpMethSym = rb_intern("<=>");
33
+ equalitySym = rb_intern("==");
34
+ to_sSym = rb_intern("to_s");
35
+ hashSym = rb_intern("hash");
36
+ }
37
+
38
+ }
39
+ #endif
@@ -0,0 +1,212 @@
1
+ #ifdef HAVE_BOOST_MULTI_INDEX_CONTAINER_HPP
2
+ #include "container.hpp"
3
+
4
+ #include "ruby_util.hpp"
5
+
6
+ #include <boost/multi_index_container.hpp>
7
+ #include <boost/multi_index/hashed_index.hpp>
8
+ #include <boost/multi_index/ordered_index.hpp>
9
+ #include <boost/multi_index/member.hpp>
10
+
11
+ namespace rb_lovely { namespace hybrid {
12
+
13
+ struct member {
14
+ bool operator<(member const& rhs) const {
15
+ auto cmpVal = rb_funcall(val, cmpMethSym, 1, rhs.val);
16
+ return NUM2INT(cmpVal) < 0;
17
+ }
18
+
19
+ bool operator==(member const& rhs) const {
20
+ auto equalityVal = rb_funcall(key, equalitySym, 1, rhs.key);
21
+ return RTEST(equalityVal);
22
+ }
23
+
24
+ // also cache as two element array?
25
+ member(VALUE _key, VALUE _val) : key(_key), val(_val) {}
26
+
27
+ VALUE key;
28
+ VALUE val;
29
+ };
30
+
31
+ std::size_t hash_value(member const& member) {
32
+ // TODO: something better?
33
+ return reinterpret_cast<std::size_t>(&member);
34
+ // return NUM2INT(rb_funcall(member.val, hashSym, 0));
35
+ }
36
+
37
+ namespace mi = boost::multi_index;
38
+
39
+ typedef boost::multi_index_container<
40
+ member,
41
+ mi::indexed_by<
42
+ mi::hashed_unique< mi::member<member, VALUE, &member::key> >,
43
+ mi::ordered_non_unique< mi::identity<member> >
44
+ >
45
+ > Hash;
46
+
47
+ VALUE hashInitialize(int argc, VALUE *argv, VALUE self) {
48
+ if (argc == 1) {
49
+ auto array = rb_check_array_type(argv[0]);
50
+ if (array == Qnil) {
51
+ rb_raise(rb_eArgError, "Expected array");
52
+ }
53
+ else {
54
+ auto len = RARRAY_LEN(array);
55
+ if (len % 2 != 0) {
56
+ rb_raise(rb_eArgError, "Expected even number of parameters");
57
+ }
58
+ else {
59
+ Hash* hash = rubyCast<Hash>(self);
60
+ for (auto i = 0; i < len; i += 2) {
61
+ hash->insert(member(rb_ary_entry(array, i), rb_ary_entry(array, i + 1)));
62
+ }
63
+ }
64
+ }
65
+ }
66
+ return self;
67
+ }
68
+
69
+ VALUE hashUpdate(VALUE self, VALUE key, VALUE val) {
70
+ Hash* hash = rubyCast<Hash>(self);
71
+ // TODO: overwrite value
72
+ auto it = hash->find(key);
73
+ if (it != hash->end())
74
+ hash->replace(it, member(key, val));
75
+ else
76
+ hash->insert(member(key, val));
77
+ return self;
78
+ }
79
+
80
+ VALUE hashGet(VALUE self, VALUE key) {
81
+ Hash* hash = rubyCast<Hash>(self);
82
+ auto it = hash->find(key);
83
+ if (it == hash->end()) {
84
+ return Qnil;
85
+ }
86
+ else {
87
+ return it->val;
88
+ }
89
+ }
90
+
91
+ VALUE hashEach(VALUE self) {
92
+ if (! rb_block_given_p()) {
93
+ // TODO: return Enumerator
94
+ rb_raise(rb_eArgError, "Expected block");
95
+ }
96
+ else {
97
+ Hash* hash = rubyCast<Hash>(self);
98
+ for (auto const& member : hash->get<1>()) {
99
+ rb_yield_values(2, member.key, member.val);
100
+ }
101
+ }
102
+
103
+ return Qnil;
104
+ }
105
+
106
+ VALUE hashToString(VALUE self) {
107
+ std::stringstream str;
108
+ str << "RbLovely::SortedHash {";
109
+ Hash* hash = rubyCast<Hash>(self);
110
+ if (! hash->empty()) {
111
+ auto& idx = hash->get<1>();
112
+ auto it = idx.begin();
113
+ str << ' ' << toS(it->key) << " => " << toS(it->val);
114
+ for (++it; it != idx.end(); ++it) {
115
+ str << ", " << toS(it->key) << " => " << toS(it->val);
116
+ }
117
+ }
118
+ str << " }";
119
+
120
+ auto stlString = str.str();
121
+ return rb_str_new(stlString.data(), stlString.size());
122
+ }
123
+
124
+ VALUE hashFirst(VALUE self) {
125
+ Hash* hash = rubyCast<Hash>(self);
126
+ return hash->empty() ? Qnil : hash->get<1>().begin()->val;
127
+ }
128
+
129
+ VALUE hashLast(VALUE self) {
130
+ Hash* hash = rubyCast<Hash>(self);
131
+ if (hash->empty())
132
+ return Qnil;
133
+
134
+ auto last = hash->get<1>().end();
135
+ --last;
136
+ return last->val;
137
+ }
138
+
139
+ VALUE hashMutatingDelete(VALUE self, VALUE toDelete) {
140
+ Hash* hash = rubyCast<Hash>(self);
141
+ auto it = hash->find(toDelete);
142
+ if (it == hash->end()) {
143
+ return Qnil;
144
+ }
145
+ else {
146
+ auto valBackup = it->val;
147
+ hash->erase(it);
148
+ return valBackup;
149
+ }
150
+ }
151
+
152
+ VALUE hashShift(VALUE self) {
153
+ Hash* hash = rubyCast<Hash>(self);
154
+ if (hash->empty())
155
+ return Qnil;
156
+
157
+ auto& idx = hash->get<1>();
158
+ auto bak = idx.begin()->val;
159
+ idx.erase(idx.begin());
160
+ return bak;
161
+ }
162
+
163
+ VALUE hashPop(VALUE self) {
164
+ Hash* hash = rubyCast<Hash>(self);
165
+ if (hash->empty())
166
+ return Qnil;
167
+
168
+ auto& idx = hash->get<1>();
169
+ auto last = idx.end();
170
+ --last;
171
+ auto bak = last->val;
172
+ idx.erase(last);
173
+ return bak;
174
+ }
175
+
176
+ VALUE hashHas(VALUE self, VALUE key) {
177
+ Hash* hash = rubyCast<Hash>(self);
178
+ auto it = hash->find(key);
179
+ return it == hash->end() ? Qfalse : Qtrue;
180
+ }
181
+
182
+ } }
183
+
184
+ extern "C" {
185
+ using namespace rb_lovely;
186
+ using namespace rb_lovely::hybrid;
187
+
188
+ void Init_rb_lovely_hybrid_set() {
189
+ auto rbHash = rb_define_class_under(rbMod, "SortedHash", rb_cObject);
190
+ rb_define_alloc_func(rbHash, rubyAlloc<Hash>);
191
+ rb_include_module(rbHash, rb_const_get(rb_cObject, rb_intern("Enumerable")));
192
+
193
+ rb_define_method(rbHash, "initialize", RUBY_METHOD_FUNC(hashInitialize), -1);
194
+ initSet<Hash>(rbHash);
195
+ rb_define_method(rbHash, "[]=", RUBY_METHOD_FUNC(hashUpdate), 2);
196
+ rb_define_method(rbHash, "[]", RUBY_METHOD_FUNC(hashGet), 1);
197
+ rb_define_method(rbHash, "each", RUBY_METHOD_FUNC(hashEach), 0);
198
+ rb_define_method(rbHash, "to_s", RUBY_METHOD_FUNC(hashToString), 0);
199
+ rb_define_method(rbHash, "first", RUBY_METHOD_FUNC(hashFirst), 0);
200
+ rb_define_method(rbHash, "last", RUBY_METHOD_FUNC(hashLast), 0);
201
+ rb_define_method(rbHash, "delete", RUBY_METHOD_FUNC(hashMutatingDelete), 1);
202
+ // rb_define_method(rbHash, "reject!", RUBY_METHOD_FUNC(hashMutatingReject), 0);
203
+ // rb_define_method(rbHash, "reject_first!", RUBY_METHOD_FUNC(hashMutatingRejectFirst), 0);
204
+ // rb_define_method(rbHash, "select!", RUBY_METHOD_FUNC(hashMutatingSelect), 0);
205
+ rb_define_method(rbHash, "shift", RUBY_METHOD_FUNC(hashShift), 0);
206
+ rb_define_method(rbHash, "pop", RUBY_METHOD_FUNC(hashPop), 0);
207
+ // Enumerable would test both key and value for include?
208
+ rb_define_method(rbHash, "include?", RUBY_METHOD_FUNC(hashHas), 1);
209
+ rb_define_method(rbHash, "has_key?", RUBY_METHOD_FUNC(hashHas), 1);
210
+ }
211
+ }
212
+ #endif
@@ -0,0 +1,214 @@
1
+ #include "container.hpp"
2
+
3
+ #include "ruby_util.hpp"
4
+
5
+ #include <set>
6
+ #include <sstream>
7
+
8
+ namespace rb_lovely { namespace ordered {
9
+
10
+ struct Compare {
11
+ bool operator()(VALUE const& lhs, VALUE const& rhs);
12
+ };
13
+
14
+ typedef std::set<VALUE, Compare> Set;
15
+
16
+ bool Compare::operator()(VALUE const& lhs, VALUE const& rhs) {
17
+ auto cmpVal = rb_funcall(lhs, cmpMethSym, 1, rhs);
18
+ return NUM2INT(cmpVal) < 0;
19
+ }
20
+
21
+ VALUE setInitialize(int argc, VALUE *argv, VALUE self) {
22
+ if (argc == 1) {
23
+ auto array = rb_check_array_type(argv[0]);
24
+ if (array == Qnil) {
25
+ rb_raise(rb_eArgError, "Expected array");
26
+ }
27
+ else {
28
+ Set* set = rubyCast<Set>(self);
29
+ auto len = RARRAY_LEN(array);
30
+ for (auto i = 0; i < len; ++i) {
31
+ set->insert(rb_ary_entry(array, i));
32
+ }
33
+ }
34
+ }
35
+ return self;
36
+ }
37
+
38
+ VALUE setAdd(VALUE self, VALUE val) {
39
+ Set* set = rubyCast<Set>(self);
40
+ set->insert(val);
41
+ return self;
42
+ }
43
+
44
+ VALUE setEach(VALUE self) {
45
+ if (! rb_block_given_p()) {
46
+ // TODO: return Enumerator
47
+ rb_raise(rb_eArgError, "Expected block");
48
+ }
49
+ else {
50
+ Set* set = rubyCast<Set>(self);
51
+ for (auto const& val : *set) {
52
+ rb_yield(val);
53
+ }
54
+ }
55
+
56
+ return Qnil;
57
+ }
58
+
59
+ VALUE setToString(VALUE self) {
60
+ std::stringstream str;
61
+ str << "RbLovely::SortedSet {";
62
+ Set* set = rubyCast<Set>(self);
63
+ if (! set->empty()) {
64
+ auto it = set->begin();
65
+ str << ' ' << toS(*it);
66
+ for (++it; it != set->end(); ++it) {
67
+ str << ", " << toS(*it);
68
+ }
69
+ }
70
+ str << " }";
71
+
72
+ auto stlString = str.str();
73
+ return rb_str_new(stlString.data(), stlString.size());
74
+ }
75
+
76
+ VALUE setFirst(VALUE self) {
77
+ Set* set = rubyCast<Set>(self);
78
+
79
+ return set->empty() ? Qnil : *set->begin();
80
+ }
81
+
82
+ VALUE setLast(VALUE self) {
83
+ Set* set = rubyCast<Set>(self);
84
+ if (set->empty())
85
+ return Qnil;
86
+
87
+ auto last = set->end();
88
+ --last;
89
+ return *last;
90
+ }
91
+
92
+ VALUE setMutatingDelete(VALUE self, VALUE toDelete) {
93
+ Set* set = rubyCast<Set>(self);
94
+ auto it = set->find(toDelete);
95
+ if (it == set->end()) {
96
+ return Qnil;
97
+ }
98
+ else {
99
+ auto valBackup = *it;
100
+ set->erase(it);
101
+ return valBackup;
102
+ }
103
+ }
104
+
105
+ VALUE setMutatingReject(VALUE self) {
106
+ if (! rb_block_given_p()) {
107
+ rb_raise(rb_eArgError, "Expected block");
108
+ }
109
+ else {
110
+ Set* set = rubyCast<Set>(self);
111
+ for (auto it = set->begin(); it != set->end();) {
112
+ auto predicateRetVal = rb_yield(*it);
113
+ if (RTEST(predicateRetVal))
114
+ it = set->erase(it);
115
+ else
116
+ ++it;
117
+ }
118
+ }
119
+ return self;
120
+ }
121
+
122
+ VALUE setMutatingRejectFirst(VALUE self) {
123
+ if (! rb_block_given_p()) {
124
+ rb_raise(rb_eArgError, "Expected block");
125
+ }
126
+ else {
127
+ Set* set = rubyCast<Set>(self);
128
+ for (auto it = set->begin(); it != set->end(); ++it) {
129
+ auto predicateRetVal = rb_yield(*it);
130
+ if (RTEST(predicateRetVal)) {
131
+ auto valBackup = *it;
132
+ set->erase(it);
133
+ return valBackup;
134
+ }
135
+ }
136
+ }
137
+ return Qnil;
138
+ }
139
+
140
+ VALUE setMutatingSelect(VALUE self) {
141
+ if (! rb_block_given_p()) {
142
+ rb_raise(rb_eArgError, "Expected block");
143
+ return self;
144
+ }
145
+ else {
146
+ Set* set = rubyCast<Set>(self);
147
+ for (auto it = set->begin(); it != set->end();) {
148
+ auto predicateRetVal = rb_yield(*it);
149
+ if (! RTEST(predicateRetVal))
150
+ it = set->erase(it);
151
+ else
152
+ ++it;
153
+ }
154
+ }
155
+ return self;
156
+ }
157
+
158
+ VALUE setShift(VALUE self) {
159
+ Set* set = rubyCast<Set>(self);
160
+ if (set->empty())
161
+ return Qnil;
162
+
163
+ auto bak = *set->begin();
164
+ set->erase(set->begin());
165
+ return bak;
166
+ }
167
+
168
+ VALUE setPop(VALUE self) {
169
+ Set* set = rubyCast<Set>(self);
170
+ if (set->empty())
171
+ return Qnil;
172
+
173
+ auto last = set->end();
174
+ --last;
175
+ auto bak = *last;
176
+ set->erase(last);
177
+ return bak;
178
+ }
179
+
180
+ VALUE setHas(VALUE self, VALUE val) {
181
+ Set* set = rubyCast<Set>(self);
182
+ auto it = set->find(val);
183
+ return it == set->end() ? Qfalse : Qtrue;
184
+ }
185
+
186
+ } } // end namespace
187
+
188
+ extern "C" {
189
+ using namespace rb_lovely;
190
+ using namespace rb_lovely::ordered;
191
+
192
+ void Init_rb_lovely_sorted_set() {
193
+ auto rbSet = rb_define_class_under(rbMod, "SortedSet", rb_cObject);
194
+ rb_define_alloc_func(rbSet, rubyAlloc<Set>);
195
+ rb_include_module(rbSet, rb_const_get(rb_cObject, rb_intern("Enumerable")));
196
+
197
+ rb_define_method(rbSet, "initialize", RUBY_METHOD_FUNC(setInitialize), -1);
198
+ initSet<Set>(rbSet);
199
+ rb_define_method(rbSet, "add", RUBY_METHOD_FUNC(setAdd), 1);
200
+ rb_define_method(rbSet, "<<", RUBY_METHOD_FUNC(setAdd), 1);
201
+ rb_define_method(rbSet, "each", RUBY_METHOD_FUNC(setEach), 0);
202
+ rb_define_method(rbSet, "to_s", RUBY_METHOD_FUNC(setToString), 0);
203
+ rb_define_method(rbSet, "first", RUBY_METHOD_FUNC(setFirst), 0);
204
+ rb_define_method(rbSet, "last", RUBY_METHOD_FUNC(setLast), 0);
205
+ rb_define_method(rbSet, "delete", RUBY_METHOD_FUNC(setMutatingDelete), 1);
206
+ rb_define_method(rbSet, "reject!", RUBY_METHOD_FUNC(setMutatingReject), 0);
207
+ rb_define_method(rbSet, "reject_first!", RUBY_METHOD_FUNC(setMutatingRejectFirst), 0);
208
+ rb_define_method(rbSet, "select!", RUBY_METHOD_FUNC(setMutatingSelect), 0);
209
+ rb_define_method(rbSet, "shift", RUBY_METHOD_FUNC(setShift), 0);
210
+ rb_define_method(rbSet, "pop", RUBY_METHOD_FUNC(setPop), 0);
211
+ // Enumerable provides a slower version of this
212
+ rb_define_method(rbSet, "include?", RUBY_METHOD_FUNC(setHas), 1);
213
+ }
214
+ }
metadata ADDED
@@ -0,0 +1,52 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rb_lovely
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.3
5
+ platform: ruby
6
+ authors:
7
+ - James Pike
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A fast sorted set built using std::set and a fast sorted hash built using
14
+ boost::multi_index_container.
15
+ email:
16
+ - gems@chilon.net
17
+ executables: []
18
+ extensions:
19
+ - ext/rb_lovely/extconf.rb
20
+ extra_rdoc_files: []
21
+ files:
22
+ - ext/rb_lovely/container.hpp
23
+ - ext/rb_lovely/extconf.rb
24
+ - ext/rb_lovely/package.cpp
25
+ - ext/rb_lovely/ruby_util.hpp
26
+ - ext/rb_lovely/sorted_hash.cpp
27
+ - ext/rb_lovely/sorted_set.cpp
28
+ homepage: https://github.com/nuisanceofcats/rb_lovely
29
+ licenses:
30
+ - Expat
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubyforge_project:
48
+ rubygems_version: 2.2.2
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: Fast sorted sets and hashes.
52
+ test_files: []