rmtools 2.2.7 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
+