patch.diff

Masaki Matsushita, 07/30/2013 10:58 PM

Download (7.55 KB)

View differences:

hash.c
222 222
    return Qnil;
223 223
}
224 224

  
225
void
226
rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
225
static VALUE
226
hash_reverse_foreach_call(VALUE arg)
227
{
228
    VALUE hash = ((struct hash_foreach_arg *)arg)->hash;
229
    if (st_reverse_foreach_check(RHASH(hash)->ntbl, hash_foreach_iter, (st_data_t)arg, (st_data_t)Qundef)) {
230
	rb_raise(rb_eRuntimeError, "hash modified during iteration");
231
    }
232
    return Qnil;
233
}
234

  
235
static void
236
do_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg, int reverse)
227 237
{
228 238
    struct hash_foreach_arg arg;
229 239

  
......
233 243
    arg.hash = hash;
234 244
    arg.func = (rb_foreach_func *)func;
235 245
    arg.arg  = farg;
236
    rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
246
    if (reverse)
247
	rb_ensure(hash_reverse_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
248
    else
249
	rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
250
}
251

  
252
void
253
rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
254
{
255
    do_hash_foreach(hash, func, farg, 0);
256
}
257

  
258
static void
259
rb_hash_reverse_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
260
{
261
    do_hash_foreach(hash, func, farg, 1);
237 262
}
238 263

  
239 264
static VALUE
......
1534 1559
    return hash;
1535 1560
}
1536 1561

  
1562
/*
1563
 *  call-seq:
1564
 *     hsh.reverse_each      {| key, value | block } -> hsh
1565
 *     hsh.reverse_each                              -> an_enumerator
1566
 *
1567
 *  Calls <i>block</i> once for each key in <i>hsh</i>, passing the key-value
1568
 *  pair as parameters.
1569
 *
1570
 *  If no block is given, an enumerator is returned instead.
1571
 *
1572
 *     h = { "a" => 100, "b" => 200 }
1573
 *     h.reverse_each {|key, value| puts "#{key} is #{value}" }
1574
 *
1575
 *  <em>produces:</em>
1576
 *
1577
 *     b is 200
1578
 *     a is 100
1579
 *
1580
 */
