sparse_array 0.0.1

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.
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: []