rmtools 2.3.6 → 2.4.0
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.
- checksums.yaml +4 -4
- data/README.md +11 -1
- data/ext/rmtools.cpp +560 -560
- data/ext/rmtools.h +161 -161
- data/lib/rmtools/console/coloring.rb +1 -1
- data/lib/rmtools/conversions/enum.rb +1 -1
- data/lib/rmtools/conversions/json.rb +3 -3
- data/lib/rmtools/core/arguments.rb +0 -1
- data/lib/rmtools/core/b.rb +4 -2
- data/lib/rmtools/core/js.rb +5 -2
- data/lib/rmtools/core/numeric.rb +15 -7
- data/lib/rmtools/core/proc.rb +2 -2
- data/lib/rmtools/core/symbol.rb +1 -6
- data/lib/rmtools/dev/binding.rb +1 -1
- data/lib/rmtools/dev/highlight.rb +14 -0
- data/lib/rmtools/dev/trace_format.rb +18 -13
- data/lib/rmtools/enumerable/array.rb +2 -1
- data/lib/rmtools/enumerable/array_iterators.rb +13 -2
- data/lib/rmtools/enumerable/object_space.rb +1 -0
- data/lib/rmtools/fs/tools.rb +1 -1
- data/lib/rmtools/lang/ansi.rb +4 -0
- data/lib/rmtools/text/string_simple.rb +4 -0
- data/lib/rmtools/text/string_split.rb +15 -11
- data/lib/rmtools/version.rb +1 -1
- data/rmtools.gemspec +2 -6
- metadata +6 -49
- data/lib/rmtools/conversions/numeric.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4af007b3b54a30faa10b74f7954970878d36ab73
|
4
|
+
data.tar.gz: 202e16f990d3115ef0d9a934b0fec88f52c85644
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c2869bcd4ca80a81bec45e10c23eb778bc48e03b89f9889d5efe901e09e28fb843204f9c293cb4b55032636175bf5fe8e9e8786632295c7c6e9c6a45fdd2c0c
|
7
|
+
data.tar.gz: bec7b536593e4c95fbb689e5a9eed3aaa6f211eef5a895d2f9a76e11db4aa9d71237a37eebb568ea1d2292f5aff602a77b7b4b9bf0571add58553519559fac5d
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
### RMTools
|
2
2
|
[github](https://github.com/tinbka/rmtools)
|
3
3
|
|
4
|
+
*This description is kinda fuzzy and outdated. More up-to-date statement of concept is in [version 3](https://github.com/tinbka/rmtools/tree/v3) readme. I'll try to release it at September.*
|
5
|
+
|
4
6
|
Collection of helpers for any need: strings, enumerables, modules... hundreds of bicycles and shortcuts you ever wanted to implement are here, optimized for performance.
|
5
7
|
Small dev library (constantly in progress): fast and smart logger, binding explorer, backtrace formatter, each is console-colored.
|
6
8
|
Started from basic classes, now it contains low-level helpers for ActiveRecord and makes LibXML more jqueryish.
|
@@ -27,7 +29,15 @@ It's still randomly documented since it's just my working tool.
|
|
27
29
|
|
28
30
|
### CHANGES
|
29
31
|
|
30
|
-
##### Version 2.
|
32
|
+
##### Version 2.4.0
|
33
|
+
|
34
|
+
* Ruby 2.1+ behaviour:
|
35
|
+
Since String#b in Ruby 2.1 is now an internal method incompatible with rmtools' String#b, our String#b will not be defined only if ruby version > 2.1.
|
36
|
+
Other methods have been refactored with this in an account.
|
37
|
+
* RMTools.format_trace
|
38
|
+
fixed double rendering within rails depths
|
39
|
+
|
40
|
+
##### Version 2.3.6
|
31
41
|
|
32
42
|
* Ruby 2+ behaviour:
|
33
43
|
* Disabled C-extension
|
data/ext/rmtools.cpp
CHANGED
@@ -1,560 +1,560 @@
|
|
1
|
-
#include "rmtools.h"
|
2
|
-
|
3
|
-
using namespace std;
|
4
|
-
|
5
|
-
/*
|
6
|
-
* Assign new value by variable or constant address. Can't process numeric, nil, false and true. Though, it can process containers with all of that shit.
|
7
|
-
* a = 'Object.new'
|
8
|
-
* => "Object.new"
|
9
|
-
* def inspire x
|
10
|
-
* x.define! eval x
|
11
|
-
* end
|
12
|
-
* => nil
|
13
|
-
* inspire a
|
14
|
-
* => #<Object:0xb790bed0>
|
15
|
-
* a
|
16
|
-
* => #<Object:0xb790bed0>
|
17
|
-
* It's quite buggy, you can get sudden segfault sometime after using method ^_^'\
|
18
|
-
* Maybe it could mark used objects for GC not to collect
|
19
|
-
*/
|
20
|
-
static VALUE object_define_new_value(VALUE self, VALUE new_obj)
|
21
|
-
{
|
22
|
-
if (FIXNUM_P(self) || self == Qnil || self == Qfalse || self == Qtrue || self == Qundef) {
|
23
|
-
VALUE tmp = rb_mod_name(rb_obj_class(self));
|
24
|
-
const char* msg = StringValuePtr(tmp);
|
25
|
-
rb_raise(rb_eTypeError, "can't redefine %s", msg);
|
26
|
-
}
|
27
|
-
if (FIXNUM_P(new_obj) || new_obj == Qnil || new_obj == Qfalse || new_obj == Qtrue || new_obj == Qundef) {
|
28
|
-
VALUE tmp = rb_mod_name(rb_obj_class(self));
|
29
|
-
const char* msg = StringValuePtr(tmp);
|
30
|
-
rb_raise(rb_eTypeError, "can't define object as %s", msg);
|
31
|
-
}
|
32
|
-
// Place the definition of the new object in the slot of self
|
33
|
-
memcpy(reinterpret_cast<void*>(self), reinterpret_cast<void*>(rb_funcall(new_obj, rb_intern("clone"), 0)), SLOT_SIZE);
|
34
|
-
return self;
|
35
|
-
}
|
36
|
-
|
37
|
-
|
38
|
-
/*
|
39
|
-
* puts ['123', '456', '789'].stranspose
|
40
|
-
* 147
|
41
|
-
* 258
|
42
|
-
* 369
|
43
|
-
*/
|
44
|
-
static VALUE rb_ary_string_transpose(VALUE ary)
|
45
|
-
{
|
46
|
-
long elen = -1, alen, i, j;
|
47
|
-
VALUE tmp, result = 0;
|
48
|
-
|
49
|
-
alen = RARRAY_LEN(ary);
|
50
|
-
if (alen == 0) return rb_ary_dup(ary);
|
51
|
-
for (i=0; i<alen; i++) {
|
52
|
-
tmp = RARRAY_PTR(ary)[i];
|
53
|
-
if (elen < 0) { /* first element */
|
54
|
-
elen = RSTRING_LEN(tmp);
|
55
|
-
result = rb_ary_new2(elen);
|
56
|
-
for (j=0; j<elen; j++) rb_ary_store(result, j, rb_str_new("", 0));
|
57
|
-
}
|
58
|
-
else if (elen != RSTRING_LEN(tmp))
|
59
|
-
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
60
|
-
RARRAY_LEN(tmp), elen);
|
61
|
-
for (j=0; j<elen; j++) rb_str_buf_cat(RARRAY_PTR(result)[j], &(RSTRING_PTR(tmp)[j]), 1);
|
62
|
-
}
|
63
|
-
return result;
|
64
|
-
}
|
65
|
-
|
66
|
-
/*
|
67
|
-
* puts ['123', '456', '789'].turn_ccw
|
68
|
-
* 369
|
69
|
-
* 258
|
70
|
-
* 147
|
71
|
-
*/
|
72
|
-
static VALUE rb_ary_turn_ccw(VALUE ary)
|
73
|
-
{
|
74
|
-
long elen, alen, i, j;
|
75
|
-
VALUE tmp, result = 0;
|
76
|
-
alen = RARRAY_LEN(ary);
|
77
|
-
if (alen == 0) return rb_ary_dup(ary);
|
78
|
-
|
79
|
-
tmp = RARRAY_PTR(ary)[0];
|
80
|
-
if (TYPE(tmp) == T_STRING) {
|
81
|
-
elen = RSTRING_LEN(tmp);
|
82
|
-
result = rb_ary_new2(elen);
|
83
|
-
for (j=0; j<elen; j++) rb_ary_store(result, j, rb_str_new("", 0));
|
84
|
-
for (i=0; i<alen; i++) {
|
85
|
-
if (i) tmp = RARRAY_PTR(ary)[i];
|
86
|
-
if (elen != RSTRING_LEN(tmp))
|
87
|
-
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
88
|
-
RARRAY_LEN(tmp), elen);
|
89
|
-
for (j=0; j<elen; j++) rb_str_buf_cat(RARRAY_PTR(result)[j], &(RSTRING_PTR(tmp)[elen-1-j]), 1);
|
90
|
-
}
|
91
|
-
}
|
92
|
-
else {
|
93
|
-
elen = RARRAY_LEN(tmp);
|
94
|
-
for (j=0; j<elen; j++) rb_ary_store(result, j, rb_ary_new2(alen));
|
95
|
-
for (i=0; i<alen; i++) {
|
96
|
-
if (i) tmp = RARRAY_PTR(ary)[i];
|
97
|
-
if (elen != RARRAY_LEN(tmp))
|
98
|
-
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
99
|
-
RARRAY_LEN(tmp), elen);
|
100
|
-
for (j=0; j<elen; j++) rb_ary_store(RARRAY_PTR(result)[j], i, RARRAY_PTR(tmp)[elen-1-j]);
|
101
|
-
}
|
102
|
-
}
|
103
|
-
|
104
|
-
return result;
|
105
|
-
}
|
106
|
-
|
107
|
-
/*
|
108
|
-
* puts ['123', '456', '789'].turn_cw
|
109
|
-
* 147
|
110
|
-
* 258
|
111
|
-
* 369
|
112
|
-
*/
|
113
|
-
static VALUE rb_ary_turn_cw(VALUE ary)
|
114
|
-
{
|
115
|
-
long elen, alen, i, j;
|
116
|
-
VALUE tmp, result = 0;
|
117
|
-
alen = RARRAY_LEN(ary);
|
118
|
-
if (alen == 0) return rb_ary_dup(ary);
|
119
|
-
|
120
|
-
tmp = RARRAY_PTR(ary)[0];
|
121
|
-
if (TYPE(tmp) == T_STRING) {
|
122
|
-
elen = RSTRING_LEN(tmp);
|
123
|
-
result = rb_ary_new2(elen);
|
124
|
-
for (j=0; j<elen; j++) rb_ary_store(result, j, rb_str_new("", 0));
|
125
|
-
for (i=alen-1; i>-1; i--) {
|
126
|
-
tmp = RARRAY_PTR(ary)[i];
|
127
|
-
if (elen != RSTRING_LEN(tmp))
|
128
|
-
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
129
|
-
RARRAY_LEN(tmp), elen);
|
130
|
-
for (j=0; j<elen; j++) rb_str_buf_cat(RARRAY_PTR(result)[j], &(RSTRING_PTR(tmp)[j]), 1);
|
131
|
-
}
|
132
|
-
}
|
133
|
-
else {
|
134
|
-
elen = RARRAY_LEN(tmp);
|
135
|
-
for (j=0; j<elen; j++) rb_ary_store(result, j, rb_ary_new2(alen));
|
136
|
-
for (i=0; i<alen; i++) {
|
137
|
-
if (i) tmp = RARRAY_PTR(ary)[i];
|
138
|
-
if (elen != RARRAY_LEN(tmp))
|
139
|
-
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
140
|
-
RARRAY_LEN(tmp), elen);
|
141
|
-
for (j=0; j<elen; j++) rb_ary_store(RARRAY_PTR(result)[j], elen-1-i, RARRAY_PTR(tmp)[j]);
|
142
|
-
}
|
143
|
-
}
|
144
|
-
|
145
|
-
return result;
|
146
|
-
}
|
147
|
-
|
148
|
-
/*
|
149
|
-
* " @@@@@@".conj " @@@ @@@"
|
150
|
-
* => " @@@"
|
151
|
-
*/
|
152
|
-
static VALUE rb_str_disjunction(VALUE self, VALUE str)
|
153
|
-
{
|
154
|
-
if (RSTRING_LEN(self) != RSTRING_LEN(str))
|
155
|
-
rb_raise(rb_eIndexError, "strings sizes differs (%ld and %ld)",
|
156
|
-
RSTRING_LEN(self), RSTRING_LEN(str));
|
157
|
-
VALUE new_str = rb_str_new("", 0);
|
158
|
-
int i;
|
159
|
-
const char *selfptr = RSTRING_PTR(self), *strptr = RSTRING_PTR(str);
|
160
|
-
for (i=0;i<RSTRING_LEN(str);i++) {
|
161
|
-
if (strptr[i] != ' ' || selfptr[i] != ' ')
|
162
|
-
rb_str_buf_cat(new_str, "@", 1);
|
163
|
-
else
|
164
|
-
rb_str_buf_cat(new_str, " ", 1);
|
165
|
-
}
|
166
|
-
return new_str;
|
167
|
-
}
|
168
|
-
|
169
|
-
/*
|
170
|
-
* " @@@@@@".disj " @@@ @@@"
|
171
|
-
* => " @@@@@@@@@"
|
172
|
-
*/
|
173
|
-
static VALUE rb_str_conjunction(VALUE self, VALUE str)
|
174
|
-
{
|
175
|
-
if (RSTRING_LEN(self) != RSTRING_LEN(str))
|
176
|
-
rb_raise(rb_eIndexError, "strings sizes differs (%ld and %ld)",
|
177
|
-
RSTRING_LEN(self), RSTRING_LEN(str));
|
178
|
-
VALUE new_str = rb_str_new("", 0);
|
179
|
-
int i;
|
180
|
-
const char *selfptr = RSTRING_PTR(self), *strptr = RSTRING_PTR(str);
|
181
|
-
for (i=0;i<RSTRING_LEN(str);i++) {
|
182
|
-
if (strptr[i] == '@' && selfptr[i] == '@')
|
183
|
-
rb_str_buf_cat(new_str, "@", 1);
|
184
|
-
else
|
185
|
-
rb_str_buf_cat(new_str, " ", 1);
|
186
|
-
}
|
187
|
-
return new_str;
|
188
|
-
}
|
189
|
-
|
190
|
-
/*
|
191
|
-
* Modifies array, throwing all elements not having unique block result
|
192
|
-
* a = randarr 10
|
193
|
-
* => [8, 2, 0, 5, 4, 1, 7, 3, 9, 6]
|
194
|
-
* a.uniq_by! {|e| e%2}
|
195
|
-
* => [8, 5]
|
196
|
-
* a
|
197
|
-
* => [8, 5]
|
198
|
-
* Here is implyied that callback block is +clean function+
|
199
|
-
*/
|
200
|
-
static VALUE rb_ary_uniq_by_bang(VALUE ary)
|
201
|
-
{
|
202
|
-
long len = RARRAY_LEN(ary);
|
203
|
-
if (len < 2)
|
204
|
-
return Qnil;
|
205
|
-
if (!rb_block_given_p())
|
206
|
-
return rb_ary_new4(RARRAY_LEN(ary), RARRAY_PTR(ary));
|
207
|
-
VALUE hash, res_hash, res, el;
|
208
|
-
long i, j;
|
209
|
-
|
210
|
-
hash = rb_hash_new();
|
211
|
-
res_hash = rb_hash_new();
|
212
|
-
for (i=j=0; i<len; i++) {
|
213
|
-
// We store an element itself and so we won't calculate function of it
|
214
|
-
// other time we'll find it in source. Ruby store function is very fast,
|
215
|
-
// so we can neglect its runtime even if source array is allready uniq
|
216
|
-
el = RARRAY_PTR(ary)[i];
|
217
|
-
if (st_lookup(RHASH_TBL(hash), el, 0)) continue;
|
218
|
-
res = rb_yield(el);
|
219
|
-
if (st_lookup(RHASH_TBL(res_hash), res, 0)) continue;
|
220
|
-
rb_hash_aset(hash, el, Qtrue);
|
221
|
-
rb_hash_aset(res_hash, res, Qtrue);
|
222
|
-
rb_ary_store(ary, j++, el);
|
223
|
-
}
|
224
|
-
ARY_SET_LEN(ary, j);
|
225
|
-
|
226
|
-
return j == len ? Qnil : ary;
|
227
|
-
}
|
228
|
-
|
229
|
-
/*
|
230
|
-
* Safe version of uniq_by!
|
231
|
-
*/
|
232
|
-
static VALUE rb_ary_uniq_by(VALUE ary)
|
233
|
-
{
|
234
|
-
VALUE ary_dup = rb_ary_dup(ary);
|
235
|
-
rb_ary_uniq_by_bang(ary_dup);
|
236
|
-
return ary_dup;
|
237
|
-
}
|
238
|
-
|
239
|
-
/*
|
240
|
-
* Make hash with unique items of +self+ or (when block given)
|
241
|
-
* unique results of items yield for keys and
|
242
|
-
* count of them in +self+,
|
243
|
-
* or (with option :fill) arrays of yield results,
|
244
|
-
* or (with option :indexes) arrays of indexes of them,
|
245
|
-
* or (with option :group) arrays of themselves for values
|
246
|
-
*
|
247
|
-
* [1, 2, 2, 2, 3, 3].arrange
|
248
|
-
* => {1=>1, 2=>3, 3=>2}
|
249
|
-
* [1, 2, 2, 2, 3, 3].arrange {|i| i%2}
|
250
|
-
* => {0=>3, 1=>3}
|
251
|
-
* [1, 2, 2, 2, 3, 3].arrange :fill
|
252
|
-
* => {1=>[1], 2=>[2, 2, 2], 3=>[3, 3]}
|
253
|
-
* [1, 2, 2, 2, 3, 3].arrange :indexes
|
254
|
-
* => {1=>[0], 2=>[1, 2, 3], 3=>[4, 5]}
|
255
|
-
* [1, 2, 2, 2, 3, 3].arrange(:indexes) {|i| i%2}
|
256
|
-
* => {0=>[1, 2, 3], 1=>[0, 4, 5]}
|
257
|
-
* :group is analogue to rails' group_by but twice faster
|
258
|
-
* [1, 2, 2, 2, 3, 3].arrange(:group) {|i| i%2}
|
259
|
-
* => {0=>[2, 2, 2], 1=>[1, 3, 3]}
|
260
|
-
*/
|
261
|
-
static VALUE rb_ary_count_items(int argc, VALUE *argv, VALUE ary)
|
262
|
-
{
|
263
|
-
long i, alen, block_given;
|
264
|
-
int fill, ind, group;
|
265
|
-
VALUE key, arg, storage;
|
266
|
-
VALUE hash = rb_hash_new();
|
267
|
-
VALUE val = Qnil;
|
268
|
-
|
269
|
-
block_given = rb_block_given_p();
|
270
|
-
rb_scan_args(argc, argv, "01", &arg);
|
271
|
-
ind = arg == ID2SYM(rb_intern("indexes"));
|
272
|
-
group = arg == ID2SYM(rb_intern("group"));
|
273
|
-
fill = ind || group || arg == ID2SYM(rb_intern("fill"));
|
274
|
-
|
275
|
-
alen = RARRAY_LEN(ary);
|
276
|
-
for (i=0; i<RARRAY_LEN(ary); i++) {
|
277
|
-
key = block_given ? rb_yield(RARRAY_PTR(ary)[i]) : RARRAY_PTR(ary)[i];
|
278
|
-
if (fill)
|
279
|
-
{
|
280
|
-
if (st_lookup(RHASH_TBL(hash), key, 0))
|
281
|
-
storage = rb_hash_aref(hash, key);
|
282
|
-
else {
|
283
|
-
storage = rb_ary_new2(alen);
|
284
|
-
rb_hash_aset(hash, key, storage);
|
285
|
-
}
|
286
|
-
rb_ary_push(storage, ind ? LONG2FIX(i) : group ? RARRAY_PTR(ary)[i] : key);
|
287
|
-
}
|
288
|
-
else {
|
289
|
-
if (st_lookup(RHASH_TBL(hash), key, &val))
|
290
|
-
rb_hash_aset(hash, key, LONG2FIX(FIX2LONG(val) + 1));
|
291
|
-
else
|
292
|
-
rb_hash_aset(hash, key, INT2FIX(1));
|
293
|
-
}
|
294
|
-
}
|
295
|
-
return hash;
|
296
|
-
}
|
297
|
-
|
298
|
-
/*
|
299
|
-
* call-seq:
|
300
|
-
* ary.partition {| obj | block } => [ true_array, false_array ]
|
301
|
-
*
|
302
|
-
* Same as Enumerable#partition, but twice faster
|
303
|
-
*
|
304
|
-
* [5, 6, 1, 2, 4, 3].partition {|i| (i&1).zero?} #=> [[2, 4, 6], [1, 3, 5]]
|
305
|
-
*
|
306
|
-
*/
|
307
|
-
|
308
|
-
static VALUE rb_ary_partition(VALUE ary)
|
309
|
-
{
|
310
|
-
VALUE select, reject;
|
311
|
-
long i, len;
|
312
|
-
|
313
|
-
RETURN_ENUMERATOR(ary, 0, 0);
|
314
|
-
len = RARRAY_LEN(ary);
|
315
|
-
select = rb_ary_new2(len);
|
316
|
-
reject = rb_ary_new2(len);
|
317
|
-
for (i = 0; i < len; i++)
|
318
|
-
rb_ary_push((RTEST(rb_yield(RARRAY_PTR(ary)[i])) ? select : reject), RARRAY_PTR(ary)[i]);
|
319
|
-
|
320
|
-
return rb_assoc_new(select, reject);
|
321
|
-
}
|
322
|
-
|
323
|
-
// HASH
|
324
|
-
|
325
|
-
static int replace_keys_i(VALUE key, VALUE value, VALUE hash)
|
326
|
-
{
|
327
|
-
if (key == Qundef) return ST_CONTINUE;
|
328
|
-
rb_hash_delete(hash, key);
|
329
|
-
rb_hash_aset(hash, rb_yield(key), value);
|
330
|
-
return ST_CONTINUE;
|
331
|
-
}
|
332
|
-
static int map_keys_i(VALUE key, VALUE value, VALUE hash)
|
333
|
-
{
|
334
|
-
if (key == Qundef) return ST_CONTINUE;
|
335
|
-
rb_hash_aset(hash, rb_yield(key), value);
|
336
|
-
return ST_CONTINUE;
|
337
|
-
}
|
338
|
-
static int map_values_i(VALUE key, VALUE value, VALUE hash)
|
339
|
-
{
|
340
|
-
if (key == Qundef) return ST_CONTINUE;
|
341
|
-
rb_hash_aset(hash, key, rb_yield(value));
|
342
|
-
return ST_CONTINUE;
|
343
|
-
}
|
344
|
-
static int map_pairs_i(VALUE key, VALUE value, VALUE hash)
|
345
|
-
{
|
346
|
-
if (key == Qundef) return ST_CONTINUE;
|
347
|
-
rb_hash_aset(hash, key, rb_yield(rb_assoc_new(key, value)));
|
348
|
-
return ST_CONTINUE;
|
349
|
-
}
|
350
|
-
|
351
|
-
/*
|
352
|
-
* Hashes map methods that doesn't make hash into array
|
353
|
-
* New hash may get shorter than source
|
354
|
-
*/
|
355
|
-
static VALUE rb_hash_map_keys_bang(VALUE hash)
|
356
|
-
{
|
357
|
-
rb_hash_foreach(hash, (int (*)(ANYARGS))replace_keys_i, hash);
|
358
|
-
return hash;
|
359
|
-
}
|
360
|
-
|
361
|
-
/*
|
362
|
-
* Hashes map methods that doesn't make hash into array
|
363
|
-
*/
|
364
|
-
static VALUE rb_hash_map_values_bang(VALUE hash)
|
365
|
-
{
|
366
|
-
rb_hash_foreach(hash, (int (*)(ANYARGS))map_values_i, hash);
|
367
|
-
return hash;
|
368
|
-
}
|
369
|
-
|
370
|
-
/*
|
371
|
-
* Hashes map methods that doesn't make hash into array
|
372
|
-
*/
|
373
|
-
static VALUE rb_hash_map_pairs_bang(VALUE hash)
|
374
|
-
{
|
375
|
-
rb_hash_foreach(hash, (int (*)(ANYARGS))map_pairs_i, hash);
|
376
|
-
return hash;
|
377
|
-
}
|
378
|
-
|
379
|
-
/*
|
380
|
-
* Hashes map methods that doesn't make hash into array
|
381
|
-
*/
|
382
|
-
static VALUE rb_hash_map_values(VALUE hash)
|
383
|
-
{
|
384
|
-
VALUE new_hash = rb_hash_new();
|
385
|
-
rb_hash_foreach(hash, (int (*)(ANYARGS))map_values_i, new_hash);
|
386
|
-
return new_hash;
|
387
|
-
}
|
388
|
-
|
389
|
-
/*
|
390
|
-
* Hashes map methods that doesn't make hash into array
|
391
|
-
* New hash may get shorter than source
|
392
|
-
*/
|
393
|
-
static VALUE rb_hash_map_keys(VALUE hash)
|
394
|
-
{
|
395
|
-
VALUE new_hash = rb_hash_new();
|
396
|
-
rb_hash_foreach(hash, (int (*)(ANYARGS))map_keys_i, new_hash);
|
397
|
-
return new_hash;
|
398
|
-
}
|
399
|
-
|
400
|
-
/*
|
401
|
-
* Hashes map methods that doesn't make hash into array
|
402
|
-
*/
|
403
|
-
static VALUE rb_hash_map_pairs(VALUE hash)
|
404
|
-
{
|
405
|
-
VALUE new_hash = rb_hash_new();
|
406
|
-
rb_hash_foreach(hash, (int (*)(ANYARGS))map_pairs_i, new_hash);
|
407
|
-
return new_hash;
|
408
|
-
}
|
409
|
-
|
410
|
-
/*
|
411
|
-
* x! ( specially for /c/ ^__^ )
|
412
|
-
* 5.fact # => 120
|
413
|
-
* x3 boost relative to 1.8.7
|
414
|
-
*/
|
415
|
-
static VALUE rb_math_factorial(VALUE x)
|
416
|
-
{
|
417
|
-
long a = FIX2LONG(x);
|
418
|
-
for (int i = 2; i < a; i++)
|
419
|
-
x = TYPE(x) == T_BIGNUM ?
|
420
|
-
rb_big_mul(x, rb_int2big(i)) :
|
421
|
-
rb_big_mul(rb_int2big(FIX2LONG(x)), rb_int2big(i));
|
422
|
-
return x;
|
423
|
-
}
|
424
|
-
|
425
|
-
static int unsigned_big_lte(VALUE x, VALUE y)
|
426
|
-
{
|
427
|
-
long xlen = RBIGNUM_LEN(x);
|
428
|
-
long ylen = RBIGNUM_LEN(y);
|
429
|
-
if (xlen < ylen) return 1;
|
430
|
-
if (xlen > RBIGNUM_LEN(y)) return 0;
|
431
|
-
while (xlen-- && (BDIGITS(x)[xlen]==BDIGITS(y)[xlen])) {};
|
432
|
-
if (-1 == xlen) return 1; // ==
|
433
|
-
return (BDIGITS(x)[xlen] > BDIGITS(y)[xlen]) ? 0 : 1;
|
434
|
-
}
|
435
|
-
/*
|
436
|
-
* timer(100000) {1073741823.factorize}
|
437
|
-
* => "res: [3, 3, 7, 11, 31, 151, 331], one: 0.0053ms, total: 530.0ms"
|
438
|
-
* ruby count Bignums starting from 2**30
|
439
|
-
* < 2**30: x1-x30 speed, >= 2**30: x1 - x3 speed ~_~
|
440
|
-
* Caution! It can just hung up on numbers over 2**64 and you'll have to kill it -9
|
441
|
-
* And this shit doesn't think if you have 64-bit system, so it could be faster a bit
|
442
|
-
*/
|
443
|
-
static VALUE rb_math_factorization(VALUE x) {
|
444
|
-
VALUE factors = rb_ary_new2(31);
|
445
|
-
int len = 0;
|
446
|
-
long y = FIX2LONG(x);
|
447
|
-
long n = 2;
|
448
|
-
while (n*n <= y) {
|
449
|
-
if (y%n == 0) {
|
450
|
-
y /= n;
|
451
|
-
rb_ary_store(factors, len++, LONG2FIX(n));
|
452
|
-
} else
|
453
|
-
n++;
|
454
|
-
}
|
455
|
-
rb_ary_store(factors, len++, LONG2FIX(y));
|
456
|
-
ARY_SET_LEN(factors, len);
|
457
|
-
return factors;
|
458
|
-
}
|
459
|
-
/*
|
460
|
-
* timer(100000) {1073741823.factorize}
|
461
|
-
* => "res: [3, 3, 7, 11, 31, 151, 331], one: 0.0053ms, total: 530.0ms"
|
462
|
-
* ruby count Bignums starting from 2**30
|
463
|
-
* < 2**30: x1-x30 speed, >= 2**30: x1 - x3 speed ~_~
|
464
|
-
* Caution! It can just hung up on numbers over 2**64 and you'll have to kill it -9
|
465
|
-
* And this shit doesn't think if you have 64-bit system, so it could be faster a bit
|
466
|
-
*/
|
467
|
-
static VALUE rb_math_big_factorization(VALUE y) {
|
468
|
-
VALUE factors = rb_ary_new2(127);
|
469
|
-
int len = 0;
|
470
|
-
long n = 2;
|
471
|
-
int cont = 0;
|
472
|
-
VALUE big_n, divmod, mod;
|
473
|
-
while (unsigned_big_lte(rb_int2big(n*n), y)) {
|
474
|
-
divmod = rb_big_divmod(y, rb_int2big(n));
|
475
|
-
mod = RARRAY_PTR(divmod)[1];
|
476
|
-
|
477
|
-
if (FIXNUM_P(mod) && !FIX2LONG(mod)) {
|
478
|
-
y = RARRAY_PTR(divmod)[0];
|
479
|
-
if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
|
480
|
-
rb_ary_store(factors, len++, LONG2FIX(n));
|
481
|
-
} else {
|
482
|
-
n++;
|
483
|
-
if (n == 46341) {
|
484
|
-
big_n = rb_int2big(n);
|
485
|
-
cont = 1;
|
486
|
-
break;
|
487
|
-
}
|
488
|
-
}
|
489
|
-
}
|
490
|
-
if (cont)
|
491
|
-
while (unsigned_big_lte(rb_big_mul(big_n, big_n), y)) {
|
492
|
-
divmod = rb_big_divmod(y, big_n);
|
493
|
-
mod = RARRAY_PTR(divmod)[1];
|
494
|
-
|
495
|
-
if (FIXNUM_P(mod) && !FIX2LONG(mod)) {
|
496
|
-
y = RARRAY_PTR(divmod)[0];
|
497
|
-
if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
|
498
|
-
rb_ary_store(factors, len++, big_n);
|
499
|
-
} else {
|
500
|
-
big_n = (n < LONG_MAX) ? rb_int2big(++n) : rb_big_plus(big_n, rb_int2big(1));
|
501
|
-
}
|
502
|
-
}
|
503
|
-
rb_ary_store(factors, len++, y);
|
504
|
-
ARY_SET_LEN(factors, len);
|
505
|
-
return factors;
|
506
|
-
}
|
507
|
-
|
508
|
-
|
509
|
-
/*
|
510
|
-
static VALUE rb_eval_frame(VALUE self, VALUE src, VALUE levv)
|
511
|
-
{
|
512
|
-
struct FRAME *frame_orig = ruby_frame;
|
513
|
-
NODE *node_orig = ruby_current_node;
|
514
|
-
VALUE val;
|
515
|
-
int i = 0, lev = FIX2INT(levv);
|
516
|
-
|
517
|
-
while (lev-- > 0) {
|
518
|
-
ruby_frame = ruby_frame->prev;
|
519
|
-
if (!ruby_frame) break;
|
520
|
-
}
|
521
|
-
|
522
|
-
val = rb_funcall(self, rb_intern("eval"), 1, src);
|
523
|
-
ruby_current_node = node_orig;
|
524
|
-
ruby_frame = frame_orig;
|
525
|
-
|
526
|
-
return val;
|
527
|
-
}
|
528
|
-
*/
|
529
|
-
extern "C" void Init_rmtools()
|
530
|
-
{
|
531
|
-
// rb_define_method(rb_mKernel, "eval_frame", RUBY_METHOD_FUNC(rb_eval_frame), 2);
|
532
|
-
|
533
|
-
rb_define_method(rb_cFixnum, "fact", RUBY_METHOD_FUNC(rb_math_factorial), 0);
|
534
|
-
rb_define_method(rb_cFixnum, "factorize", RUBY_METHOD_FUNC(rb_math_factorization), 0);
|
535
|
-
rb_define_method(rb_cBignum, "factorize", RUBY_METHOD_FUNC(rb_math_big_factorization), 0);
|
536
|
-
|
537
|
-
rb_define_method(rb_cHash, "map_keys", RUBY_METHOD_FUNC(rb_hash_map_keys), 0);
|
538
|
-
rb_define_method(rb_cHash, "map_values", RUBY_METHOD_FUNC(rb_hash_map_values), 0);
|
539
|
-
rb_define_method(rb_cHash, "map2", RUBY_METHOD_FUNC(rb_hash_map_pairs), 0);
|
540
|
-
rb_define_method(rb_cHash, "map_keys!", RUBY_METHOD_FUNC(rb_hash_map_keys_bang), 0);
|
541
|
-
rb_define_method(rb_cHash, "map_values!", RUBY_METHOD_FUNC(rb_hash_map_values_bang), 0);
|
542
|
-
rb_define_method(rb_cHash, "map!", RUBY_METHOD_FUNC(rb_hash_map_pairs_bang), 0);
|
543
|
-
|
544
|
-
rb_define_method(rb_cArray, "uniq_by", RUBY_METHOD_FUNC(rb_ary_uniq_by), 0);
|
545
|
-
rb_define_method(rb_cArray, "uniq_by!", RUBY_METHOD_FUNC(rb_ary_uniq_by_bang), 0);
|
546
|
-
|
547
|
-
rb_define_method(rb_cArray, "arrange", RUBY_METHOD_FUNC(rb_ary_count_items), -1);
|
548
|
-
|
549
|
-
rb_define_method(rb_cArray, "partition", RUBY_METHOD_FUNC(rb_ary_partition), 0);
|
550
|
-
|
551
|
-
rb_define_method(rb_cArray, "stranspose", RUBY_METHOD_FUNC(rb_ary_string_transpose), 0);
|
552
|
-
rb_define_method(rb_cArray, "turn_cw", RUBY_METHOD_FUNC(rb_ary_turn_cw), 0);
|
553
|
-
rb_define_method(rb_cArray, "turn_ccw", RUBY_METHOD_FUNC(rb_ary_turn_ccw), 0);
|
554
|
-
|
555
|
-
rb_define_method(rb_cString, "conj", RUBY_METHOD_FUNC(rb_str_conjunction), 1);
|
556
|
-
rb_define_method(rb_cString, "disj", RUBY_METHOD_FUNC(rb_str_disjunction), 1);
|
557
|
-
|
558
|
-
rb_define_method(rb_cObject, "define!", RUBY_METHOD_FUNC(object_define_new_value), 1);
|
559
|
-
}
|
560
|
-
|
1
|
+
#include "rmtools.h"
|
2
|
+
|
3
|
+
using namespace std;
|
4
|
+
|
5
|
+
/*
|
6
|
+
* Assign new value by variable or constant address. Can't process numeric, nil, false and true. Though, it can process containers with all of that shit.
|
7
|
+
* a = 'Object.new'
|
8
|
+
* => "Object.new"
|
9
|
+
* def inspire x
|
10
|
+
* x.define! eval x
|
11
|
+
* end
|
12
|
+
* => nil
|
13
|
+
* inspire a
|
14
|
+
* => #<Object:0xb790bed0>
|
15
|
+
* a
|
16
|
+
* => #<Object:0xb790bed0>
|
17
|
+
* It's quite buggy, you can get sudden segfault sometime after using method ^_^'\
|
18
|
+
* Maybe it could mark used objects for GC not to collect
|
19
|
+
*/
|
20
|
+
static VALUE object_define_new_value(VALUE self, VALUE new_obj)
|
21
|
+
{
|
22
|
+
if (FIXNUM_P(self) || self == Qnil || self == Qfalse || self == Qtrue || self == Qundef) {
|
23
|
+
VALUE tmp = rb_mod_name(rb_obj_class(self));
|
24
|
+
const char* msg = StringValuePtr(tmp);
|
25
|
+
rb_raise(rb_eTypeError, "can't redefine %s", msg);
|
26
|
+
}
|
27
|
+
if (FIXNUM_P(new_obj) || new_obj == Qnil || new_obj == Qfalse || new_obj == Qtrue || new_obj == Qundef) {
|
28
|
+
VALUE tmp = rb_mod_name(rb_obj_class(self));
|
29
|
+
const char* msg = StringValuePtr(tmp);
|
30
|
+
rb_raise(rb_eTypeError, "can't define object as %s", msg);
|
31
|
+
}
|
32
|
+
// Place the definition of the new object in the slot of self
|
33
|
+
memcpy(reinterpret_cast<void*>(self), reinterpret_cast<void*>(rb_funcall(new_obj, rb_intern("clone"), 0)), SLOT_SIZE);
|
34
|
+
return self;
|
35
|
+
}
|
36
|
+
|
37
|
+
|
38
|
+
/*
|
39
|
+
* puts ['123', '456', '789'].stranspose
|
40
|
+
* 147
|
41
|
+
* 258
|
42
|
+
* 369
|
43
|
+
*/
|
44
|
+
static VALUE rb_ary_string_transpose(VALUE ary)
|
45
|
+
{
|
46
|
+
long elen = -1, alen, i, j;
|
47
|
+
VALUE tmp, result = 0;
|
48
|
+
|
49
|
+
alen = RARRAY_LEN(ary);
|
50
|
+
if (alen == 0) return rb_ary_dup(ary);
|
51
|
+
for (i=0; i<alen; i++) {
|
52
|
+
tmp = RARRAY_PTR(ary)[i];
|
53
|
+
if (elen < 0) { /* first element */
|
54
|
+
elen = RSTRING_LEN(tmp);
|
55
|
+
result = rb_ary_new2(elen);
|
56
|
+
for (j=0; j<elen; j++) rb_ary_store(result, j, rb_str_new("", 0));
|
57
|
+
}
|
58
|
+
else if (elen != RSTRING_LEN(tmp))
|
59
|
+
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
60
|
+
RARRAY_LEN(tmp), elen);
|
61
|
+
for (j=0; j<elen; j++) rb_str_buf_cat(RARRAY_PTR(result)[j], &(RSTRING_PTR(tmp)[j]), 1);
|
62
|
+
}
|
63
|
+
return result;
|
64
|
+
}
|
65
|
+
|
66
|
+
/*
|
67
|
+
* puts ['123', '456', '789'].turn_ccw
|
68
|
+
* 369
|
69
|
+
* 258
|
70
|
+
* 147
|
71
|
+
*/
|
72
|
+
static VALUE rb_ary_turn_ccw(VALUE ary)
|
73
|
+
{
|
74
|
+
long elen, alen, i, j;
|
75
|
+
VALUE tmp, result = 0;
|
76
|
+
alen = RARRAY_LEN(ary);
|
77
|
+
if (alen == 0) return rb_ary_dup(ary);
|
78
|
+
|
79
|
+
tmp = RARRAY_PTR(ary)[0];
|
80
|
+
if (TYPE(tmp) == T_STRING) {
|
81
|
+
elen = RSTRING_LEN(tmp);
|
82
|
+
result = rb_ary_new2(elen);
|
83
|
+
for (j=0; j<elen; j++) rb_ary_store(result, j, rb_str_new("", 0));
|
84
|
+
for (i=0; i<alen; i++) {
|
85
|
+
if (i) tmp = RARRAY_PTR(ary)[i];
|
86
|
+
if (elen != RSTRING_LEN(tmp))
|
87
|
+
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
88
|
+
RARRAY_LEN(tmp), elen);
|
89
|
+
for (j=0; j<elen; j++) rb_str_buf_cat(RARRAY_PTR(result)[j], &(RSTRING_PTR(tmp)[elen-1-j]), 1);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
else {
|
93
|
+
elen = RARRAY_LEN(tmp);
|
94
|
+
for (j=0; j<elen; j++) rb_ary_store(result, j, rb_ary_new2(alen));
|
95
|
+
for (i=0; i<alen; i++) {
|
96
|
+
if (i) tmp = RARRAY_PTR(ary)[i];
|
97
|
+
if (elen != RARRAY_LEN(tmp))
|
98
|
+
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
99
|
+
RARRAY_LEN(tmp), elen);
|
100
|
+
for (j=0; j<elen; j++) rb_ary_store(RARRAY_PTR(result)[j], i, RARRAY_PTR(tmp)[elen-1-j]);
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
return result;
|
105
|
+
}
|
106
|
+
|
107
|
+
/*
|
108
|
+
* puts ['123', '456', '789'].turn_cw
|
109
|
+
* 147
|
110
|
+
* 258
|
111
|
+
* 369
|
112
|
+
*/
|
113
|
+
static VALUE rb_ary_turn_cw(VALUE ary)
|
114
|
+
{
|
115
|
+
long elen, alen, i, j;
|
116
|
+
VALUE tmp, result = 0;
|
117
|
+
alen = RARRAY_LEN(ary);
|
118
|
+
if (alen == 0) return rb_ary_dup(ary);
|
119
|
+
|
120
|
+
tmp = RARRAY_PTR(ary)[0];
|
121
|
+
if (TYPE(tmp) == T_STRING) {
|
122
|
+
elen = RSTRING_LEN(tmp);
|
123
|
+
result = rb_ary_new2(elen);
|
124
|
+
for (j=0; j<elen; j++) rb_ary_store(result, j, rb_str_new("", 0));
|
125
|
+
for (i=alen-1; i>-1; i--) {
|
126
|
+
tmp = RARRAY_PTR(ary)[i];
|
127
|
+
if (elen != RSTRING_LEN(tmp))
|
128
|
+
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
129
|
+
RARRAY_LEN(tmp), elen);
|
130
|
+
for (j=0; j<elen; j++) rb_str_buf_cat(RARRAY_PTR(result)[j], &(RSTRING_PTR(tmp)[j]), 1);
|
131
|
+
}
|
132
|
+
}
|
133
|
+
else {
|
134
|
+
elen = RARRAY_LEN(tmp);
|
135
|
+
for (j=0; j<elen; j++) rb_ary_store(result, j, rb_ary_new2(alen));
|
136
|
+
for (i=0; i<alen; i++) {
|
137
|
+
if (i) tmp = RARRAY_PTR(ary)[i];
|
138
|
+
if (elen != RARRAY_LEN(tmp))
|
139
|
+
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld)",
|
140
|
+
RARRAY_LEN(tmp), elen);
|
141
|
+
for (j=0; j<elen; j++) rb_ary_store(RARRAY_PTR(result)[j], elen-1-i, RARRAY_PTR(tmp)[j]);
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
return result;
|
146
|
+
}
|
147
|
+
|
148
|
+
/*
|
149
|
+
* " @@@@@@".conj " @@@ @@@"
|
150
|
+
* => " @@@"
|
151
|
+
*/
|
152
|
+
static VALUE rb_str_disjunction(VALUE self, VALUE str)
|
153
|
+
{
|
154
|
+
if (RSTRING_LEN(self) != RSTRING_LEN(str))
|
155
|
+
rb_raise(rb_eIndexError, "strings sizes differs (%ld and %ld)",
|
156
|
+
RSTRING_LEN(self), RSTRING_LEN(str));
|
157
|
+
VALUE new_str = rb_str_new("", 0);
|
158
|
+
int i;
|
159
|
+
const char *selfptr = RSTRING_PTR(self), *strptr = RSTRING_PTR(str);
|
160
|
+
for (i=0;i<RSTRING_LEN(str);i++) {
|
161
|
+
if (strptr[i] != ' ' || selfptr[i] != ' ')
|
162
|
+
rb_str_buf_cat(new_str, "@", 1);
|
163
|
+
else
|
164
|
+
rb_str_buf_cat(new_str, " ", 1);
|
165
|
+
}
|
166
|
+
return new_str;
|
167
|
+
}
|
168
|
+
|
169
|
+
/*
|
170
|
+
* " @@@@@@".disj " @@@ @@@"
|
171
|
+
* => " @@@@@@@@@"
|
172
|
+
*/
|
173
|
+
static VALUE rb_str_conjunction(VALUE self, VALUE str)
|
174
|
+
{
|
175
|
+
if (RSTRING_LEN(self) != RSTRING_LEN(str))
|
176
|
+
rb_raise(rb_eIndexError, "strings sizes differs (%ld and %ld)",
|
177
|
+
RSTRING_LEN(self), RSTRING_LEN(str));
|
178
|
+
VALUE new_str = rb_str_new("", 0);
|
179
|
+
int i;
|
180
|
+
const char *selfptr = RSTRING_PTR(self), *strptr = RSTRING_PTR(str);
|
181
|
+
for (i=0;i<RSTRING_LEN(str);i++) {
|
182
|
+
if (strptr[i] == '@' && selfptr[i] == '@')
|
183
|
+
rb_str_buf_cat(new_str, "@", 1);
|
184
|
+
else
|
185
|
+
rb_str_buf_cat(new_str, " ", 1);
|
186
|
+
}
|
187
|
+
return new_str;
|
188
|
+
}
|
189
|
+
|
190
|
+
/*
|
191
|
+
* Modifies array, throwing all elements not having unique block result
|
192
|
+
* a = randarr 10
|
193
|
+
* => [8, 2, 0, 5, 4, 1, 7, 3, 9, 6]
|
194
|
+
* a.uniq_by! {|e| e%2}
|
195
|
+
* => [8, 5]
|
196
|
+
* a
|
197
|
+
* => [8, 5]
|
198
|
+
* Here is implyied that callback block is +clean function+
|
199
|
+
*/
|
200
|
+
static VALUE rb_ary_uniq_by_bang(VALUE ary)
|
201
|
+
{
|
202
|
+
long len = RARRAY_LEN(ary);
|
203
|
+
if (len < 2)
|
204
|
+
return Qnil;
|
205
|
+
if (!rb_block_given_p())
|
206
|
+
return rb_ary_new4(RARRAY_LEN(ary), RARRAY_PTR(ary));
|
207
|
+
VALUE hash, res_hash, res, el;
|
208
|
+
long i, j;
|
209
|
+
|
210
|
+
hash = rb_hash_new();
|
211
|
+
res_hash = rb_hash_new();
|
212
|
+
for (i=j=0; i<len; i++) {
|
213
|
+
// We store an element itself and so we won't calculate function of it
|
214
|
+
// other time we'll find it in source. Ruby store function is very fast,
|
215
|
+
// so we can neglect its runtime even if source array is allready uniq
|
216
|
+
el = RARRAY_PTR(ary)[i];
|
217
|
+
if (st_lookup(RHASH_TBL(hash), el, 0)) continue;
|
218
|
+
res = rb_yield(el);
|
219
|
+
if (st_lookup(RHASH_TBL(res_hash), res, 0)) continue;
|
220
|
+
rb_hash_aset(hash, el, Qtrue);
|
221
|
+
rb_hash_aset(res_hash, res, Qtrue);
|
222
|
+
rb_ary_store(ary, j++, el);
|
223
|
+
}
|
224
|
+
ARY_SET_LEN(ary, j);
|
225
|
+
|
226
|
+
return j == len ? Qnil : ary;
|
227
|
+
}
|
228
|
+
|
229
|
+
/*
|
230
|
+
* Safe version of uniq_by!
|
231
|
+
*/
|
232
|
+
static VALUE rb_ary_uniq_by(VALUE ary)
|
233
|
+
{
|
234
|
+
VALUE ary_dup = rb_ary_dup(ary);
|
235
|
+
rb_ary_uniq_by_bang(ary_dup);
|
236
|
+
return ary_dup;
|
237
|
+
}
|
238
|
+
|
239
|
+
/*
|
240
|
+
* Make hash with unique items of +self+ or (when block given)
|
241
|
+
* unique results of items yield for keys and
|
242
|
+
* count of them in +self+,
|
243
|
+
* or (with option :fill) arrays of yield results,
|
244
|
+
* or (with option :indexes) arrays of indexes of them,
|
245
|
+
* or (with option :group) arrays of themselves for values
|
246
|
+
*
|
247
|
+
* [1, 2, 2, 2, 3, 3].arrange
|
248
|
+
* => {1=>1, 2=>3, 3=>2}
|
249
|
+
* [1, 2, 2, 2, 3, 3].arrange {|i| i%2}
|
250
|
+
* => {0=>3, 1=>3}
|
251
|
+
* [1, 2, 2, 2, 3, 3].arrange :fill
|
252
|
+
* => {1=>[1], 2=>[2, 2, 2], 3=>[3, 3]}
|
253
|
+
* [1, 2, 2, 2, 3, 3].arrange :indexes
|
254
|
+
* => {1=>[0], 2=>[1, 2, 3], 3=>[4, 5]}
|
255
|
+
* [1, 2, 2, 2, 3, 3].arrange(:indexes) {|i| i%2}
|
256
|
+
* => {0=>[1, 2, 3], 1=>[0, 4, 5]}
|
257
|
+
* :group is analogue to rails' group_by but twice faster
|
258
|
+
* [1, 2, 2, 2, 3, 3].arrange(:group) {|i| i%2}
|
259
|
+
* => {0=>[2, 2, 2], 1=>[1, 3, 3]}
|
260
|
+
*/
|
261
|
+
static VALUE rb_ary_count_items(int argc, VALUE *argv, VALUE ary)
|
262
|
+
{
|
263
|
+
long i, alen, block_given;
|
264
|
+
int fill, ind, group;
|
265
|
+
VALUE key, arg, storage;
|
266
|
+
VALUE hash = rb_hash_new();
|
267
|
+
VALUE val = Qnil;
|
268
|
+
|
269
|
+
block_given = rb_block_given_p();
|
270
|
+
rb_scan_args(argc, argv, "01", &arg);
|
271
|
+
ind = arg == ID2SYM(rb_intern("indexes"));
|
272
|
+
group = arg == ID2SYM(rb_intern("group"));
|
273
|
+
fill = ind || group || arg == ID2SYM(rb_intern("fill"));
|
274
|
+
|
275
|
+
alen = RARRAY_LEN(ary);
|
276
|
+
for (i=0; i<RARRAY_LEN(ary); i++) {
|
277
|
+
key = block_given ? rb_yield(RARRAY_PTR(ary)[i]) : RARRAY_PTR(ary)[i];
|
278
|
+
if (fill)
|
279
|
+
{
|
280
|
+
if (st_lookup(RHASH_TBL(hash), key, 0))
|
281
|
+
storage = rb_hash_aref(hash, key);
|
282
|
+
else {
|
283
|
+
storage = rb_ary_new2(alen);
|
284
|
+
rb_hash_aset(hash, key, storage);
|
285
|
+
}
|
286
|
+
rb_ary_push(storage, ind ? LONG2FIX(i) : group ? RARRAY_PTR(ary)[i] : key);
|
287
|
+
}
|
288
|
+
else {
|
289
|
+
if (st_lookup(RHASH_TBL(hash), key, &val))
|
290
|
+
rb_hash_aset(hash, key, LONG2FIX(FIX2LONG(val) + 1));
|
291
|
+
else
|
292
|
+
rb_hash_aset(hash, key, INT2FIX(1));
|
293
|
+
}
|
294
|
+
}
|
295
|
+
return hash;
|
296
|
+
}
|
297
|
+
|
298
|
+
/*
|
299
|
+
* call-seq:
|
300
|
+
* ary.partition {| obj | block } => [ true_array, false_array ]
|
301
|
+
*
|
302
|
+
* Same as Enumerable#partition, but twice faster
|
303
|
+
*
|
304
|
+
* [5, 6, 1, 2, 4, 3].partition {|i| (i&1).zero?} #=> [[2, 4, 6], [1, 3, 5]]
|
305
|
+
*
|
306
|
+
*/
|
307
|
+
|
308
|
+
static VALUE rb_ary_partition(VALUE ary)
|
309
|
+
{
|
310
|
+
VALUE select, reject;
|
311
|
+
long i, len;
|
312
|
+
|
313
|
+
RETURN_ENUMERATOR(ary, 0, 0);
|
314
|
+
len = RARRAY_LEN(ary);
|
315
|
+
select = rb_ary_new2(len);
|
316
|
+
reject = rb_ary_new2(len);
|
317
|
+
for (i = 0; i < len; i++)
|
318
|
+
rb_ary_push((RTEST(rb_yield(RARRAY_PTR(ary)[i])) ? select : reject), RARRAY_PTR(ary)[i]);
|
319
|
+
|
320
|
+
return rb_assoc_new(select, reject);
|
321
|
+
}
|
322
|
+
|
323
|
+
// HASH
|
324
|
+
|
325
|
+
static int replace_keys_i(VALUE key, VALUE value, VALUE hash)
|
326
|
+
{
|
327
|
+
if (key == Qundef) return ST_CONTINUE;
|
328
|
+
rb_hash_delete(hash, key);
|
329
|
+
rb_hash_aset(hash, rb_yield(key), value);
|
330
|
+
return ST_CONTINUE;
|
331
|
+
}
|
332
|
+
static int map_keys_i(VALUE key, VALUE value, VALUE hash)
|
333
|
+
{
|
334
|
+
if (key == Qundef) return ST_CONTINUE;
|
335
|
+
rb_hash_aset(hash, rb_yield(key), value);
|
336
|
+
return ST_CONTINUE;
|
337
|
+
}
|
338
|
+
static int map_values_i(VALUE key, VALUE value, VALUE hash)
|
339
|
+
{
|
340
|
+
if (key == Qundef) return ST_CONTINUE;
|
341
|
+
rb_hash_aset(hash, key, rb_yield(value));
|
342
|
+
return ST_CONTINUE;
|
343
|
+
}
|
344
|
+
static int map_pairs_i(VALUE key, VALUE value, VALUE hash)
|
345
|
+
{
|
346
|
+
if (key == Qundef) return ST_CONTINUE;
|
347
|
+
rb_hash_aset(hash, key, rb_yield(rb_assoc_new(key, value)));
|
348
|
+
return ST_CONTINUE;
|
349
|
+
}
|
350
|
+
|
351
|
+
/*
|
352
|
+
* Hashes map methods that doesn't make hash into array
|
353
|
+
* New hash may get shorter than source
|
354
|
+
*/
|
355
|
+
static VALUE rb_hash_map_keys_bang(VALUE hash)
|
356
|
+
{
|
357
|
+
rb_hash_foreach(hash, (int (*)(ANYARGS))replace_keys_i, hash);
|
358
|
+
return hash;
|
359
|
+
}
|
360
|
+
|
361
|
+
/*
|
362
|
+
* Hashes map methods that doesn't make hash into array
|
363
|
+
*/
|
364
|
+
static VALUE rb_hash_map_values_bang(VALUE hash)
|
365
|
+
{
|
366
|
+
rb_hash_foreach(hash, (int (*)(ANYARGS))map_values_i, hash);
|
367
|
+
return hash;
|
368
|
+
}
|
369
|
+
|
370
|
+
/*
|
371
|
+
* Hashes map methods that doesn't make hash into array
|
372
|
+
*/
|
373
|
+
static VALUE rb_hash_map_pairs_bang(VALUE hash)
|
374
|
+
{
|
375
|
+
rb_hash_foreach(hash, (int (*)(ANYARGS))map_pairs_i, hash);
|
376
|
+
return hash;
|
377
|
+
}
|
378
|
+
|
379
|
+
/*
|
380
|
+
* Hashes map methods that doesn't make hash into array
|
381
|
+
*/
|
382
|
+
static VALUE rb_hash_map_values(VALUE hash)
|
383
|
+
{
|
384
|
+
VALUE new_hash = rb_hash_new();
|
385
|
+
rb_hash_foreach(hash, (int (*)(ANYARGS))map_values_i, new_hash);
|
386
|
+
return new_hash;
|
387
|
+
}
|
388
|
+
|
389
|
+
/*
|
390
|
+
* Hashes map methods that doesn't make hash into array
|
391
|
+
* New hash may get shorter than source
|
392
|
+
*/
|
393
|
+
static VALUE rb_hash_map_keys(VALUE hash)
|
394
|
+
{
|
395
|
+
VALUE new_hash = rb_hash_new();
|
396
|
+
rb_hash_foreach(hash, (int (*)(ANYARGS))map_keys_i, new_hash);
|
397
|
+
return new_hash;
|
398
|
+
}
|
399
|
+
|
400
|
+
/*
|
401
|
+
* Hashes map methods that doesn't make hash into array
|
402
|
+
*/
|
403
|
+
static VALUE rb_hash_map_pairs(VALUE hash)
|
404
|
+
{
|
405
|
+
VALUE new_hash = rb_hash_new();
|
406
|
+
rb_hash_foreach(hash, (int (*)(ANYARGS))map_pairs_i, new_hash);
|
407
|
+
return new_hash;
|
408
|
+
}
|
409
|
+
|
410
|
+
/*
|
411
|
+
* x! ( specially for /c/ ^__^ )
|
412
|
+
* 5.fact # => 120
|
413
|
+
* x3 boost relative to 1.8.7
|
414
|
+
*/
|
415
|
+
static VALUE rb_math_factorial(VALUE x)
|
416
|
+
{
|
417
|
+
long a = FIX2LONG(x);
|
418
|
+
for (int i = 2; i < a; i++)
|
419
|
+
x = TYPE(x) == T_BIGNUM ?
|
420
|
+
rb_big_mul(x, rb_int2big(i)) :
|
421
|
+
rb_big_mul(rb_int2big(FIX2LONG(x)), rb_int2big(i));
|
422
|
+
return x;
|
423
|
+
}
|
424
|
+
|
425
|
+
static int unsigned_big_lte(VALUE x, VALUE y)
|
426
|
+
{
|
427
|
+
long xlen = RBIGNUM_LEN(x);
|
428
|
+
long ylen = RBIGNUM_LEN(y);
|
429
|
+
if (xlen < ylen) return 1;
|
430
|
+
if (xlen > RBIGNUM_LEN(y)) return 0;
|
431
|
+
while (xlen-- && (BDIGITS(x)[xlen]==BDIGITS(y)[xlen])) {};
|
432
|
+
if (-1 == xlen) return 1; // ==
|
433
|
+
return (BDIGITS(x)[xlen] > BDIGITS(y)[xlen]) ? 0 : 1;
|
434
|
+
}
|
435
|
+
/*
|
436
|
+
* timer(100000) {1073741823.factorize}
|
437
|
+
* => "res: [3, 3, 7, 11, 31, 151, 331], one: 0.0053ms, total: 530.0ms"
|
438
|
+
* ruby count Bignums starting from 2**30
|
439
|
+
* < 2**30: x1-x30 speed, >= 2**30: x1 - x3 speed ~_~
|
440
|
+
* Caution! It can just hung up on numbers over 2**64 and you'll have to kill it -9
|
441
|
+
* And this shit doesn't think if you have 64-bit system, so it could be faster a bit
|
442
|
+
*/
|
443
|
+
static VALUE rb_math_factorization(VALUE x) {
|
444
|
+
VALUE factors = rb_ary_new2(31);
|
445
|
+
int len = 0;
|
446
|
+
long y = FIX2LONG(x);
|
447
|
+
long n = 2;
|
448
|
+
while (n*n <= y) {
|
449
|
+
if (y%n == 0) {
|
450
|
+
y /= n;
|
451
|
+
rb_ary_store(factors, len++, LONG2FIX(n));
|
452
|
+
} else
|
453
|
+
n++;
|
454
|
+
}
|
455
|
+
rb_ary_store(factors, len++, LONG2FIX(y));
|
456
|
+
ARY_SET_LEN(factors, len);
|
457
|
+
return factors;
|
458
|
+
}
|
459
|
+
/*
|
460
|
+
* timer(100000) {1073741823.factorize}
|
461
|
+
* => "res: [3, 3, 7, 11, 31, 151, 331], one: 0.0053ms, total: 530.0ms"
|
462
|
+
* ruby count Bignums starting from 2**30
|
463
|
+
* < 2**30: x1-x30 speed, >= 2**30: x1 - x3 speed ~_~
|
464
|
+
* Caution! It can just hung up on numbers over 2**64 and you'll have to kill it -9
|
465
|
+
* And this shit doesn't think if you have 64-bit system, so it could be faster a bit
|
466
|
+
*/
|
467
|
+
static VALUE rb_math_big_factorization(VALUE y) {
|
468
|
+
VALUE factors = rb_ary_new2(127);
|
469
|
+
int len = 0;
|
470
|
+
long n = 2;
|
471
|
+
int cont = 0;
|
472
|
+
VALUE big_n, divmod, mod;
|
473
|
+
while (unsigned_big_lte(rb_int2big(n*n), y)) {
|
474
|
+
divmod = rb_big_divmod(y, rb_int2big(n));
|
475
|
+
mod = RARRAY_PTR(divmod)[1];
|
476
|
+
|
477
|
+
if (FIXNUM_P(mod) && !FIX2LONG(mod)) {
|
478
|
+
y = RARRAY_PTR(divmod)[0];
|
479
|
+
if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
|
480
|
+
rb_ary_store(factors, len++, LONG2FIX(n));
|
481
|
+
} else {
|
482
|
+
n++;
|
483
|
+
if (n == 46341) {
|
484
|
+
big_n = rb_int2big(n);
|
485
|
+
cont = 1;
|
486
|
+
break;
|
487
|
+
}
|
488
|
+
}
|
489
|
+
}
|
490
|
+
if (cont)
|
491
|
+
while (unsigned_big_lte(rb_big_mul(big_n, big_n), y)) {
|
492
|
+
divmod = rb_big_divmod(y, big_n);
|
493
|
+
mod = RARRAY_PTR(divmod)[1];
|
494
|
+
|
495
|
+
if (FIXNUM_P(mod) && !FIX2LONG(mod)) {
|
496
|
+
y = RARRAY_PTR(divmod)[0];
|
497
|
+
if (FIXNUM_P(y)) y = rb_int2big(FIX2LONG(y));
|
498
|
+
rb_ary_store(factors, len++, big_n);
|
499
|
+
} else {
|
500
|
+
big_n = (n < LONG_MAX) ? rb_int2big(++n) : rb_big_plus(big_n, rb_int2big(1));
|
501
|
+
}
|
502
|
+
}
|
503
|
+
rb_ary_store(factors, len++, y);
|
504
|
+
ARY_SET_LEN(factors, len);
|
505
|
+
return factors;
|
506
|
+
}
|
507
|
+
|
508
|
+
|
509
|
+
/*
|
510
|
+
static VALUE rb_eval_frame(VALUE self, VALUE src, VALUE levv)
|
511
|
+
{
|
512
|
+
struct FRAME *frame_orig = ruby_frame;
|
513
|
+
NODE *node_orig = ruby_current_node;
|
514
|
+
VALUE val;
|
515
|
+
int i = 0, lev = FIX2INT(levv);
|
516
|
+
|
517
|
+
while (lev-- > 0) {
|
518
|
+
ruby_frame = ruby_frame->prev;
|
519
|
+
if (!ruby_frame) break;
|
520
|
+
}
|
521
|
+
|
522
|
+
val = rb_funcall(self, rb_intern("eval"), 1, src);
|
523
|
+
ruby_current_node = node_orig;
|
524
|
+
ruby_frame = frame_orig;
|
525
|
+
|
526
|
+
return val;
|
527
|
+
}
|
528
|
+
*/
|
529
|
+
extern "C" void Init_rmtools()
|
530
|
+
{
|
531
|
+
// rb_define_method(rb_mKernel, "eval_frame", RUBY_METHOD_FUNC(rb_eval_frame), 2);
|
532
|
+
|
533
|
+
rb_define_method(rb_cFixnum, "fact", RUBY_METHOD_FUNC(rb_math_factorial), 0);
|
534
|
+
rb_define_method(rb_cFixnum, "factorize", RUBY_METHOD_FUNC(rb_math_factorization), 0);
|
535
|
+
rb_define_method(rb_cBignum, "factorize", RUBY_METHOD_FUNC(rb_math_big_factorization), 0);
|
536
|
+
|
537
|
+
rb_define_method(rb_cHash, "map_keys", RUBY_METHOD_FUNC(rb_hash_map_keys), 0);
|
538
|
+
rb_define_method(rb_cHash, "map_values", RUBY_METHOD_FUNC(rb_hash_map_values), 0);
|
539
|
+
rb_define_method(rb_cHash, "map2", RUBY_METHOD_FUNC(rb_hash_map_pairs), 0);
|
540
|
+
rb_define_method(rb_cHash, "map_keys!", RUBY_METHOD_FUNC(rb_hash_map_keys_bang), 0);
|
541
|
+
rb_define_method(rb_cHash, "map_values!", RUBY_METHOD_FUNC(rb_hash_map_values_bang), 0);
|
542
|
+
rb_define_method(rb_cHash, "map!", RUBY_METHOD_FUNC(rb_hash_map_pairs_bang), 0);
|
543
|
+
|
544
|
+
rb_define_method(rb_cArray, "uniq_by", RUBY_METHOD_FUNC(rb_ary_uniq_by), 0);
|
545
|
+
rb_define_method(rb_cArray, "uniq_by!", RUBY_METHOD_FUNC(rb_ary_uniq_by_bang), 0);
|
546
|
+
|
547
|
+
rb_define_method(rb_cArray, "arrange", RUBY_METHOD_FUNC(rb_ary_count_items), -1);
|
548
|
+
|
549
|
+
rb_define_method(rb_cArray, "partition", RUBY_METHOD_FUNC(rb_ary_partition), 0);
|
550
|
+
|
551
|
+
rb_define_method(rb_cArray, "stranspose", RUBY_METHOD_FUNC(rb_ary_string_transpose), 0);
|
552
|
+
rb_define_method(rb_cArray, "turn_cw", RUBY_METHOD_FUNC(rb_ary_turn_cw), 0);
|
553
|
+
rb_define_method(rb_cArray, "turn_ccw", RUBY_METHOD_FUNC(rb_ary_turn_ccw), 0);
|
554
|
+
|
555
|
+
rb_define_method(rb_cString, "conj", RUBY_METHOD_FUNC(rb_str_conjunction), 1);
|
556
|
+
rb_define_method(rb_cString, "disj", RUBY_METHOD_FUNC(rb_str_disjunction), 1);
|
557
|
+
|
558
|
+
rb_define_method(rb_cObject, "define!", RUBY_METHOD_FUNC(object_define_new_value), 1);
|
559
|
+
}
|
560
|
+
|