1581

  
1582
static VALUE
1583
rb_hash_reverse_each_pair(VALUE hash)
1584
{
1585
    RETURN_SIZED_ENUMERATOR(hash, 0, 0, hash_enum_size);
1586
    if (rb_block_arity() > 1)
1587
	rb_hash_reverse_foreach(hash, each_pair_i_fast, 0);
1588
    else
1589
	rb_hash_reverse_foreach(hash, each_pair_i, 0);
1590
    return hash;
1591
}
1592

  
1537 1593
static int
1538 1594
to_a_i(VALUE key, VALUE value, VALUE ary)
1539 1595
{
......
3643 3699
    rb_define_method(rb_cHash,"each_key", rb_hash_each_key, 0);
3644 3700
    rb_define_method(rb_cHash,"each_pair", rb_hash_each_pair, 0);
3645 3701
    rb_define_method(rb_cHash,"each", rb_hash_each_pair, 0);
3702
    rb_define_method(rb_cHash,"reverse_each", rb_hash_reverse_each_pair, 0);
3646 3703

  
3647 3704
    rb_define_method(rb_cHash,"keys", rb_hash_keys, 0);
3648 3705
    rb_define_method(rb_cHash,"values", rb_hash_values, 0);
include/ruby/st.h
111 111
int st_update(st_table *table, st_data_t key, st_update_callback_func *func, st_data_t arg);
112 112
int st_foreach(st_table *, int (*)(ANYARGS), st_data_t);
113 113
int st_foreach_check(st_table *, int (*)(ANYARGS), st_data_t, st_data_t);
114
int st_reverse_foreach(st_table *, int (*)(ANYARGS), st_data_t);
114
int st_reverse_foreach_check(st_table *, int (*)(ANYARGS), st_data_t, st_data_t);
115 115
void st_add_direct(st_table *, st_data_t, st_data_t);
116 116
void st_free_table(st_table *);
117 117
void st_cleanup_safe(st_table *, st_data_t);
st.c
1091 1091
    return 0;
1092 1092
}
1093 1093

  
1094
#if 0  /* unused right now */
1095 1094
int
1096
st_reverse_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
1095
st_reverse_foreach_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never)
1097 1096
{
1098 1097
    st_table_entry *ptr, **last, *tmp;
1099 1098
    enum st_retval retval;
1100 1099
    int i;
1101 1100

  
1102 1101
    if (table->entries_packed) {
1103
        for (i = table->num_entries-1; 0 <= i; i--) {
1104
            int j;
1105
            st_data_t key, val;
1106
            key = PKEY(table, i);
1107
            val = PVAL(table, i);
1108
            retval = (*func)(key, val, arg);
1109
            switch (retval) {
1102
        for (i = table->num_entries-1; i >= 0; i--) {
1103
	    st_data_t key, val;
1104
	    st_index_t hash;
1105
	    key = PKEY(table, i);
1106
	    val = PVAL(table, i);
1107
	    hash = PHASH(table, i);
1108
	    if (key == never) continue;
1109
	    retval = (*func)(key, val, arg);
1110
	    if (!table->entries_packed) {
1111
		FIND_ENTRY(table, ptr, hash, i);
1112
		if (retval == ST_CHECK) {
1113
		    if (!ptr) goto deleted;
1114
		    goto unpacked_continue;
1115
		}
1116
		goto unpacked;
1117
	    }
1118
	    switch (retval) {
1110 1119
	      case ST_CHECK:	/* check if hash is modified during iteration */
1111
                for (j = 0; j < table->num_entries; j++) {
1112
                    if (PKEY(table, j) == key)
1113
                        break;
1114
                }
1115
                if (j == table->num_entries) {
1116
                    /* call func with error notice */
1117
                    retval = (*func)(0, 0, arg, 1);
1118
                    return 1;
1119
                }
1120
		if (PHASH(table, i) == 0 && PKEY(table, i) == never) {
1121
		    break;
1122
		}
1123
		i = find_packed_index(table, hash, key);
1124
		if (i == table->real_entries) {
1125
		    goto deleted;
1126
		}
1120 1127
		/* fall through */
1121 1128
	      case ST_CONTINUE:
1122 1129
		break;
1123 1130
	      case ST_STOP:
1124 1131
		return 0;
1125 1132
	      case ST_DELETE:
1126
		remove_packed_entry(table, i);
1127
                break;
1128
            }
1133
		remove_safe_packed_entry(table, i, never);
1134
		break;
1135
	    }
1129 1136
        }
1130 1137
        return 0;
1131 1138
    }
1139
    else {
1140
	ptr = table->tail;
1141
    }
1132 1142

  
1133
    if ((ptr = table->head) != 0) {
1134
	ptr = ptr->back;
1143
    if (ptr != 0) {
1135 1144
	do {
1136
	    retval = (*func)(ptr->key, ptr->record, arg, 0);
1145
	    if (ptr->key == never)
1146
		goto unpacked_continue;
1147
	    i = ptr->hash % table->num_bins;
1148
	    retval = (*func)(ptr->key, ptr->record, arg);
1149
	  unpacked:
1137 1150
	    switch (retval) {
1138 1151
	      case ST_CHECK:	/* check if hash is modified during iteration */
1139
		i = ptr->hash % table->num_bins;
1140 1152
		for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) {
1141 1153
		    if (!tmp) {
1154
		      deleted:
1142 1155
			/* call func with error notice */
1143 1156
			retval = (*func)(0, 0, arg, 1);
1144 1157
			return 1;
......
1146 1159
		}
1147 1160
		/* fall through */
1148 1161
	      case ST_CONTINUE:
1162
	      unpacked_continue:
1149 1163
		ptr = ptr->back;
1150 1164
		break;
1151 1165
	      case ST_STOP:
......
1155 1169
		for (; (tmp = *last) != 0; last = &tmp->next) {
1156 1170
		    if (ptr == tmp) {
1157 1171
			tmp = ptr->back;
1158
			*last = ptr->next;
1159 1172
			remove_entry(table, ptr);
1160
			st_free_entry(ptr);
1173
			ptr->key = ptr->record = never;
1174
			ptr->hash = 0;
1161 1175
			ptr = tmp;
1162 1176
			break;
1163 1177
		    }
1164 1178
		}
1165
		ptr = ptr->next;
1166
		free(tmp);
1167
		table->num_entries--;
1168 1179
	    }
1169 1180
	} while (ptr && table->head);
1170 1181
    }
1171 1182
    return 0;
1172 1183
}
1173
#endif
1174 1184

  
1175 1185
/*
1176 1186
 * hash_32 - 32 bit Fowler/Noll/Vo FNV-1a hash code
test/ruby/test_hash.rb
400 400
    assert_equal([], res - expected)
401 401
  end
402 402

  
403
  def test_reverse_each
404
    count = 0
405
    @cls[].reverse_each { |k, v| count + 1 }
406
    assert_equal(0, count)
407

  
408
    h = @h
409
    h.reverse_each do |k, v|
410
      assert_equal(v, h.delete(k))
411
    end
412
    assert_equal(@cls[], h)
413

  
414
    h = @cls[]
415
    h[1] = 1
416
    h[2] = 2
417
    assert_equal([[2,2],[1,1]], h.reverse_each.to_a)
418
  end
419

  
403 420
  def test_empty?
404 421
    assert_empty(@cls[])
405 422
    assert_not_empty(@h)