ralgorithms 0.2.1 → 0.3.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.
@@ -0,0 +1,8 @@
1
+ require 'mkmf'
2
+ $CFLAGS << " -DRUBY19" if RUBY_VERSION >= '1.9.0'
3
+ $CFLAGS << " -DRUBY186" if RUBY_VERSION < '1.8.7'
4
+ $CFLAGS << " -Wall " unless RUBY_PLATFORM =~ /solaris/
5
+ $CFLAGS << ' -g -ggdb -rdynamic -O0 -DDEBUG' if ENV['DEBUG']
6
+ $CFLAGS << " -Wconversion -Wsign-compare -Wno-unused-parameter -Wwrite-strings -Wpointer-arith -fno-common -pedantic -Wno-long-long" if ENV['STRICT']
7
+ $CFLAGS << (ENV['CFLAGS'] || '')
8
+ create_makefile("sorting_ext")
@@ -0,0 +1,401 @@
1
+ #include "ruby/ruby.h"
2
+ #include <assert.h>
3
+
4
+ const char*
5
+ obj_inspect(VALUE obj) {
6
+ VALUE str = rb_funcall(obj, rb_intern("inspect"), 0);
7
+ const char * result = RSTRING_PTR(str);
8
+ return result;
9
+ }
10
+
11
+ void
12
+ print_ruby_obj(const char* prefix, VALUE obj)
13
+ {
14
+ const char* str = obj_inspect(obj);
15
+ printf("%s: %s\n", prefix, str);
16
+ }
17
+
18
+ void
19
+ printp_ruby_obj(const char* prefix, void* base)
20
+ {
21
+ VALUE obj = *(const VALUE*)base;
22
+ print_ruby_obj(prefix, obj);
23
+ }
24
+
25
+ static ID id_cmp;
26
+ struct ary_sort_data {
27
+ VALUE ary;
28
+ int opt_methods;
29
+ int opt_inited;
30
+ };
31
+ enum {
32
+ sort_opt_Fixnum,
33
+ sort_opt_String,
34
+ sort_optimizable_count
35
+ };
36
+
37
+ #define STRING_P(s) (TYPE(s) == T_STRING && CLASS_OF(s) == rb_cString)
38
+
39
+ #define SORT_OPTIMIZABLE_BIT(type) (1U << TOKEN_PASTE(sort_opt_,type))
40
+ #define SORT_OPTIMIZABLE(data, type) \
41
+ ((data->opt_inited & SORT_OPTIMIZABLE_BIT(type)) ? \
42
+ (data->opt_methods & SORT_OPTIMIZABLE_BIT(type)) : \
43
+ ((data->opt_inited |= SORT_OPTIMIZABLE_BIT(type)), \
44
+ rb_method_basic_definition_p(TOKEN_PASTE(rb_c,type), id_cmp) && \
45
+ (data->opt_methods |= SORT_OPTIMIZABLE_BIT(type))))
46
+
47
+ # define ARY_SHARED_P(ary) \
48
+ (assert(!FL_TEST(ary, ELTS_SHARED) || !FL_TEST(ary, RARRAY_EMBED_FLAG)), \
49
+ FL_TEST(ary,ELTS_SHARED)!=0)
50
+ # define ARY_EMBED_P(ary) \
51
+ (assert(!FL_TEST(ary, ELTS_SHARED) || !FL_TEST(ary, RARRAY_EMBED_FLAG)), \
52
+ FL_TEST(ary, RARRAY_EMBED_FLAG)!=0)
53
+
54
+ #define ARY_HEAP_PTR(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr)
55
+ #define ARY_HEAP_LEN(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len)
56
+ #define ARY_EMBED_PTR(a) (assert(ARY_EMBED_P(a)), RARRAY(a)->as.ary)
57
+ #define ARY_EMBED_LEN(a) \
58
+ (assert(ARY_EMBED_P(a)), \
59
+ (long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \
60
+ (RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT)))
61
+
62
+ #define ARY_OWNS_HEAP_P(a) (!FL_TEST(a, ELTS_SHARED|RARRAY_EMBED_FLAG))
63
+ #define FL_SET_EMBED(a) do { \
64
+ assert(!ARY_SHARED_P(a)); \
65
+ assert(!OBJ_FROZEN(a)); \
66
+ FL_SET(a, RARRAY_EMBED_FLAG); \
67
+ } while (0)
68
+ #define FL_UNSET_EMBED(ary) FL_UNSET(ary, RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK)
69
+ #define FL_SET_SHARED(ary) do { \
70
+ assert(!ARY_EMBED_P(ary)); \
71
+ FL_SET(ary, ELTS_SHARED); \
72
+ } while (0)
73
+ #define FL_UNSET_SHARED(ary) FL_UNSET(ary, ELTS_SHARED)
74
+
75
+ #define ARY_SET_PTR(ary, p) do { \
76
+ assert(!ARY_EMBED_P(ary)); \
77
+ assert(!OBJ_FROZEN(ary)); \
78
+ RARRAY(ary)->as.heap.ptr = (p); \
79
+ } while (0)
80
+ #define ARY_SET_EMBED_LEN(ary, n) do { \
81
+ long tmp_n = n; \
82
+ assert(ARY_EMBED_P(ary)); \
83
+ assert(!OBJ_FROZEN(ary)); \
84
+ RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; \
85
+ RBASIC(ary)->flags |= (tmp_n) << RARRAY_EMBED_LEN_SHIFT; \
86
+ } while (0)
87
+ #define ARY_SET_HEAP_LEN(ary, n) do { \
88
+ assert(!ARY_EMBED_P(ary)); \
89
+ RARRAY(ary)->as.heap.len = n; \
90
+ } while (0)
91
+ #define ARY_SET_LEN(ary, n) do { \
92
+ if (ARY_EMBED_P(ary)) { \
93
+ ARY_SET_EMBED_LEN(ary, n); \
94
+ } \
95
+ else { \
96
+ ARY_SET_HEAP_LEN(ary, n); \
97
+ } \
98
+ assert(RARRAY_LEN(ary) == n); \
99
+ } while (0)
100
+ #define ARY_INCREASE_PTR(ary, n) do { \
101
+ assert(!ARY_EMBED_P(ary)); \
102
+ assert(!OBJ_FROZEN(ary)); \
103
+ RARRAY(ary)->as.heap.ptr += n; \
104
+ } while (0)
105
+ #define ARY_INCREASE_LEN(ary, n) do { \
106
+ assert(!OBJ_FROZEN(ary)); \
107
+ if (ARY_EMBED_P(ary)) { \
108
+ ARY_SET_EMBED_LEN(ary, RARRAY_LEN(ary)+n); \
109
+ } \
110
+ else { \
111
+ RARRAY(ary)->as.heap.len += n; \
112
+ } \
113
+ } while (0)
114
+
115
+ #define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? RARRAY_EMBED_LEN_MAX : \
116
+ ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : RARRAY(ary)->as.heap.aux.capa)
117
+ #define ARY_SET_CAPA(ary, n) do { \
118
+ assert(!ARY_EMBED_P(ary)); \
119
+ assert(!ARY_SHARED_P(ary)); \
120
+ assert(!OBJ_FROZEN(ary)); \
121
+ RARRAY(ary)->as.heap.aux.capa = (n); \
122
+ } while (0)
123
+
124
+ #define ARY_SHARED(ary) (assert(ARY_SHARED_P(ary)), RARRAY(ary)->as.heap.aux.shared)
125
+ #define ARY_SET_SHARED(ary, value) do { \
126
+ assert(!ARY_EMBED_P(ary)); \
127
+ assert(ARY_SHARED_P(ary)); \
128
+ assert(ARY_SHARED_ROOT_P(value)); \
129
+ RARRAY(ary)->as.heap.aux.shared = (value); \
130
+ } while (0)
131
+ #define RARRAY_SHARED_ROOT_FLAG FL_USER5
132
+ #define ARY_SHARED_ROOT_P(ary) (FL_TEST(ary, RARRAY_SHARED_ROOT_FLAG))
133
+ #define ARY_SHARED_NUM(ary) \
134
+ (assert(ARY_SHARED_ROOT_P(ary)), RARRAY(ary)->as.heap.aux.capa)
135
+ #define ARY_SET_SHARED_NUM(ary, value) do { \
136
+ assert(ARY_SHARED_ROOT_P(ary)); \
137
+ RARRAY(ary)->as.heap.aux.capa = (value); \
138
+ } while (0)
139
+ #define FL_SET_SHARED_ROOT(ary) do { \
140
+ assert(!ARY_EMBED_P(ary)); \
141
+ FL_SET(ary, RARRAY_SHARED_ROOT_FLAG); \
142
+ } while (0)
143
+
144
+ static VALUE
145
+ rb_ary_increment_share(VALUE shared)
146
+ {
147
+ long num = ARY_SHARED_NUM(shared);
148
+ if (num >= 0) {
149
+ ARY_SET_SHARED_NUM(shared, num + 1);
150
+ }
151
+ return shared;
152
+ }
153
+
154
+ static void
155
+ rb_ary_decrement_share(VALUE shared)
156
+ {
157
+ if (shared) {
158
+ long num = ARY_SHARED_NUM(shared) - 1;
159
+ if (num == 0) {
160
+ rb_ary_free(shared);
161
+ rb_gc_force_recycle(shared);
162
+ }
163
+ else if (num > 0) {
164
+ ARY_SET_SHARED_NUM(shared, num);
165
+ }
166
+ }
167
+ }
168
+
169
+ static void
170
+ rb_ary_unshare(VALUE ary)
171
+ {
172
+ VALUE shared = RARRAY(ary)->as.heap.aux.shared;
173
+ rb_ary_decrement_share(shared);
174
+ FL_UNSET_SHARED(ary);
175
+ }
176
+
177
+ static VALUE
178
+ ary_make_shared(VALUE ary)
179
+ {
180
+ assert(!ARY_EMBED_P(ary));
181
+ if (ARY_SHARED_P(ary)) {
182
+ return ARY_SHARED(ary);
183
+ }
184
+ else if (ARY_SHARED_ROOT_P(ary)) {
185
+ return ary;
186
+ }
187
+ else if (OBJ_FROZEN(ary)) {
188
+ ary_resize_capa(ary, ARY_HEAP_LEN(ary));
189
+ FL_SET_SHARED_ROOT(ary);
190
+ ARY_SET_SHARED_NUM(ary, 1);
191
+ return ary;
192
+ }
193
+ else {
194
+ NEWOBJ(shared, struct RArray);
195
+ OBJSETUP(shared, 0, T_ARRAY);
196
+ FL_UNSET_EMBED(shared);
197
+
198
+ ARY_SET_LEN((VALUE)shared, RARRAY_LEN(ary));
199
+ ARY_SET_PTR((VALUE)shared, RARRAY_PTR(ary));
200
+ FL_SET_SHARED_ROOT(shared);
201
+ ARY_SET_SHARED_NUM((VALUE)shared, 1);
202
+ FL_SET_SHARED(ary);
203
+ ARY_SET_SHARED(ary, (VALUE)shared);
204
+ OBJ_FREEZE(shared);
205
+ return (VALUE)shared;
206
+ }
207
+ }
208
+ static VALUE
209
+ ary_make_substitution(VALUE ary)
210
+ {
211
+ if (RARRAY_LEN(ary) <= RARRAY_EMBED_LEN_MAX) {
212
+ VALUE subst = rb_ary_new2(RARRAY_LEN(ary));
213
+ MEMCPY(ARY_EMBED_PTR(subst), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
214
+ ARY_SET_EMBED_LEN(subst, RARRAY_LEN(ary));
215
+ return subst;
216
+ }
217
+ else {
218
+ return rb_ary_increment_share(ary_make_shared(ary));
219
+ }
220
+ }
221
+
222
+ static VALUE
223
+ sort_reentered(VALUE ary)
224
+ {
225
+ if (RBASIC(ary)->klass) {
226
+ rb_raise(rb_eRuntimeError, "sort reentered");
227
+ }
228
+ return Qnil;
229
+ }
230
+
231
+ static inline void
232
+ rb_ary_modify_check(VALUE ary)
233
+ {
234
+ if (OBJ_FROZEN(ary)) rb_error_frozen("array");
235
+ if (!OBJ_UNTRUSTED(ary) && rb_safe_level() >= 4)
236
+ rb_raise(rb_eSecurityError, "Insecure: can't modify array");
237
+ }
238
+ static void
239
+ rb_ary_modify(VALUE ary)
240
+ {
241
+ rb_ary_modify_check(ary);
242
+ if (ARY_SHARED_P(ary)) {
243
+ long len = RARRAY_LEN(ary);
244
+ if (len <= RARRAY_EMBED_LEN_MAX) {
245
+ VALUE *ptr = ARY_HEAP_PTR(ary);
246
+ VALUE shared = ARY_SHARED(ary);
247
+ FL_UNSET_SHARED(ary);
248
+ FL_SET_EMBED(ary);
249
+ MEMCPY(ARY_EMBED_PTR(ary), ptr, VALUE, len);
250
+ rb_ary_decrement_share(shared);
251
+ ARY_SET_EMBED_LEN(ary, len);
252
+ }
253
+ else {
254
+ VALUE *ptr = ALLOC_N(VALUE, len);
255
+ MEMCPY(ptr, RARRAY_PTR(ary), VALUE, len);
256
+ rb_ary_unshare(ary);
257
+ ARY_SET_CAPA(ary, len);
258
+ ARY_SET_PTR(ary, ptr);
259
+ }
260
+ }
261
+ }
262
+
263
+ static int
264
+ sort_1(const void *ap, const void *bp, void *dummy)
265
+ {
266
+ struct ary_sort_data *data = dummy;
267
+ VALUE retval = sort_reentered(data->ary);
268
+ VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
269
+ int n;
270
+
271
+ retval = rb_yield_values(2, a, b);
272
+ n = rb_cmpint(retval, a, b);
273
+ sort_reentered(data->ary);
274
+ return n;
275
+ }
276
+
277
+ static int
278
+ sort_2(const void *ap, const void *bp, void *dummy)
279
+ {
280
+ struct ary_sort_data *data = dummy;
281
+ VALUE retval = sort_reentered(data->ary);
282
+ VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp;
283
+ int n;
284
+
285
+ if (FIXNUM_P(a) && FIXNUM_P(b) && SORT_OPTIMIZABLE(data, Fixnum)) {
286
+ if ((long)a > (long)b) return 1;
287
+ if ((long)a < (long)b) return -1;
288
+ return 0;
289
+ }
290
+ if (STRING_P(a) && STRING_P(b) && SORT_OPTIMIZABLE(data, String)) {
291
+ return rb_str_cmp(a, b);
292
+ }
293
+
294
+ retval = rb_funcall(a, id_cmp, 1, b);
295
+ n = rb_cmpint(retval, a, b);
296
+ sort_reentered(data->ary);
297
+
298
+ return n;
299
+ }
300
+
301
+ static int
302
+ sort_3(VALUE a, VALUE b, void *dummy)
303
+ {
304
+ struct ary_sort_data *data = dummy;
305
+ VALUE retval = sort_reentered(data->ary);
306
+ int n;
307
+
308
+ retval = rb_yield_values(2, a, b);
309
+ n = rb_cmpint(retval, a, b);
310
+ sort_reentered(data->ary);
311
+ return n;
312
+ }
313
+
314
+ static int
315
+ sort_4(VALUE a, VALUE b, void *dummy)
316
+ {
317
+ struct ary_sort_data *data = dummy;
318
+ VALUE retval = sort_reentered(data->ary);
319
+ int n;
320
+
321
+ if (FIXNUM_P(a) && FIXNUM_P(b) && SORT_OPTIMIZABLE(data, Fixnum)) {
322
+ if ((long)a > (long)b) return 1;
323
+ if ((long)a < (long)b) return -1;
324
+ return 0;
325
+ }
326
+ if (STRING_P(a) && STRING_P(b) && SORT_OPTIMIZABLE(data, String)) {
327
+ return rb_str_cmp(a, b);
328
+ }
329
+
330
+ retval = rb_funcall(a, id_cmp, 1, b);
331
+ n = rb_cmpint(retval, a, b);
332
+ sort_reentered(data->ary);
333
+
334
+ return n;
335
+ }
336
+
337
+ void
338
+ set_id_cmp(ID id)
339
+ {
340
+ id_cmp = id;
341
+ }
342
+
343
+ VALUE
344
+ dynamic_sort(VALUE ary, void(*sort_handler)(void*, const size_t, long, long, long, int(*)(const void*, const void*, void*), void*), long start, long l, long r)
345
+ {
346
+ rb_ary_modify(ary);
347
+ assert(!ARY_SHARED_P(ary));
348
+ if (RARRAY_LEN(ary) > 1) {
349
+ VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */
350
+ struct ary_sort_data data;
351
+
352
+ RBASIC(tmp)->klass = 0;
353
+ data.ary = tmp;
354
+ data.opt_methods = 0;
355
+ data.opt_inited = 0;
356
+ sort_handler(RARRAY_PTR(tmp), RARRAY_LEN(tmp), start, l, r,
357
+ rb_block_given_p()?sort_3:sort_4, &data);
358
+
359
+ if (ARY_EMBED_P(tmp)) {
360
+ assert(ARY_EMBED_P(tmp));
361
+ if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */
362
+ rb_ary_unshare(ary);
363
+ }
364
+ FL_SET_EMBED(ary);
365
+ MEMCPY(RARRAY_PTR(ary), ARY_EMBED_PTR(tmp), VALUE, ARY_EMBED_LEN(tmp));
366
+ ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
367
+ }
368
+ else {
369
+ assert(!ARY_EMBED_P(tmp));
370
+ if (ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) {
371
+ assert(!ARY_EMBED_P(ary));
372
+ FL_UNSET_SHARED(ary);
373
+ ARY_SET_CAPA(ary, ARY_CAPA(tmp));
374
+ }
375
+ else {
376
+ assert(!ARY_SHARED_P(tmp));
377
+ if (ARY_EMBED_P(ary)) {
378
+ FL_UNSET_EMBED(ary);
379
+ }
380
+ else if (ARY_SHARED_P(ary)) {
381
+ /* ary might be destructively operated in the given block */
382
+ rb_ary_unshare(ary);
383
+ }
384
+ else {
385
+ xfree(ARY_HEAP_PTR(ary));
386
+ }
387
+ ARY_SET_PTR(ary, RARRAY_PTR(tmp));
388
+ ARY_SET_HEAP_LEN(ary, RARRAY_LEN(tmp));
389
+ ARY_SET_CAPA(ary, ARY_CAPA(tmp));
390
+ }
391
+ /* tmp was lost ownership for the ptr */
392
+ FL_UNSET(tmp, FL_FREEZE);
393
+ FL_SET_EMBED(tmp);
394
+ ARY_SET_EMBED_LEN(tmp, 0);
395
+ FL_SET(tmp, FL_FREEZE);
396
+ }
397
+ /* tmp will be GC'ed. */
398
+ RBASIC(tmp)->klass = rb_cArray;
399
+ }
400
+ return ary;
401
+ }
@@ -0,0 +1,112 @@
1
+ #include "ruby/ruby.h"
2
+
3
+ VALUE sortingModule;
4
+ VALUE sortingClass;
5
+
6
+ void
7
+ insert_sort_impl(VALUE* base, const size_t len, long start, long l, long r,
8
+ register int (*cmp)(const void*, const void*, void*), void *d)
9
+ {
10
+ VALUE obj;
11
+ VALUE previous;
12
+ register size_t i, j;
13
+ if (l == -1) l = 0;
14
+ if (r == -1) r = len - 1;
15
+ if (start == -1) start = l + 1;
16
+ for(i = start; i <=r; i++) {
17
+ obj = base[i];
18
+ j = i;
19
+ while (j > l) {
20
+ previous = base[j-1];
21
+ if((*cmp)(obj, previous, d) < 0) {
22
+ base[j] = previous;
23
+ j--;
24
+ } else break;
25
+ }
26
+ base[j] = obj;
27
+ }
28
+
29
+ }
30
+
31
+ void
32
+ binary_insert_sort_impl(VALUE* ary, const size_t len, long start, long l, long r,
33
+ register int (*cmp)(const void*, const void*, void*), void *d)
34
+ {
35
+ char *base = (char *)ary;
36
+ size_t size = sizeof(VALUE);
37
+ VALUE obj;
38
+ VALUE previous;
39
+ register size_t i, j;
40
+ long low, high, mid, found, length;
41
+ char *dest;
42
+ char *src;
43
+ if (l == -1) l = 0;
44
+ if (r == -1) r = len - 1;
45
+ if (start == -1) start = l + 1;
46
+ for(i = start; i <=r; i++) {
47
+ obj = ary[i];
48
+ low = l;
49
+ high = i - 1;
50
+ found = -1;
51
+ while (low <= high) {
52
+ mid = low + (high-low)/2;
53
+ if ((*cmp)(obj, ary[mid], d) > 0) {
54
+ low = mid + 1;
55
+ } else {
56
+ found = mid;
57
+ high = mid - 1;
58
+ }
59
+ }
60
+ if(found != -1) {
61
+ length = i - found;
62
+ if (length == 1) {
63
+ ary[i] = ary[found];
64
+ } else {
65
+ dest = base + (found+1)*size;
66
+ src = base + found*size;
67
+ memmove(dest, src, size*length);
68
+ }
69
+ ary[found] = obj;
70
+ }
71
+ }
72
+
73
+ }
74
+
75
+ void
76
+ insert_sort_bang(int argc, VALUE *argv, VALUE dummy)
77
+ {
78
+ VALUE ary = Qnil;
79
+ VALUE rb_start = Qnil;
80
+ VALUE rb_l = Qnil;
81
+ VALUE rb_r = Qnil;
82
+ long start = -1, l = -1, r = -1;
83
+ rb_scan_args(argc, argv, "13", &ary, &rb_l, &rb_r, &rb_start);
84
+ if (!NIL_P(rb_start)) start = NUM2LONG(rb_start);
85
+ if (!NIL_P(rb_l)) l = NUM2LONG(rb_l);
86
+ if (!NIL_P(rb_r)) r = NUM2LONG(rb_r);
87
+ dynamic_sort(ary, insert_sort_impl, start, l, r);
88
+ }
89
+
90
+ void
91
+ binary_insert_sort_bang(int argc, VALUE *argv, VALUE dummy)
92
+ {
93
+ VALUE ary = Qnil;
94
+ VALUE rb_start = Qnil;
95
+ VALUE rb_l = Qnil;
96
+ VALUE rb_r = Qnil;
97
+ long start = -1, l = -1, r = -1;
98
+ rb_scan_args(argc, argv, "13", &ary, &rb_l, &rb_r, &rb_start);
99
+ if (!NIL_P(rb_start)) start = NUM2LONG(rb_start);
100
+ if (!NIL_P(rb_l)) l = NUM2LONG(rb_l);
101
+ if (!NIL_P(rb_r)) r = NUM2LONG(rb_r);
102
+ dynamic_sort(ary, binary_insert_sort_impl, start, l, r);
103
+ }
104
+
105
+ void Init_sorting_ext(void) {
106
+ sortingModule = rb_define_module("Sorting");
107
+ sortingClass = rb_define_class_under(sortingModule, "InsertionSort", rb_cObject);
108
+ rb_define_singleton_method(sortingClass, "sort!", insert_sort_bang, -1);
109
+ rb_define_singleton_method(sortingClass, "binary_sort!", binary_insert_sort_bang, -1);
110
+ rb_define_const(sortingClass, "IS_EXT", Qtrue);
111
+ set_id_cmp(rb_intern("<=>"));
112
+ }