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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a624e7cdadf7421d7df627648c5feb73f4dfe683
4
- data.tar.gz: 9aece4ce00e37b2f92dc01ab2bd9226cdb1220ae
3
+ metadata.gz: 4af007b3b54a30faa10b74f7954970878d36ab73
4
+ data.tar.gz: 202e16f990d3115ef0d9a934b0fec88f52c85644
5
5
  SHA512:
6
- metadata.gz: 5b56ed690d219c2d040e067fb9037a9f733303813c9faf8c61a82f1edf5861e96395d37a9181dc7d2c3ad70bfa9c2a77770689cdbb47772ecc4070d615d76c55
7
- data.tar.gz: fad21c0a9f989576ad787191ac9694c1ea149fb59c34aee367b6f10fb154c36568e42e750c730e063ef092e2de08f2f7a78edf719716c936f7e3bd71cc547769
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.3.5
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
+