source: EcnlProtoTool/trunk/mruby-2.1.1/src/hash.c@ 439

Last change on this file since 439 was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 33.7 KB
Line 
1/*
2** hash.c - Hash class
3**
4** See Copyright Notice in mruby.h
5*/
6
7#include <mruby.h>
8#include <mruby/array.h>
9#include <mruby/class.h>
10#include <mruby/hash.h>
11#include <mruby/string.h>
12#include <mruby/variable.h>
13
14#ifndef MRB_WITHOUT_FLOAT
15/* a function to get hash value of a float number */
16mrb_int mrb_float_id(mrb_float f);
17#endif
18
19#ifndef MRB_HT_INIT_SIZE
20#define MRB_HT_INIT_SIZE 4
21#endif
22#define HT_SEG_INCREASE_RATIO 6 / 5
23
24struct segkv {
25 mrb_value key;
26 mrb_value val;
27};
28
29typedef struct segment {
30 uint16_t size;
31 struct segment *next;
32 struct segkv e[];
33} segment;
34
35typedef struct segindex {
36 size_t size;
37 size_t capa;
38 struct segkv *table[];
39} segindex;
40
41/* hash table structure */
42typedef struct htable {
43 segment *rootseg;
44 segment *lastseg;
45 mrb_int size;
46 uint16_t last_len;
47 segindex *index;
48} htable;
49
50static /* inline */ size_t
51ht_hash_func(mrb_state *mrb, htable *t, mrb_value key)
52{
53 enum mrb_vtype tt = mrb_type(key);
54 mrb_value hv;
55 size_t h;
56 segindex *index = t->index;
57 size_t capa = index ? index->capa : 0;
58
59 switch (tt) {
60 case MRB_TT_STRING:
61 h = mrb_str_hash(mrb, key);
62 break;
63
64 case MRB_TT_TRUE:
65 case MRB_TT_FALSE:
66 case MRB_TT_SYMBOL:
67 case MRB_TT_FIXNUM:
68#ifndef MRB_WITHOUT_FLOAT
69 case MRB_TT_FLOAT:
70#endif
71 h = (size_t)mrb_obj_id(key);
72 break;
73
74 default:
75 hv = mrb_funcall(mrb, key, "hash", 0);
76 h = (size_t)t ^ (size_t)mrb_fixnum(hv);
77 break;
78 }
79 if (index && (index != t->index || capa != index->capa)) {
80 mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified");
81 }
82 return ((h)^((h)<<2)^((h)>>2));
83}
84
85static inline mrb_bool
86ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b)
87{
88 enum mrb_vtype tt = mrb_type(a);
89
90 switch (tt) {
91 case MRB_TT_STRING:
92 return mrb_str_equal(mrb, a, b);
93
94 case MRB_TT_SYMBOL:
95 if (!mrb_symbol_p(b)) return FALSE;
96 return mrb_symbol(a) == mrb_symbol(b);
97
98 case MRB_TT_FIXNUM:
99 switch (mrb_type(b)) {
100 case MRB_TT_FIXNUM:
101 return mrb_fixnum(a) == mrb_fixnum(b);
102#ifndef MRB_WITHOUT_FLOAT
103 case MRB_TT_FLOAT:
104 return (mrb_float)mrb_fixnum(a) == mrb_float(b);
105#endif
106 default:
107 return FALSE;
108 }
109
110#ifndef MRB_WITHOUT_FLOAT
111 case MRB_TT_FLOAT:
112 switch (mrb_type(b)) {
113 case MRB_TT_FIXNUM:
114 return mrb_float(a) == (mrb_float)mrb_fixnum(b);
115 case MRB_TT_FLOAT:
116 return mrb_float(a) == mrb_float(b);
117 default:
118 return FALSE;
119 }
120#endif
121
122 default:
123 {
124 segindex *index = t->index;
125 size_t capa = index ? index->capa : 0;
126 mrb_bool eql = mrb_eql(mrb, a, b);
127 if (index && (index != t->index || capa != index->capa)) {
128 mrb_raise(mrb, E_RUNTIME_ERROR, "hash modified");
129 }
130 return eql;
131 }
132 }
133}
134
135/* Creates the hash table. */
136static htable*
137ht_new(mrb_state *mrb)
138{
139 htable *t;
140
141 t = (htable*)mrb_malloc(mrb, sizeof(htable));
142 t->size = 0;
143 t->rootseg = NULL;
144 t->lastseg = NULL;
145 t->last_len = 0;
146 t->index = NULL;
147
148 return t;
149}
150
151#define power2(v) do { \
152 v--;\
153 v |= v >> 1;\
154 v |= v >> 2;\
155 v |= v >> 4;\
156 v |= v >> 8;\
157 v |= v >> 16;\
158 v++;\
159} while (0)
160
161#ifndef UPPER_BOUND
162#define UPPER_BOUND(x) ((x)>>2|(x)>>1)
163#endif
164
165#define HT_MASK(index) ((index->capa)-1)
166
167/* Build index for the hash table */
168static void
169ht_index(mrb_state *mrb, htable *t)
170{
171 size_t size = (size_t)t->size;
172 size_t mask;
173 segindex *index = t->index;
174 segment *seg;
175 size_t i;
176
177 /* allocate index table */
178 if (index && index->size >= UPPER_BOUND(index->capa)) {
179 size = index->capa+1;
180 }
181 power2(size);
182 if (!index || index->capa < size) {
183 index = (segindex*)mrb_realloc_simple(mrb, index, sizeof(segindex)+sizeof(struct segkv*)*size);
184 if (index == NULL) {
185 mrb_free(mrb, t->index);
186 t->index = NULL;
187 return;
188 }
189 t->index = index;
190 }
191 index->size = t->size;
192 index->capa = size;
193 for (i=0; i<size; i++) {
194 index->table[i] = NULL;
195 }
196
197 /* rebuld index */
198 mask = HT_MASK(index);
199 seg = t->rootseg;
200 while (seg) {
201 for (i=0; i<seg->size; i++) {
202 mrb_value key;
203 size_t k, step = 0;
204
205 if (!seg->next && i >= (size_t)t->last_len) {
206 return;
207 }
208 key = seg->e[i].key;
209 if (mrb_undef_p(key)) continue;
210 k = ht_hash_func(mrb, t, key) & mask;
211 while (index->table[k]) {
212 k = (k+(++step)) & mask;
213 }
214 index->table[k] = &seg->e[i];
215 }
216 seg = seg->next;
217 }
218}
219
220/* Compacts the hash table removing deleted entries. */
221static void
222ht_compact(mrb_state *mrb, htable *t)
223{
224 segment *seg;
225 uint16_t i, i2;
226 segment *seg2 = NULL;
227 mrb_int size = 0;
228
229 if (t == NULL) return;
230 seg = t->rootseg;
231 if (t->index && (size_t)t->size == t->index->size) {
232 ht_index(mrb, t);
233 return;
234 }
235 while (seg) {
236 for (i=0; i<seg->size; i++) {
237 mrb_value k = seg->e[i].key;
238
239 if (!seg->next && i >= t->last_len) {
240 goto exit;
241 }
242 if (mrb_undef_p(k)) { /* found deleted key */
243 if (seg2 == NULL) {
244 seg2 = seg;
245 i2 = i;
246 }
247 }
248 else {
249 size++;
250 if (seg2 != NULL) {
251 seg2->e[i2++] = seg->e[i];
252 if (i2 >= seg2->size) {
253 seg2 = seg2->next;
254 i2 = 0;
255 }
256 }
257 }
258 }
259 seg = seg->next;
260 }
261 exit:
262 /* reached at end */
263 t->size = size;
264 if (seg2) {
265 seg = seg2->next;
266 seg2->next = NULL;
267 t->last_len = i2;
268 t->lastseg = seg2;
269 while (seg) {
270 seg2 = seg->next;
271 mrb_free(mrb, seg);
272 seg = seg2;
273 }
274 }
275 if (t->index) {
276 ht_index(mrb, t);
277 }
278}
279
280static segment*
281segment_alloc(mrb_state *mrb, segment *seg)
282{
283 uint32_t size;
284
285 if (!seg) size = MRB_HT_INIT_SIZE;
286 else {
287 size = seg->size*HT_SEG_INCREASE_RATIO + 1;
288 if (size > UINT16_MAX) size = UINT16_MAX;
289 }
290
291 seg = (segment*)mrb_malloc(mrb, sizeof(segment)+sizeof(struct segkv)*size);
292 seg->size = size;
293 seg->next = NULL;
294
295 return seg;
296}
297
298/* Set the value for the key in the indexed table. */
299static void
300ht_index_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val)
301{
302 segindex *index = t->index;
303 size_t k, sp, step = 0, mask;
304 segment *seg;
305
306 if (index->size >= UPPER_BOUND(index->capa)) {
307 /* need to expand table */
308 ht_compact(mrb, t);
309 index = t->index;
310 }
311 mask = HT_MASK(index);
312 sp = index->capa;
313 k = ht_hash_func(mrb, t, key) & mask;
314 while (index->table[k]) {
315 mrb_value key2 = index->table[k]->key;
316 if (mrb_undef_p(key2)) {
317 if (sp == index->capa) sp = k;
318 }
319 else if (ht_hash_equal(mrb, t, key, key2)) {
320 index->table[k]->val = val;
321 return;
322 }
323 k = (k+(++step)) & mask;
324 }
325 if (sp < index->capa) {
326 k = sp;
327 }
328
329 /* put the value at the last */
330 seg = t->lastseg;
331 if (t->last_len < seg->size) {
332 index->table[k] = &seg->e[t->last_len++];
333 }
334 else { /* append a new segment */
335 seg->next = segment_alloc(mrb, seg);
336 seg = seg->next;
337 seg->next = NULL;
338 t->lastseg = seg;
339 t->last_len = 1;
340 index->table[k] = &seg->e[0];
341 }
342 index->table[k]->key = key;
343 index->table[k]->val = val;
344 index->size++;
345 t->size++;
346}
347
348/* Set the value for the key in the hash table. */
349static void
350ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val)
351{
352 segment *seg;
353 mrb_int i, deleted = 0;
354
355 if (t == NULL) return;
356 if (t->index) {
357 ht_index_put(mrb, t, key, val);
358 return;
359 }
360 seg = t->rootseg;
361 while (seg) {
362 for (i=0; i<seg->size; i++) {
363 mrb_value k = seg->e[i].key;
364 /* Found room in last segment after last_len */
365 if (!seg->next && i >= t->last_len) {
366 seg->e[i].key = key;
367 seg->e[i].val = val;
368 t->last_len = i+1;
369 t->size++;
370 return;
371 }
372 if (mrb_undef_p(k)) {
373 deleted++;
374 continue;
375 }
376 if (ht_hash_equal(mrb, t, k, key)) {
377 seg->e[i].val = val;
378 return;
379 }
380 }
381 seg = seg->next;
382 }
383 /* Not found */
384
385 /* Compact if last segment has room */
386 if (deleted > 0 && deleted > MRB_HT_INIT_SIZE) {
387 ht_compact(mrb, t);
388 }
389 t->size++;
390
391 /* check if thre's room after compaction */
392 if (t->lastseg && t->last_len < t->lastseg->size) {
393 seg = t->lastseg;
394 i = t->last_len;
395 }
396 else {
397 /* append new segment */
398 seg = segment_alloc(mrb, t->lastseg);
399 i = 0;
400 if (t->rootseg == NULL) {
401 t->rootseg = seg;
402 }
403 else {
404 t->lastseg->next = seg;
405 }
406 t->lastseg = seg;
407 }
408 seg->e[i].key = key;
409 seg->e[i].val = val;
410 t->last_len = i+1;
411 if (t->index == NULL && t->size > MRB_HT_INIT_SIZE*4) {
412 ht_index(mrb, t);
413 }
414}
415
416/* Get a value for a key from the indexed table. */
417static mrb_bool
418ht_index_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp)
419{
420 segindex *index = t->index;
421 size_t mask = HT_MASK(index);
422 size_t k = ht_hash_func(mrb, t, key) & mask;
423 size_t step = 0;
424
425 while (index->table[k]) {
426 mrb_value key2 = index->table[k]->key;
427 if (!mrb_undef_p(key2) && ht_hash_equal(mrb, t, key, key2)) {
428 if (vp) *vp = index->table[k]->val;
429 return TRUE;
430 }
431 k = (k+(++step)) & mask;
432 }
433 return FALSE;
434}
435
436/* Get a value for a key from the hash table. */
437static mrb_bool
438ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp)
439{
440 segment *seg;
441 mrb_int i;
442
443 if (t == NULL) return FALSE;
444 if (t->index) {
445 return ht_index_get(mrb, t, key, vp);
446 }
447
448 seg = t->rootseg;
449 while (seg) {
450 for (i=0; i<seg->size; i++) {
451 mrb_value k = seg->e[i].key;
452
453 if (!seg->next && i >= t->last_len) {
454 return FALSE;
455 }
456 if (mrb_undef_p(k)) continue;
457 if (ht_hash_equal(mrb, t, k, key)) {
458 if (vp) *vp = seg->e[i].val;
459 return TRUE;
460 }
461 }
462 seg = seg->next;
463 }
464 return FALSE;
465}
466
467/* Deletes the value for the symbol from the hash table. */
468/* Deletion is done by overwriting keys by `undef`. */
469static mrb_bool
470ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp)
471{
472 segment *seg;
473 mrb_int i;
474
475 if (t == NULL) return FALSE;
476 seg = t->rootseg;
477 while (seg) {
478 for (i=0; i<seg->size; i++) {
479 mrb_value key2;
480
481 if (!seg->next && i >= t->last_len) {
482 /* not found */
483 return FALSE;
484 }
485 key2 = seg->e[i].key;
486 if (!mrb_undef_p(key2) && ht_hash_equal(mrb, t, key, key2)) {
487 if (vp) *vp = seg->e[i].val;
488 seg->e[i].key = mrb_undef_value();
489 t->size--;
490 return TRUE;
491 }
492 }
493 seg = seg->next;
494 }
495 return FALSE;
496}
497
498/* Iterates over the hash table. */
499static void
500ht_foreach(mrb_state *mrb, htable *t, mrb_hash_foreach_func *func, void *p)
501{
502 segment *seg;
503 mrb_int i;
504
505 if (t == NULL) return;
506 seg = t->rootseg;
507 while (seg) {
508 for (i=0; i<seg->size; i++) {
509 /* no value in last segment after last_len */
510 if (!seg->next && i >= t->last_len) {
511 return;
512 }
513 if (mrb_undef_p(seg->e[i].key)) continue;
514 if ((*func)(mrb, seg->e[i].key, seg->e[i].val, p) != 0)
515 return;
516 }
517 seg = seg->next;
518 }
519}
520
521/* Iterates over the hash table. */
522MRB_API void
523mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p)
524{
525 ht_foreach(mrb, hash->ht, func, p);
526}
527
528/* Copy the hash table. */
529static htable*
530ht_copy(mrb_state *mrb, htable *t)
531{
532 segment *seg;
533 htable *t2;
534 mrb_int i;
535
536 seg = t->rootseg;
537 t2 = ht_new(mrb);
538 if (t->size == 0) return t2;
539
540 while (seg) {
541 for (i=0; i<seg->size; i++) {
542 mrb_value key = seg->e[i].key;
543 mrb_value val = seg->e[i].val;
544
545 if ((seg->next == NULL) && (i >= t->last_len)) {
546 return t2;
547 }
548 if (mrb_undef_p(key)) continue; /* skip deleted key */
549 ht_put(mrb, t2, key, val);
550 }
551 seg = seg->next;
552 }
553 return t2;
554}
555
556/* Free memory of the hash table. */
557static void
558ht_free(mrb_state *mrb, htable *t)
559{
560 segment *seg;
561
562 if (!t) return;
563 seg = t->rootseg;
564 while (seg) {
565 segment *p = seg;
566 seg = seg->next;
567 mrb_free(mrb, p);
568 }
569 if (t->index) mrb_free(mrb, t->index);
570 mrb_free(mrb, t);
571}
572
573static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
574
575static inline mrb_value
576ht_key(mrb_state *mrb, mrb_value key)
577{
578 if (mrb_string_p(key) && !mrb_frozen_p(mrb_str_ptr(key))) {
579 key = mrb_str_dup(mrb, key);
580 MRB_SET_FROZEN_FLAG(mrb_str_ptr(key));
581 }
582 return key;
583}
584
585#define KEY(key) ht_key(mrb, key)
586
587static int
588hash_mark_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
589{
590 mrb_gc_mark_value(mrb, key);
591 mrb_gc_mark_value(mrb, val);
592 return 0;
593}
594
595void
596mrb_gc_mark_hash(mrb_state *mrb, struct RHash *hash)
597{
598 ht_foreach(mrb, hash->ht, hash_mark_i, NULL);
599}
600
601size_t
602mrb_gc_mark_hash_size(mrb_state *mrb, struct RHash *hash)
603{
604 if (!hash->ht) return 0;
605 return hash->ht->size*2;
606}
607
608void
609mrb_gc_free_hash(mrb_state *mrb, struct RHash *hash)
610{
611 ht_free(mrb, hash->ht);
612}
613
614MRB_API mrb_value
615mrb_hash_new(mrb_state *mrb)
616{
617 struct RHash *h;
618
619 h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
620 h->ht = 0;
621 h->iv = 0;
622 return mrb_obj_value(h);
623}
624
625MRB_API mrb_value
626mrb_hash_new_capa(mrb_state *mrb, mrb_int capa)
627{
628 struct RHash *h;
629
630 h = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
631 /* preallocate hash table */
632 h->ht = ht_new(mrb);
633 /* capacity ignored */
634 h->iv = 0;
635 return mrb_obj_value(h);
636}
637
638static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash);
639static mrb_value hash_default(mrb_state *mrb, mrb_value hash, mrb_value key);
640
641static mrb_value
642mrb_hash_init_copy(mrb_state *mrb, mrb_value self)
643{
644 mrb_value orig;
645 struct RHash* copy;
646 htable *orig_h;
647 mrb_value ifnone, vret;
648
649 mrb_get_args(mrb, "o", &orig);
650 if (mrb_obj_equal(mrb, self, orig)) return self;
651 if ((mrb_type(self) != mrb_type(orig)) || (mrb_obj_class(mrb, self) != mrb_obj_class(mrb, orig))) {
652 mrb_raise(mrb, E_TYPE_ERROR, "initialize_copy should take same class object");
653 }
654
655 orig_h = RHASH_TBL(self);
656 copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
657 copy->ht = ht_copy(mrb, orig_h);
658
659 if (MRB_RHASH_DEFAULT_P(self)) {
660 copy->flags |= MRB_HASH_DEFAULT;
661 }
662 if (MRB_RHASH_PROCDEFAULT_P(self)) {
663 copy->flags |= MRB_HASH_PROC_DEFAULT;
664 }
665 vret = mrb_obj_value(copy);
666 ifnone = RHASH_IFNONE(self);
667 if (!mrb_nil_p(ifnone)) {
668 mrb_iv_set(mrb, vret, mrb_intern_lit(mrb, "ifnone"), ifnone);
669 }
670 return vret;
671}
672
673static int
674check_kdict_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data)
675{
676 if (!mrb_symbol_p(key)) {
677 mrb_raise(mrb, E_ARGUMENT_ERROR, "keyword argument hash with non symbol keys");
678 }
679 return 0;
680}
681
682void
683mrb_hash_check_kdict(mrb_state *mrb, mrb_value self)
684{
685 htable *t;
686
687 t = RHASH_TBL(self);
688 if (!t || t->size == 0) return;
689 ht_foreach(mrb, t, check_kdict_i, NULL);
690}
691
692MRB_API mrb_value
693mrb_hash_dup(mrb_state *mrb, mrb_value self)
694{
695 struct RHash* copy;
696 htable *orig_h;
697
698 orig_h = RHASH_TBL(self);
699 copy = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
700 copy->ht = orig_h ? ht_copy(mrb, orig_h) : NULL;
701 return mrb_obj_value(copy);
702}
703
704MRB_API mrb_value
705mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
706{
707 mrb_value val;
708 mrb_sym mid;
709
710 if (ht_get(mrb, RHASH_TBL(hash), key, &val)) {
711 return val;
712 }
713
714 mid = mrb_intern_lit(mrb, "default");
715 if (mrb_func_basic_p(mrb, hash, mid, mrb_hash_default)) {
716 return hash_default(mrb, hash, key);
717 }
718 /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */
719 return mrb_funcall_argv(mrb, hash, mid, 1, &key);
720}
721
722MRB_API mrb_value
723mrb_hash_fetch(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value def)
724{
725 mrb_value val;
726
727 if (ht_get(mrb, RHASH_TBL(hash), key, &val)) {
728 return val;
729 }
730 /* not found */
731 return def;
732}
733
734MRB_API void
735mrb_hash_set(mrb_state *mrb, mrb_value hash, mrb_value key, mrb_value val)
736{
737 mrb_hash_modify(mrb, hash);
738
739 key = KEY(key);
740 ht_put(mrb, RHASH_TBL(hash), key, val);
741 mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), key);
742 mrb_field_write_barrier_value(mrb, (struct RBasic*)RHASH(hash), val);
743 return;
744}
745
746static void
747mrb_hash_modify(mrb_state *mrb, mrb_value hash)
748{
749 mrb_check_frozen(mrb, mrb_hash_ptr(hash));
750 if (!RHASH_TBL(hash)) {
751 RHASH_TBL(hash) = ht_new(mrb);
752 }
753}
754
755/* 15.2.13.4.16 */
756/*
757 * call-seq:
758 * Hash.new -> new_hash
759 * Hash.new(obj) -> new_hash
760 * Hash.new {|hash, key| block } -> new_hash
761 *
762 * Returns a new, empty hash. If this hash is subsequently accessed by
763 * a key that doesn't correspond to a hash entry, the value returned
764 * depends on the style of <code>new</code> used to create the hash. In
765 * the first form, the access returns <code>nil</code>. If
766 * <i>obj</i> is specified, this single object will be used for
767 * all <em>default values</em>. If a block is specified, it will be
768 * called with the hash object and the key, and should return the
769 * default value. It is the block's responsibility to store the value
770 * in the hash if required.
771 *
772 * h = Hash.new("Go Fish")
773 * h["a"] = 100
774 * h["b"] = 200
775 * h["a"] #=> 100
776 * h["c"] #=> "Go Fish"
777 * # The following alters the single default object
778 * h["c"].upcase! #=> "GO FISH"
779 * h["d"] #=> "GO FISH"
780 * h.keys #=> ["a", "b"]
781 *
782 * # While this creates a new default object each time
783 * h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
784 * h["c"] #=> "Go Fish: c"
785 * h["c"].upcase! #=> "GO FISH: C"
786 * h["d"] #=> "Go Fish: d"
787 * h.keys #=> ["c", "d"]
788 *
789 */
790
791static mrb_value
792mrb_hash_init(mrb_state *mrb, mrb_value hash)
793{
794 mrb_value block, ifnone;
795 mrb_bool ifnone_p;
796
797 ifnone = mrb_nil_value();
798 mrb_get_args(mrb, "&|o?", &block, &ifnone, &ifnone_p);
799 mrb_hash_modify(mrb, hash);
800 if (!mrb_nil_p(block)) {
801 if (ifnone_p) {
802 mrb_argnum_error(mrb, 1, 0, 0);
803 }
804 RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT;
805 ifnone = block;
806 }
807 if (!mrb_nil_p(ifnone)) {
808 RHASH(hash)->flags |= MRB_HASH_DEFAULT;
809 mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
810 }
811 return hash;
812}
813
814/* 15.2.13.4.2 */
815/*
816 * call-seq:
817 * hsh[key] -> value
818 *
819 * Element Reference---Retrieves the <i>value</i> object corresponding
820 * to the <i>key</i> object. If not found, returns the default value (see
821 * <code>Hash::new</code> for details).
822 *
823 * h = { "a" => 100, "b" => 200 }
824 * h["a"] #=> 100
825 * h["c"] #=> nil
826 *
827 */
828static mrb_value
829mrb_hash_aget(mrb_state *mrb, mrb_value self)
830{
831 mrb_value key;
832
833 mrb_get_args(mrb, "o", &key);
834 return mrb_hash_get(mrb, self, key);
835}
836
837static mrb_value
838hash_default(mrb_state *mrb, mrb_value hash, mrb_value key)
839{
840 if (MRB_RHASH_DEFAULT_P(hash)) {
841 if (MRB_RHASH_PROCDEFAULT_P(hash)) {
842 return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
843 }
844 else {
845 return RHASH_IFNONE(hash);
846 }
847 }
848 return mrb_nil_value();
849}
850
851/* 15.2.13.4.5 */
852/*
853 * call-seq:
854 * hsh.default(key=nil) -> obj
855 *
856 * Returns the default value, the value that would be returned by
857 * <i>hsh</i>[<i>key</i>] if <i>key</i> did not exist in <i>hsh</i>.
858 * See also <code>Hash::new</code> and <code>Hash#default=</code>.
859 *
860 * h = Hash.new #=> {}
861 * h.default #=> nil
862 * h.default(2) #=> nil
863 *
864 * h = Hash.new("cat") #=> {}
865 * h.default #=> "cat"
866 * h.default(2) #=> "cat"
867 *
868 * h = Hash.new {|h,k| h[k] = k.to_i*10} #=> {}
869 * h.default #=> nil
870 * h.default(2) #=> 20
871 */
872
873static mrb_value
874mrb_hash_default(mrb_state *mrb, mrb_value hash)
875{
876 mrb_value key;
877 mrb_bool given;
878
879 mrb_get_args(mrb, "|o?", &key, &given);
880 if (MRB_RHASH_DEFAULT_P(hash)) {
881 if (MRB_RHASH_PROCDEFAULT_P(hash)) {
882 if (!given) return mrb_nil_value();
883 return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
884 }
885 else {
886 return RHASH_IFNONE(hash);
887 }
888 }
889 return mrb_nil_value();
890}
891
892/* 15.2.13.4.6 */
893/*
894 * call-seq:
895 * hsh.default = obj -> obj
896 *
897 * Sets the default value, the value returned for a key that does not
898 * exist in the hash. It is not possible to set the default to a
899 * <code>Proc</code> that will be executed on each key lookup.
900 *
901 * h = { "a" => 100, "b" => 200 }
902 * h.default = "Go fish"
903 * h["a"] #=> 100
904 * h["z"] #=> "Go fish"
905 * # This doesn't do what you might hope...
906 * h.default = proc do |hash, key|
907 * hash[key] = key + key
908 * end
909 * h[2] #=> #<Proc:0x401b3948@-:6>
910 * h["cat"] #=> #<Proc:0x401b3948@-:6>
911 */
912
913static mrb_value
914mrb_hash_set_default(mrb_state *mrb, mrb_value hash)
915{
916 mrb_value ifnone;
917
918 mrb_get_args(mrb, "o", &ifnone);
919 mrb_hash_modify(mrb, hash);
920 mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
921 RHASH(hash)->flags &= ~MRB_HASH_PROC_DEFAULT;
922 if (!mrb_nil_p(ifnone)) {
923 RHASH(hash)->flags |= MRB_HASH_DEFAULT;
924 }
925 else {
926 RHASH(hash)->flags &= ~MRB_HASH_DEFAULT;
927 }
928 return ifnone;
929}
930
931/* 15.2.13.4.7 */
932/*
933 * call-seq:
934 * hsh.default_proc -> anObject
935 *
936 * If <code>Hash::new</code> was invoked with a block, return that
937 * block, otherwise return <code>nil</code>.
938 *
939 * h = Hash.new {|h,k| h[k] = k*k } #=> {}
940 * p = h.default_proc #=> #<Proc:0x401b3d08@-:1>
941 * a = [] #=> []
942 * p.call(a, 2)
943 * a #=> [nil, nil, 4]
944 */
945
946
947static mrb_value
948mrb_hash_default_proc(mrb_state *mrb, mrb_value hash)
949{
950 if (MRB_RHASH_PROCDEFAULT_P(hash)) {
951 return RHASH_PROCDEFAULT(hash);
952 }
953 return mrb_nil_value();
954}
955
956/*
957 * call-seq:
958 * hsh.default_proc = proc_obj -> proc_obj
959 *
960 * Sets the default proc to be executed on each key lookup.
961 *
962 * h.default_proc = proc do |hash, key|
963 * hash[key] = key + key
964 * end
965 * h[2] #=> 4
966 * h["cat"] #=> "catcat"
967 */
968
969static mrb_value
970mrb_hash_set_default_proc(mrb_state *mrb, mrb_value hash)
971{
972 mrb_value ifnone;
973
974 mrb_get_args(mrb, "o", &ifnone);
975 mrb_hash_modify(mrb, hash);
976 mrb_iv_set(mrb, hash, mrb_intern_lit(mrb, "ifnone"), ifnone);
977 if (!mrb_nil_p(ifnone)) {
978 RHASH(hash)->flags |= MRB_HASH_PROC_DEFAULT;
979 RHASH(hash)->flags |= MRB_HASH_DEFAULT;
980 }
981 else {
982 RHASH(hash)->flags &= ~MRB_HASH_DEFAULT;
983 RHASH(hash)->flags &= ~MRB_HASH_PROC_DEFAULT;
984 }
985
986 return ifnone;
987}
988
989MRB_API mrb_value
990mrb_hash_delete_key(mrb_state *mrb, mrb_value hash, mrb_value key)
991{
992 htable *t = RHASH_TBL(hash);
993 mrb_value del_val;
994
995 if (ht_del(mrb, t, key, &del_val)) {
996 return del_val;
997 }
998
999 /* not found */
1000 return mrb_nil_value();
1001}
1002
1003static mrb_value
1004mrb_hash_delete(mrb_state *mrb, mrb_value self)
1005{
1006 mrb_value key;
1007
1008 mrb_get_args(mrb, "o", &key);
1009 mrb_hash_modify(mrb, self);
1010 return mrb_hash_delete_key(mrb, self, key);
1011}
1012
1013/* find first element in the hash table, and remove it. */
1014static void
1015ht_shift(mrb_state *mrb, htable *t, mrb_value *kp, mrb_value *vp)
1016{
1017 segment *seg = t->rootseg;
1018 mrb_int i;
1019
1020 while (seg) {
1021 for (i=0; i<seg->size; i++) {
1022 mrb_value key;
1023
1024 if (!seg->next && i >= t->last_len) {
1025 return;
1026 }
1027 key = seg->e[i].key;
1028 if (mrb_undef_p(key)) continue;
1029 *kp = key;
1030 *vp = seg->e[i].val;
1031 /* delete element */
1032 seg->e[i].key = mrb_undef_value();
1033 t->size--;
1034 return;
1035 }
1036 seg = seg->next;
1037 }
1038}
1039
1040/* 15.2.13.4.24 */
1041/*
1042 * call-seq:
1043 * hsh.shift -> anArray or obj
1044 *
1045 * Removes a key-value pair from <i>hsh</i> and returns it as the
1046 * two-item array <code>[</code> <i>key, value</i> <code>]</code>, or
1047 * the hash's default value if the hash is empty.
1048 *
1049 * h = { 1 => "a", 2 => "b", 3 => "c" }
1050 * h.shift #=> [1, "a"]
1051 * h #=> {2=>"b", 3=>"c"}
1052 */
1053
1054static mrb_value
1055mrb_hash_shift(mrb_state *mrb, mrb_value hash)
1056{
1057 htable *t = RHASH_TBL(hash);
1058
1059 mrb_hash_modify(mrb, hash);
1060 if (t && t->size > 0) {
1061 mrb_value del_key, del_val;
1062
1063 ht_shift(mrb, t, &del_key, &del_val);
1064 mrb_gc_protect(mrb, del_key);
1065 mrb_gc_protect(mrb, del_val);
1066 return mrb_assoc_new(mrb, del_key, del_val);
1067 }
1068
1069 if (MRB_RHASH_DEFAULT_P(hash)) {
1070 if (MRB_RHASH_PROCDEFAULT_P(hash)) {
1071 return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, mrb_nil_value());
1072 }
1073 else {
1074 return RHASH_IFNONE(hash);
1075 }
1076 }
1077 return mrb_nil_value();
1078}
1079
1080/* 15.2.13.4.4 */
1081/*
1082 * call-seq:
1083 * hsh.clear -> hsh
1084 *
1085 * Removes all key-value pairs from `hsh`.
1086 *
1087 * h = { "a" => 100, "b" => 200 } #=> {"a"=>100, "b"=>200}
1088 * h.clear #=> {}
1089 *
1090 */
1091
1092MRB_API mrb_value
1093mrb_hash_clear(mrb_state *mrb, mrb_value hash)
1094{
1095 htable *t = RHASH_TBL(hash);
1096
1097 mrb_hash_modify(mrb, hash);
1098 if (t) {
1099 ht_free(mrb, t);
1100 RHASH_TBL(hash) = NULL;
1101 }
1102 return hash;
1103}
1104
1105/* 15.2.13.4.3 */
1106/* 15.2.13.4.26 */
1107/*
1108 * call-seq:
1109 * hsh[key] = value -> value
1110 * hsh.store(key, value) -> value
1111 *
1112 * Element Assignment---Associates the value given by
1113 * <i>value</i> with the key given by <i>key</i>.
1114 * <i>key</i> should not have its value changed while it is in
1115 * use as a key (a <code>String</code> passed as a key will be
1116 * duplicated and frozen).
1117 *
1118 * h = { "a" => 100, "b" => 200 }
1119 * h["a"] = 9
1120 * h["c"] = 4
1121 * h #=> {"a"=>9, "b"=>200, "c"=>4}
1122 *
1123 */
1124static mrb_value
1125mrb_hash_aset(mrb_state *mrb, mrb_value self)
1126{
1127 mrb_value key, val;
1128
1129 mrb_get_args(mrb, "oo", &key, &val);
1130 mrb_hash_set(mrb, self, key, val);
1131 return val;
1132}
1133
1134MRB_API mrb_int
1135mrb_hash_size(mrb_state *mrb, mrb_value hash)
1136{
1137 htable *t = RHASH_TBL(hash);
1138
1139 if (!t) return 0;
1140 return t->size;
1141}
1142
1143/* 15.2.13.4.20 */
1144/* 15.2.13.4.25 */
1145/*
1146 * call-seq:
1147 * hsh.length -> fixnum
1148 * hsh.size -> fixnum
1149 *
1150 * Returns the number of key-value pairs in the hash.
1151 *
1152 * h = { "d" => 100, "a" => 200, "v" => 300, "e" => 400 }
1153 * h.length #=> 4
1154 * h.delete("a") #=> 200
1155 * h.length #=> 3
1156 */
1157static mrb_value
1158mrb_hash_size_m(mrb_state *mrb, mrb_value self)
1159{
1160 mrb_int size = mrb_hash_size(mrb, self);
1161 return mrb_fixnum_value(size);
1162}
1163
1164MRB_API mrb_bool
1165mrb_hash_empty_p(mrb_state *mrb, mrb_value self)
1166{
1167 htable *t = RHASH_TBL(self);
1168
1169 if (!t) return TRUE;
1170 return t->size == 0;
1171}
1172
1173/* 15.2.13.4.12 */
1174/*
1175 * call-seq:
1176 * hsh.empty? -> true or false
1177 *
1178 * Returns <code>true</code> if <i>hsh</i> contains no key-value pairs.
1179 *
1180 * {}.empty? #=> true
1181 *
1182 */
1183static mrb_value
1184mrb_hash_empty_m(mrb_state *mrb, mrb_value self)
1185{
1186 return mrb_bool_value(mrb_hash_empty_p(mrb, self));
1187}
1188
1189static int
1190hash_keys_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
1191{
1192 mrb_ary_push(mrb, *(mrb_value*)p, key);
1193 return 0;
1194}
1195
1196/* 15.2.13.4.19 */
1197/*
1198 * call-seq:
1199 * hsh.keys -> array
1200 *
1201 * Returns a new array populated with the keys from this hash. See also
1202 * <code>Hash#values</code>.
1203 *
1204 * h = { "a" => 100, "b" => 200, "c" => 300, "d" => 400 }
1205 * h.keys #=> ["a", "b", "c", "d"]
1206 *
1207 */
1208
1209MRB_API mrb_value
1210mrb_hash_keys(mrb_state *mrb, mrb_value hash)
1211{
1212 htable *t = RHASH_TBL(hash);
1213 mrb_int size;
1214 mrb_value ary;
1215
1216 if (!t || (size = t->size) == 0)
1217 return mrb_ary_new(mrb);
1218 ary = mrb_ary_new_capa(mrb, size);
1219 ht_foreach(mrb, t, hash_keys_i, (void*)&ary);
1220 return ary;
1221}
1222
1223static int
1224hash_vals_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
1225{
1226 mrb_ary_push(mrb, *(mrb_value*)p, val);
1227 return 0;
1228}
1229
1230/* 15.2.13.4.28 */
1231/*
1232 * call-seq:
1233 * hsh.values -> array
1234 *
1235 * Returns a new array populated with the values from <i>hsh</i>. See
1236 * also <code>Hash#keys</code>.
1237 *
1238 * h = { "a" => 100, "b" => 200, "c" => 300 }
1239 * h.values #=> [100, 200, 300]
1240 *
1241 */
1242
1243MRB_API mrb_value
1244mrb_hash_values(mrb_state *mrb, mrb_value hash)
1245{
1246 htable *t = RHASH_TBL(hash);
1247 mrb_int size;
1248 mrb_value ary;
1249
1250 if (!t || (size = t->size) == 0)
1251 return mrb_ary_new(mrb);
1252 ary = mrb_ary_new_capa(mrb, size);
1253 ht_foreach(mrb, t, hash_vals_i, (void*)&ary);
1254 return ary;
1255}
1256
1257/* 15.2.13.4.13 */
1258/* 15.2.13.4.15 */
1259/* 15.2.13.4.18 */
1260/* 15.2.13.4.21 */
1261/*
1262 * call-seq:
1263 * hsh.has_key?(key) -> true or false
1264 * hsh.include?(key) -> true or false
1265 * hsh.key?(key) -> true or false
1266 * hsh.member?(key) -> true or false
1267 *
1268 * Returns <code>true</code> if the given key is present in <i>hsh</i>.
1269 *
1270 * h = { "a" => 100, "b" => 200 }
1271 * h.has_key?("a") #=> true
1272 * h.has_key?("z") #=> false
1273 *
1274 */
1275
1276MRB_API mrb_bool
1277mrb_hash_key_p(mrb_state *mrb, mrb_value hash, mrb_value key)
1278{
1279 htable *t;
1280
1281 t = RHASH_TBL(hash);
1282 if (ht_get(mrb, t, key, NULL)) {
1283 return TRUE;
1284 }
1285 return FALSE;
1286}
1287
1288static mrb_value
1289mrb_hash_has_key(mrb_state *mrb, mrb_value hash)
1290{
1291 mrb_value key;
1292 mrb_bool key_p;
1293
1294 mrb_get_args(mrb, "o", &key);
1295 key_p = mrb_hash_key_p(mrb, hash, key);
1296 return mrb_bool_value(key_p);
1297}
1298
1299struct has_v_arg {
1300 mrb_bool found;
1301 mrb_value val;
1302};
1303
1304static int
1305hash_has_value_i(mrb_state *mrb, mrb_value key, mrb_value val, void *p)
1306{
1307 struct has_v_arg *arg = (struct has_v_arg*)p;
1308
1309 if (mrb_equal(mrb, arg->val, val)) {
1310 arg->found = TRUE;
1311 return 1;
1312 }
1313 return 0;
1314}
1315
1316/* 15.2.13.4.14 */
1317/* 15.2.13.4.27 */
1318/*
1319 * call-seq:
1320 * hsh.has_value?(value) -> true or false
1321 * hsh.value?(value) -> true or false
1322 *
1323 * Returns <code>true</code> if the given value is present for some key
1324 * in <i>hsh</i>.
1325 *
1326 * h = { "a" => 100, "b" => 200 }
1327 * h.has_value?(100) #=> true
1328 * h.has_value?(999) #=> false
1329 */
1330
1331static mrb_value
1332mrb_hash_has_value(mrb_state *mrb, mrb_value hash)
1333{
1334 mrb_value val;
1335 struct has_v_arg arg;
1336
1337 mrb_get_args(mrb, "o", &val);
1338 arg.found = FALSE;
1339 arg.val = val;
1340 ht_foreach(mrb, RHASH_TBL(hash), hash_has_value_i, &arg);
1341 return mrb_bool_value(arg.found);
1342}
1343
1344static int
1345merge_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data)
1346{
1347 htable *h1 = (htable*)data;
1348
1349 ht_put(mrb, h1, key, val);
1350 return 0;
1351}
1352
1353MRB_API void
1354mrb_hash_merge(mrb_state *mrb, mrb_value hash1, mrb_value hash2)
1355{
1356 htable *h1, *h2;
1357
1358 mrb_hash_modify(mrb, hash1);
1359 hash2 = mrb_ensure_hash_type(mrb, hash2);
1360 h1 = RHASH_TBL(hash1);
1361 h2 = RHASH_TBL(hash2);
1362
1363 if (!h2) return;
1364 if (!h1) {
1365 RHASH_TBL(hash1) = ht_copy(mrb, h2);
1366 return;
1367 }
1368 ht_foreach(mrb, h2, merge_i, h1);
1369 mrb_write_barrier(mrb, (struct RBasic*)RHASH(hash1));
1370 return;
1371}
1372
1373/*
1374 * call-seq:
1375 * hsh.rehash -> hsh
1376 *
1377 * Rebuilds the hash based on the current hash values for each key. If
1378 * values of key objects have changed since they were inserted, this
1379 * method will reindex <i>hsh</i>.
1380 *
1381 * keys = (1..17).map{|n| [n]}
1382 * k = keys[0]
1383 * h = {}
1384 * keys.each{|key| h[key] = key[0]}
1385 * h #=> { [1]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7,
1386 * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14,
1387 * [15]=>15,[16]=>16,[17]=>17}
1388 * h[k] #=> 1
1389 * k[0] = keys.size + 1
1390 * h #=> {[18]=> 1, [2]=> 2, [3]=> 3, [4]=> 4, [5]=> 5, [6]=> 6, [7]=> 7,
1391 * [8]=> 8, [9]=> 9,[10]=>10,[11]=>11,[12]=>12,[13]=>13,[14]=>14,
1392 * [15]=>15,[16]=>16,[17]=>17}
1393 * h[k] #=> nil
1394 * h.rehash
1395 * h[k] #=> 1
1396 */
1397static mrb_value
1398mrb_hash_rehash(mrb_state *mrb, mrb_value self)
1399{
1400 ht_compact(mrb, RHASH_TBL(self));
1401 return self;
1402}
1403
1404void
1405mrb_init_hash(mrb_state *mrb)
1406{
1407 struct RClass *h;
1408
1409 mrb->hash_class = h = mrb_define_class(mrb, "Hash", mrb->object_class); /* 15.2.13 */
1410 MRB_SET_INSTANCE_TT(h, MRB_TT_HASH);
1411
1412 mrb_define_method(mrb, h, "initialize_copy", mrb_hash_init_copy, MRB_ARGS_REQ(1));
1413 mrb_define_method(mrb, h, "[]", mrb_hash_aget, MRB_ARGS_REQ(1)); /* 15.2.13.4.2 */
1414 mrb_define_method(mrb, h, "[]=", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.3 */
1415 mrb_define_method(mrb, h, "clear", mrb_hash_clear, MRB_ARGS_NONE()); /* 15.2.13.4.4 */
1416 mrb_define_method(mrb, h, "default", mrb_hash_default, MRB_ARGS_OPT(1)); /* 15.2.13.4.5 */
1417 mrb_define_method(mrb, h, "default=", mrb_hash_set_default, MRB_ARGS_REQ(1)); /* 15.2.13.4.6 */
1418 mrb_define_method(mrb, h, "default_proc", mrb_hash_default_proc,MRB_ARGS_NONE()); /* 15.2.13.4.7 */
1419 mrb_define_method(mrb, h, "default_proc=", mrb_hash_set_default_proc,MRB_ARGS_REQ(1)); /* 15.2.13.4.7 */
1420 mrb_define_method(mrb, h, "__delete", mrb_hash_delete, MRB_ARGS_REQ(1)); /* core of 15.2.13.4.8 */
1421 mrb_define_method(mrb, h, "empty?", mrb_hash_empty_m, MRB_ARGS_NONE()); /* 15.2.13.4.12 */
1422 mrb_define_method(mrb, h, "has_key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.13 */
1423 mrb_define_method(mrb, h, "has_value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.14 */
1424 mrb_define_method(mrb, h, "include?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.15 */
1425 mrb_define_method(mrb, h, "initialize", mrb_hash_init, MRB_ARGS_OPT(1)|MRB_ARGS_BLOCK()); /* 15.2.13.4.16 */
1426 mrb_define_method(mrb, h, "key?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.18 */
1427 mrb_define_method(mrb, h, "keys", mrb_hash_keys, MRB_ARGS_NONE()); /* 15.2.13.4.19 */
1428 mrb_define_method(mrb, h, "length", mrb_hash_size_m, MRB_ARGS_NONE()); /* 15.2.13.4.20 */
1429 mrb_define_method(mrb, h, "member?", mrb_hash_has_key, MRB_ARGS_REQ(1)); /* 15.2.13.4.21 */
1430 mrb_define_method(mrb, h, "shift", mrb_hash_shift, MRB_ARGS_NONE()); /* 15.2.13.4.24 */
1431 mrb_define_method(mrb, h, "size", mrb_hash_size_m, MRB_ARGS_NONE()); /* 15.2.13.4.25 */
1432 mrb_define_method(mrb, h, "store", mrb_hash_aset, MRB_ARGS_REQ(2)); /* 15.2.13.4.26 */
1433 mrb_define_method(mrb, h, "value?", mrb_hash_has_value, MRB_ARGS_REQ(1)); /* 15.2.13.4.27 */
1434 mrb_define_method(mrb, h, "values", mrb_hash_values, MRB_ARGS_NONE()); /* 15.2.13.4.28 */
1435 mrb_define_method(mrb, h, "rehash", mrb_hash_rehash, MRB_ARGS_NONE());
1436}
Note: See TracBrowser for help on using the repository browser.