sparse_array 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sparse_array.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Sokolov Yura aka funny_falcon
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/ext/extconf.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile("sparse_array")
data/ext/sp_ar.c ADDED
@@ -0,0 +1,661 @@
1
+ #include "ruby/ruby.h"
2
+
3
+ #include <stdio.h>
4
+ #ifdef HAVE_STDLIB_H
5
+ #include <stdlib.h>
6
+ #endif
7
+ #include <string.h>
8
+
9
+ #if SIZEOF_LONG == SIZEOF_VOIDP
10
+ typedef unsigned long st_data_t;
11
+ #elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
12
+ typedef unsigned LONG_LONG st_data_t;
13
+ #else
14
+ # error ---->> sp_ar.c requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<----
15
+ #endif
16
+
17
+ typedef unsigned int spar_index_t;
18
+ #define spar_STOP ST_STOP
19
+ #define spar_CONTINUE ST_CONTINUE
20
+
21
+ #define spar_EMPTY 0
22
+
23
+ typedef struct spar_entry {
24
+ spar_index_t next;
25
+ spar_index_t key;
26
+ st_data_t value;
27
+ } spar_entry;
28
+
29
+ typedef struct spar_table {
30
+ spar_index_t num_bins;
31
+ spar_index_t num_entries;
32
+ spar_index_t free_pos;
33
+ spar_entry *entries;
34
+ } spar_table;
35
+
36
+ #define spar_EMPTY_TABLE {0, 0, 0, 0};
37
+ static void spar_init_table(spar_table *, spar_index_t);
38
+ static spar_table *spar_new_table();
39
+ static int spar_insert(spar_table *, spar_index_t, st_data_t);
40
+ static int spar_lookup(spar_table *, spar_index_t, st_data_t *);
41
+ static int spar_delete(spar_table *, spar_index_t, st_data_t *);
42
+ static void spar_clear(spar_table *);
43
+ static void spar_free_table(spar_table *);
44
+ static size_t spar_memsize(const spar_table *);
45
+ static void spar_copy_to(spar_table*, spar_table*);
46
+ typedef int (*spar_iter_func)(spar_index_t key, st_data_t val, st_data_t arg);
47
+
48
+ #define SPAR_FOREACH_START_I(table, entry) do { \
49
+ spar_table *T##entry = (table); \
50
+ spar_index_t K##entry; \
51
+ for(K##entry = 0; K##entry < T##entry->num_bins; K##entry++) { \
52
+ spar_entry *entry = T##entry->entries + K##entry; \
53
+ if (entry->next != spar_EMPTY) { \
54
+ st_data_t value = entry->value
55
+ #define SPAR_FOREACH_END() } } } while(0)
56
+
57
+ #define SPAR_FOREACH_START(table) SPAR_FOREACH_START_I(table, entry)
58
+
59
+ #define malloc xmalloc
60
+ #define calloc xcalloc
61
+ #define realloc xrealloc
62
+ #define free xfree
63
+
64
+ #define spar_table_alloc() (spar_table*)malloc(sizeof(spar_table))
65
+ #define spar_table_xalloc() (spar_table*)calloc(1, sizeof(spar_table))
66
+ #define spar_table_dealloc(table) free(table)
67
+ #define spar_entry_alloc(n) (spar_entry*)calloc((n), sizeof(spar_entry))
68
+ #define spar_entry_dealloc(entries) free(entries)
69
+
70
+ #define spar_LAST 1
71
+ #define spar_OFFSET 2
72
+
73
+ #define spar_MIN_SIZE 4
74
+
75
+ static void
76
+ spar_init_table(register spar_table *table, spar_index_t num_bins)
77
+ {
78
+ if (num_bins) {
79
+ table->num_entries = 0;
80
+ table->entries = spar_entry_alloc(num_bins);
81
+ table->num_bins = num_bins;
82
+ table->free_pos = num_bins;
83
+ }
84
+ else {
85
+ memset(table, 0, sizeof(spar_table));
86
+ }
87
+ }
88
+
89
+ static spar_table*
90
+ spar_new_table()
91
+ {
92
+ spar_table* table = spar_table_alloc();
93
+ spar_init_table(table, 0);
94
+ return table;
95
+ }
96
+
97
+ static inline spar_index_t
98
+ calc_pos(register spar_table* table, spar_index_t key)
99
+ {
100
+ /* this formula is empirical */
101
+ /* it has no good avalance, but works well in our case */
102
+ key ^= key >> 16;
103
+ key *= 0x445229;
104
+ return (key + (key >> 16)) % table->num_bins;
105
+ }
106
+
107
+ static void
108
+ fix_empty(register spar_table* table)
109
+ {
110
+ while(--table->free_pos &&
111
+ table->entries[table->free_pos-1].next != spar_EMPTY);
112
+ }
113
+
114
+ #define FLOOR_TO_4 ((~((spar_index_t)0)) << 2)
115
+ static spar_index_t
116
+ find_empty(register spar_table* table, register spar_index_t pos)
117
+ {
118
+ spar_index_t new_pos = table->free_pos-1;
119
+ spar_entry *entry;
120
+ pos &= FLOOR_TO_4;
121
+ entry = table->entries+pos;
122
+
123
+ if (entry->next == spar_EMPTY) { new_pos = pos; }
124
+ else if ((++entry)->next == spar_EMPTY) { new_pos = pos + 1; }
125
+ else if ((++entry)->next == spar_EMPTY) { new_pos = pos + 2; }
126
+ else if ((++entry)->next == spar_EMPTY) { new_pos = pos + 3; }
127
+
128
+ if (new_pos+1 == table->free_pos) fix_empty(table);
129
+ return new_pos;
130
+ }
131
+
132
+ static void resize(register spar_table* table);
133
+ static int insert_into_chain(register spar_table*, register spar_index_t, st_data_t, spar_index_t pos);
134
+ static int insert_into_main(register spar_table*, spar_index_t, st_data_t, spar_index_t pos, spar_index_t prev_pos);
135
+
136
+ static int
137
+ spar_insert(register spar_table* table, register spar_index_t key, st_data_t value)
138
+ {
139
+ spar_index_t pos, main_pos;
140
+ register spar_entry *entry;
141
+
142
+ if (table->num_bins == 0) {
143
+ spar_init_table(table, spar_MIN_SIZE);
144
+ }
145
+
146
+ pos = calc_pos(table, key);
147
+ entry = table->entries + pos;
148
+
149
+ if (entry->next == spar_EMPTY) {
150
+ entry->next = spar_LAST;
151
+ entry->key = key;
152
+ entry->value = value;
153
+ table->num_entries++;
154
+ if (pos+1 == table->free_pos) fix_empty(table);
155
+ return 0;
156
+ }
157
+
158
+ if (entry->key == key) {
159
+ entry->value = value;
160
+ return 1;
161
+ }
162
+
163
+ if (table->num_entries + (table->num_entries >> 2) > table->num_bins) {
164
+ resize(table);
165
+ return spar_insert(table, key, value);
166
+ }
167
+
168
+ main_pos = calc_pos(table, entry->key);
169
+ if (main_pos == pos) {
170
+ return insert_into_chain(table, key, value, pos);
171
+ }
172
+ else {
173
+ if (!table->free_pos) {
174
+ resize(table);
175
+ return spar_insert(table, key, value);
176
+ }
177
+ return insert_into_main(table, key, value, pos, main_pos);
178
+ }
179
+ }
180
+
181
+ static int
182
+ insert_into_chain(register spar_table* table, register spar_index_t key, st_data_t value, spar_index_t pos)
183
+ {
184
+ spar_entry *entry = table->entries + pos, *new_entry;
185
+ spar_index_t new_pos;
186
+
187
+ while (entry->next != spar_LAST) {
188
+ pos = entry->next - spar_OFFSET;
189
+ entry = table->entries + pos;
190
+ if (entry->key == key) {
191
+ entry->value = value;
192
+ return 1;
193
+ }
194
+ }
195
+
196
+ if (!table->free_pos) {
197
+ resize(table);
198
+ return spar_insert(table, key, value);
199
+ }
200
+
201
+ new_pos = find_empty(table, pos);
202
+ new_entry = table->entries + new_pos;
203
+ entry->next = new_pos + spar_OFFSET;
204
+
205
+ new_entry->next = spar_LAST;
206
+ new_entry->key = key;
207
+ new_entry->value = value;
208
+ table->num_entries++;
209
+ return 0;
210
+ }
211
+
212
+ static int
213
+ insert_into_main(register spar_table* table, spar_index_t key, st_data_t value, spar_index_t pos, spar_index_t prev_pos)
214
+ {
215
+ spar_entry *entry = table->entries + pos;
216
+ spar_index_t new_pos = find_empty(table, pos);
217
+ spar_entry *new_entry = table->entries + new_pos;
218
+ spar_index_t npos;
219
+
220
+ *new_entry = *entry;
221
+
222
+ while((npos = table->entries[prev_pos].next - spar_OFFSET) != pos) {
223
+ prev_pos = npos;
224
+ }
225
+ table->entries[prev_pos].next = new_pos + spar_OFFSET;
226
+
227
+ entry->next = spar_LAST;
228
+ entry->key = key;
229
+ entry->value = value;
230
+ table->num_entries++;
231
+ return 0;
232
+ }
233
+
234
+ static spar_index_t
235
+ new_size(spar_index_t num_entries)
236
+ {
237
+ spar_index_t msb = num_entries;
238
+ msb |= msb >> 1;
239
+ msb |= msb >> 2;
240
+ msb |= msb >> 4;
241
+ msb |= msb >> 8;
242
+ msb |= msb >> 16;
243
+ msb = ((msb >> 4) + 1) << 3;
244
+ return (num_entries & (msb | (msb >> 1))) + (msb >> 1);
245
+ }
246
+
247
+ static void
248
+ resize(register spar_table *table)
249
+ {
250
+ spar_table tmp_table;
251
+ spar_entry *entry;
252
+ spar_index_t i;
253
+
254
+ if (table->num_entries == 0) {
255
+ spar_entry_dealloc(table->entries);
256
+ memset(table, 0, sizeof(spar_table));
257
+ return;
258
+ }
259
+
260
+ spar_init_table(&tmp_table, new_size(table->num_entries + (table->num_entries >> 2)));
261
+ entry = table->entries;
262
+
263
+ for(i = 0; i < table->num_bins; i++, entry++) {
264
+ if (entry->next != spar_EMPTY) {
265
+ spar_insert(&tmp_table, entry->key, entry->value);
266
+ }
267
+ }
268
+ spar_entry_dealloc(table->entries);
269
+ *table = tmp_table;
270
+ }
271
+
272
+ static int
273
+ spar_lookup(register spar_table *table, register spar_index_t key, st_data_t *value)
274
+ {
275
+ register spar_entry *entry;
276
+
277
+ if (table->num_entries == 0) return 0;
278
+
279
+ entry = table->entries + calc_pos(table, key);
280
+ if (entry->next == spar_EMPTY) return 0;
281
+
282
+ if (entry->key == key) goto found;
283
+ if (entry->next == spar_LAST) return 0;
284
+
285
+ entry = table->entries + (entry->next - spar_OFFSET);
286
+ if (entry->key == key) goto found;
287
+
288
+ while(entry->next != spar_LAST) {
289
+ entry = table->entries + (entry->next - spar_OFFSET);
290
+ if (entry->key == key) goto found;
291
+ }
292
+ return 0;
293
+ found:
294
+ if (value) *value = entry->value;
295
+ return 1;
296
+ }
297
+
298
+ static void
299
+ spar_clear(spar_table *table)
300
+ {
301
+ spar_entry_dealloc(table->entries);
302
+ memset(table, 0, sizeof(spar_table));
303
+ }
304
+
305
+ static void
306
+ spar_free_table(spar_table *table)
307
+ {
308
+ spar_entry_dealloc(table->entries);
309
+ spar_table_dealloc(table);
310
+ }
311
+
312
+ static int
313
+ spar_delete(spar_table *table, spar_index_t key, st_data_t *value)
314
+ {
315
+ spar_index_t pos, prev_pos = ~0;
316
+ spar_entry *entry;
317
+
318
+ if (table->num_entries == 0) goto not_found;
319
+
320
+ pos = calc_pos(table, key);
321
+ entry = table->entries + pos;
322
+
323
+ if (entry->next == spar_EMPTY) goto not_found;
324
+
325
+ do {
326
+ if (entry->key == key) {
327
+ if (value) *value = entry->value;
328
+ if (entry->next != spar_LAST) {
329
+ spar_index_t npos = entry->next - spar_OFFSET;
330
+ *entry = table->entries[npos];
331
+ memset(table->entries + npos, 0, sizeof(spar_entry));
332
+ }
333
+ else {
334
+ memset(table->entries + pos, 0, sizeof(spar_entry));
335
+ if (~prev_pos) {
336
+ table->entries[prev_pos].next = spar_LAST;
337
+ }
338
+ }
339
+ table->num_entries--;
340
+ if (table->num_entries < table->num_bins / 4) {
341
+ resize(table);
342
+ }
343
+ return 1;
344
+ }
345
+ if (entry->next == spar_LAST) break;
346
+ prev_pos = pos;
347
+ pos = entry->next - spar_OFFSET;
348
+ entry = table->entries + pos;
349
+ } while(1);
350
+
351
+ not_found:
352
+ if (value) *value = 0;
353
+ return 0;
354
+ }
355
+
356
+ static size_t
357
+ spar_memsize(const spar_table *table)
358
+ {
359
+ return sizeof(spar_table) + table->num_bins * sizeof(spar_entry);
360
+ }
361
+
362
+ static void
363
+ spar_copy_to(spar_table *from, spar_table *to)
364
+ {
365
+ spar_entry_dealloc(to->entries);
366
+ *to = *from;
367
+ if (to->num_bins) {
368
+ to->entries = spar_entry_alloc(to->num_bins);
369
+ memcpy(to->entries, from->entries, from->num_bins*sizeof(spar_entry));
370
+ }
371
+ }
372
+
373
+ /******** Ruby Sparse Array binding ********/
374
+
375
+ static void
376
+ sparse_array_mark(void *p)
377
+ {
378
+ if (p) {
379
+ spar_table *ar = (spar_table*)p;
380
+ SPAR_FOREACH_START(ar);
381
+ rb_gc_mark((VALUE)value);
382
+ SPAR_FOREACH_END();
383
+ }
384
+ }
385
+
386
+ static void
387
+ sparse_array_delete(void *p)
388
+ {
389
+ if (p) {
390
+ spar_free_table((spar_table*) p);
391
+ }
392
+ }
393
+
394
+ static size_t
395
+ sparse_array_memsize(const void *p)
396
+ {
397
+ if (p) {
398
+ return spar_memsize((const spar_table*) p);
399
+ }
400
+ return 0;
401
+ }
402
+
403
+ static const rb_data_type_t SparseArray_data_type = {
404
+ "SparseArrayC",
405
+ {sparse_array_mark, sparse_array_delete, sparse_array_memsize}
406
+ };
407
+
408
+ #define GetSparseArray(value, pointer) \
409
+ TypedData_Get_Struct((value), spar_table, &SparseArray_data_type, (pointer))
410
+
411
+ static VALUE
412
+ sparse_array_alloc(VALUE klass)
413
+ {
414
+ spar_table* table = spar_new_table();
415
+ return TypedData_Wrap_Struct(klass, &SparseArray_data_type, table);
416
+ }
417
+
418
+ static VALUE
419
+ sparse_array_get(VALUE self, VALUE ri)
420
+ {
421
+ spar_table *table;
422
+ spar_index_t i = NUM2UINT(ri);
423
+ st_data_t res = Qnil;
424
+ GetSparseArray(self, table);
425
+ spar_lookup(table, i, &res);
426
+ return (VALUE)res;
427
+ }
428
+
429
+ static VALUE
430
+ sparse_array_include(VALUE self, VALUE ri)
431
+ {
432
+ spar_table *table;
433
+ spar_index_t i = NUM2UINT(ri);
434
+ st_data_t res = Qnil;
435
+ GetSparseArray(self, table);
436
+ if (spar_lookup(table, i, &res))
437
+ return Qtrue;
438
+ else
439
+ return Qfalse;
440
+ }
441
+
442
+ static VALUE
443
+ sparse_array_fetch(VALUE self, VALUE ri, VALUE def)
444
+ {
445
+ spar_table *table;
446
+ spar_index_t i = NUM2UINT(ri);
447
+ st_data_t res = Qnil;
448
+ GetSparseArray(self, table);
449
+ if (spar_lookup(table, i, &res))
450
+ return (VALUE)res;
451
+ else
452
+ return def;
453
+ }
454
+
455
+ static VALUE
456
+ sparse_array_set(VALUE self, VALUE ri, VALUE val)
457
+ {
458
+ spar_table *table;
459
+ spar_index_t i = NUM2UINT(ri);
460
+ GetSparseArray(self, table);
461
+ spar_insert(table, i, val);
462
+ return val;
463
+ }
464
+
465
+ static VALUE
466
+ sparse_array_del(VALUE self, VALUE ri)
467
+ {
468
+ spar_table *table;
469
+ spar_index_t i = NUM2UINT(ri);
470
+ st_data_t res = Qnil;
471
+ GetSparseArray(self, table);
472
+ if (spar_delete(table, i, &res))
473
+ return (VALUE)res;
474
+ return Qnil;
475
+ }
476
+
477
+ static VALUE
478
+ sparse_array_size(VALUE self)
479
+ {
480
+ spar_table *table;
481
+ GetSparseArray(self, table);
482
+ return UINT2NUM(table->num_entries);
483
+ }
484
+
485
+ static VALUE
486
+ sparse_array_empty_p(VALUE self)
487
+ {
488
+ spar_table *table;
489
+ GetSparseArray(self, table);
490
+ return table->num_entries ? Qfalse : Qtrue;
491
+ }
492
+
493
+ static VALUE
494
+ sparse_array_clear(VALUE self)
495
+ {
496
+ spar_table *table;
497
+ GetSparseArray(self, table);
498
+ spar_clear(table);
499
+ return self;
500
+ }
501
+
502
+ static VALUE
503
+ sparse_array_keys(VALUE self)
504
+ {
505
+ spar_table *table;
506
+ VALUE res;
507
+ GetSparseArray(self, table);
508
+ res = rb_ary_new2(table->num_entries);
509
+ SPAR_FOREACH_START(table);
510
+ (void)value;
511
+ rb_ary_push(res, UINT2NUM(entry->key));
512
+ SPAR_FOREACH_END();
513
+ return res;
514
+ }
515
+
516
+ static VALUE
517
+ sparse_array_values(VALUE self)
518
+ {
519
+ spar_table *table;
520
+ VALUE res;
521
+ GetSparseArray(self, table);
522
+ res = rb_ary_new2(table->num_entries);
523
+ SPAR_FOREACH_START(table);
524
+ rb_ary_push(res, (VALUE)value);
525
+ SPAR_FOREACH_END();
526
+ return res;
527
+ }
528
+
529
+ static VALUE
530
+ sparse_array_each(VALUE self)
531
+ {
532
+ spar_table *table;
533
+ VALUE keys;
534
+ long i, size;
535
+ VALUE *p;
536
+ RETURN_ENUMERATOR(self, 0, 0);
537
+ GetSparseArray(self, table);
538
+ keys = sparse_array_keys(self);
539
+ size = RARRAY_LEN(keys);
540
+ p = RARRAY_PTR(keys);
541
+ for(i=0; i<size; i++) {
542
+ spar_index_t k = NUM2UINT(p[i]);
543
+ st_data_t v = Qnil;
544
+ if (spar_lookup(table, k, &v))
545
+ rb_yield(rb_assoc_new(p[i], (VALUE)v));
546
+ }
547
+ RB_GC_GUARD(keys);
548
+ return self;
549
+ }
550
+
551
+ static VALUE
552
+ sparse_array_each_key(VALUE self)
553
+ {
554
+ spar_table *table;
555
+ VALUE keys;
556
+ long i, size;
557
+ VALUE *p;
558
+ RETURN_ENUMERATOR(self, 0, 0);
559
+ GetSparseArray(self, table);
560
+ keys = sparse_array_keys(self);
561
+ size = RARRAY_LEN(keys);
562
+ p = RARRAY_PTR(keys);
563
+ for(i=0; i<size; i++) {
564
+ spar_index_t k = NUM2UINT(p[i]);
565
+ st_data_t v = Qnil;
566
+ if (spar_lookup(table, k, &v))
567
+ rb_yield(p[i]);
568
+ }
569
+ RB_GC_GUARD(keys);
570
+ return self;
571
+ }
572
+
573
+ static VALUE
574
+ sparse_array_each_value(VALUE self)
575
+ {
576
+ spar_table *table;
577
+ VALUE keys;
578
+ long i, size;
579
+ VALUE *p;
580
+ RETURN_ENUMERATOR(self, 0, 0);
581
+ GetSparseArray(self, table);
582
+ keys = sparse_array_keys(self);
583
+ size = RARRAY_LEN(keys);
584
+ p = RARRAY_PTR(keys);
585
+ for(i=0; i<size; i++) {
586
+ spar_index_t k = NUM2UINT(p[i]);
587
+ st_data_t v = Qnil;
588
+ if (spar_lookup(table, k, &v))
589
+ rb_yield(v);
590
+ }
591
+ RB_GC_GUARD(keys);
592
+ return self;
593
+ }
594
+
595
+ static VALUE
596
+ sparse_array_init_copy(VALUE self, VALUE copy)
597
+ {
598
+ spar_table *table;
599
+ spar_table *copied;
600
+ GetSparseArray(self, table);
601
+ GetSparseArray(copy, copied);
602
+ rb_obj_init_copy(self, copy);
603
+ spar_copy_to(table, copied);
604
+ return copy;
605
+ }
606
+
607
+ static VALUE
608
+ sparse_array_inspect_rec(VALUE self, VALUE dummy, int recur)
609
+ {
610
+ VALUE str, str2;
611
+ spar_table *table;
612
+ GetSparseArray(self, table);
613
+
614
+ if (recur) return rb_usascii_str_new2("<SparseArray ...>");
615
+ str = rb_str_buf_new2("<SparseArray");
616
+ SPAR_FOREACH_START(table);
617
+ rb_str_catf(str, " %u=>", entry->key);
618
+ str2 = rb_inspect(value);
619
+ rb_str_buf_append(str, str2);
620
+ OBJ_INFECT(str, str2);
621
+ SPAR_FOREACH_END();
622
+ rb_str_buf_cat2(str, ">");
623
+ OBJ_INFECT(str, self);
624
+
625
+ return str;
626
+ }
627
+
628
+ static VALUE
629
+ sparse_array_inspect(VALUE self)
630
+ {
631
+ spar_table *table;
632
+ GetSparseArray(self, table);
633
+ if (table->num_entries == 0)
634
+ return rb_usascii_str_new2("<SparseArray>");
635
+ return rb_exec_recursive(sparse_array_inspect_rec, self, 0);
636
+ }
637
+
638
+ void
639
+ Init_sparse_array() {
640
+ VALUE cls_sparse_array = rb_define_class("SparseArray", rb_cObject);
641
+ rb_define_alloc_func(cls_sparse_array, sparse_array_alloc);
642
+ rb_define_method(cls_sparse_array, "[]", sparse_array_get, 1);
643
+ rb_define_method(cls_sparse_array, "fetch", sparse_array_fetch, 2);
644
+ rb_define_method(cls_sparse_array, "[]=", sparse_array_set, 2);
645
+ rb_define_method(cls_sparse_array, "delete", sparse_array_del, 1);
646
+ rb_define_method(cls_sparse_array, "clear", sparse_array_clear, 0);
647
+ rb_define_method(cls_sparse_array, "empty?", sparse_array_empty_p, 0);
648
+ rb_define_method(cls_sparse_array, "size", sparse_array_size, 1);
649
+ rb_define_method(cls_sparse_array, "count", sparse_array_size, 1);
650
+ rb_define_method(cls_sparse_array, "include?", sparse_array_include, 1);
651
+ rb_define_method(cls_sparse_array, "has_key?", sparse_array_include, 1);
652
+ rb_define_method(cls_sparse_array, "keys", sparse_array_keys, 0);
653
+ rb_define_method(cls_sparse_array, "values", sparse_array_values, 0);
654
+ rb_define_method(cls_sparse_array, "each", sparse_array_each, 0);
655
+ rb_define_method(cls_sparse_array, "each_pair", sparse_array_each, 0);
656
+ rb_define_method(cls_sparse_array, "each_key", sparse_array_each_key, 0);
657
+ rb_define_method(cls_sparse_array, "each_value", sparse_array_each_value, 0);
658
+ rb_define_method(cls_sparse_array, "inspect", sparse_array_inspect, 0);
659
+ rb_define_method(cls_sparse_array, "initialize_copy", sparse_array_init_copy, 1);
660
+ rb_include_module(cls_sparse_array, rb_mEnumerable);
661
+ }
@@ -0,0 +1,3 @@
1
+ class SparseArray
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sparse_array/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sparse_array"
8
+ spec.version = SparseArray::VERSION
9
+ spec.authors = ["Sokolov Yura aka funny_falcon"]
10
+ spec.email = ["funny.falcon@gmail.com"]
11
+ spec.description = %q{Sparse Array - map from integers (0..2**32-1) to objects}
12
+ spec.summary = %q{lightweight map from integers to objects}
13
+ spec.homepage = "https://github.com/funny-falcon/ruby_sparse_array"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = %w{ext/extconf.rb ext/sp_ar.c lib/sparse_array/version.rb Gemfile LICENSE.txt sparse_array.gemspec}
17
+ spec.extensions = ["ext/extconf.rb"]
18
+ spec.require_paths = ["lib", "ext"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "rake"
22
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sparse_array
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sokolov Yura aka funny_falcon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ type: :development
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ none: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ none: false
28
+ prerelease: false
29
+ name: bundler
30
+ - !ruby/object:Gem::Dependency
31
+ type: :development
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ none: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ none: false
44
+ prerelease: false
45
+ name: rake
46
+ description: Sparse Array - map from integers (0..2**32-1) to objects
47
+ email:
48
+ - funny.falcon@gmail.com
49
+ executables: []
50
+ extensions:
51
+ - ext/extconf.rb
52
+ extra_rdoc_files: []
53
+ files:
54
+ - ext/extconf.rb
55
+ - ext/sp_ar.c
56
+ - lib/sparse_array/version.rb
57
+ - Gemfile
58
+ - LICENSE.txt
59
+ - sparse_array.gemspec
60
+ homepage: https://github.com/funny-falcon/ruby_sparse_array
61
+ licenses:
62
+ - MIT
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ - ext
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ none: false
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ none: false
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 1.8.25
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: lightweight map from integers to objects
86
+ test_files: []