Project

General

Profile

Feature #9590 ยป 0001-introduce-st_foreach_update-st_foreach_update_check.patch

tarui (Masaya Tarui), 03/04/2014 12:09 PM

View differences:

hash.c
170 170
    st_data_t arg;
171 171
};
172 172

  
173
typedef int rb_foreach_update_func(VALUE*, VALUE*, VALUE, int);
174

  
175
struct hash_foreach_update_arg {
176
    VALUE hash;
177
    rb_foreach_update_func *func;
178
    VALUE arg;
179
};
180

  
173 181
static int
174 182
foreach_safe_i(st_data_t key, st_data_t value, st_data_t args, int error)
175 183
{
......
259 267
    return Qnil;
260 268
}
261 269

  
270
static VALUE
271
hash_foreach_update_call(VALUE argp)
272
{
273
    struct hash_foreach_update_arg *arg = (struct hash_foreach_update_arg *)argp;
274
    VALUE hash = arg->hash;
275
    if (st_foreach_update_check(RHASH(hash)->ntbl, arg->func, arg->arg, (st_data_t)Qundef)) {
276
	rb_raise(rb_eRuntimeError, "hash modified during iteration");
277
    }
278
    return Qnil;
279
}
280

  
262 281
void
263 282
rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
264 283
{
......
612 631
};
613 632

  
614 633
static int
615
rb_hash_rehash_i(VALUE key, VALUE value, VALUE arg)
634
rb_hash_rehash_i(VALUE *key, VALUE *value, VALUE arg, int error)
616 635
{
617
    st_table *tbl = (st_table *)arg;
618

  
619
    st_insert(tbl, (st_data_t)key, (st_data_t)value);
620
    return ST_CONTINUE;
636
    if (error) {
637
	return ST_STOP;
638
	/* rb_bug("unexcepted error in Hash#reash"); */
639
    }
640
    return ST_CHECK;
621 641
}
622 642

  
623 643
/*
......
643 663
static VALUE
644 664
rb_hash_rehash(VALUE hash)
645 665
{
646
    VALUE tmp;
647
    st_table *tbl;
666
    struct hash_foreach_update_arg arg;
648 667

  
649 668
    if (RHASH_ITER_LEV(hash) > 0) {
650 669
	rb_raise(rb_eRuntimeError, "rehash during iteration");
......
652 671
    rb_hash_modify_check(hash);
653 672
    if (!RHASH(hash)->ntbl)
654 673
        return hash;
655
    tmp = hash_alloc(0);
656
    tbl = st_init_table_with_size(RHASH(hash)->ntbl->type, RHASH(hash)->ntbl->num_entries);
657
    RHASH(tmp)->ntbl = tbl;
658

  
659
    rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tbl);
660
    st_free_table(RHASH(hash)->ntbl);
661
    RHASH(hash)->ntbl = tbl;
662
    RHASH(tmp)->ntbl = 0;
674

  
675
    RHASH_ITER_LEV(hash)++;
676
    arg.hash = hash;
677
    arg.func = rb_hash_rehash_i;
678
    arg.arg  = hash;
679
    rb_ensure(hash_foreach_update_call, (VALUE)&arg, hash_foreach_ensure, hash);
663 680

  
664 681
    return hash;
665 682
}
internal.h
815 815
int rb_get_next_signal(void);
816 816
int rb_sigaltstack_size(void);
817 817

  
818
/* st.c */
819
int st_foreach_update(st_table *table, int (*func)(ANYARGS), st_data_t arg);
820
int st_foreach_update_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never);
821

  
822

  
818 823
/* strftime.c */
819 824
#ifdef RUBY_ENCODING_H
820 825
size_t rb_strftime_timespec(char *s, size_t maxsize, const char *format, rb_encoding *enc,
st.c
1025 1025
    return 0;
1026 1026
}
1027 1027

  
1028
inline void update_direct(st_table *table, struct st_table_entry *ptr)
1029
{
1030
    st_index_t hash_val,hash_pos;
1031
    st_table_entry **last;
1032
    hash_val = do_hash(ptr->key, table);
1033
    if (hash_val == ptr->hash)
1034
	return;
1035
    hash_pos = hash_pos(hash_val, table->num_bins);
1036
    last = &table->bins[hash_pos(ptr->hash, table->num_bins)];
1037
    while (*last) {
1038
	if (*last == ptr) {
1039
	    *last = ptr->next;
1040
	    break;
1041
	}
1042
	last = &(*last)->next;
1043
    }
1044
    ptr->hash = hash_val;
1045
    ptr->next = table->bins[hash_pos];
1046
    table->bins[hash_pos]=ptr;
1047
}
1048

  
1049
/* don't insert or delete in func */
1050
int
1051
st_foreach_update(st_table *table, int (*func)(ANYARGS), st_data_t arg)
1052
{
1053
    st_table_entry *ptr, **last, *tmp;
1054
    enum st_retval retval;
1055
    st_index_t i;
1056

  
1057
    if (table->entries_packed) {
1058
	for (i = 0; i < table->real_entries; i++) {
1059
	    retval = (*func)(&PKEY(table, i), &PVAL(table, i), arg);
1060
	    /* TODO?: check modify */
1061
	    switch (retval) {
1062
	      case ST_CHECK:
1063
		PHASH_SET(table, i, do_hash(PKEY(table, i), table));
1064
		break;
1065
	      case ST_CONTINUE:
1066
		break;
1067
	      case ST_STOP:
1068
		return 0;
1069
	      case ST_DELETE:
1070
		remove_packed_entry(table, i);
1071
		i--;
1072
		break;
1073
	    }
1074
	}
1075
	return 0;
1076
    }
1077
    ptr = table->head;
1078
    if (ptr != 0) {
1079
	do {
1080
	    i = hash_pos(ptr->hash, table->num_bins);
1081
	    retval = (*func)(&ptr->key, &ptr->record, arg);
1082
	    switch (retval) {
1083
	      case ST_CHECK:
1084
		update_direct(table,ptr);
1085
		/* fall through */
1086
	      case ST_CONTINUE:
1087
		ptr = ptr->fore;
1088
		break;
1089
	      case ST_STOP:
1090
		return 0;
1091
	      case ST_DELETE:
1092
		last = &table->bins[hash_pos(ptr->hash, table->num_bins)];
1093
		for (; (tmp = *last) != 0; last = &tmp->next) {
1094
		    if (ptr == tmp) {
1095
			tmp = ptr->fore;
1096
			*last = ptr->next;
1097
			remove_entry(table, ptr);
1098
			st_free_entry(ptr);
1099
			ptr = tmp;
1100
			break;
1101
		    }
1102
		}
1103
	    }
1104
	} while (ptr && table->head);
1105
    }
1106
    return 0;
1107
}
1108

  
1109
/* use st_delete_safe for delete into func */
1110
int
1111
st_foreach_update_check(st_table *table, int (*func)(ANYARGS), st_data_t arg, st_data_t never)
1112
{
1113
    st_table_entry *ptr, **last, *tmp;
1114
    st_data_t r_key, r_val;
1115
    enum st_retval retval;
1116
    st_index_t i;
1117

  
1118
    if (table->entries_packed) {
1119
	for (i = 0; i < table->real_entries; i++) {
1120
	    st_data_t key, val;
1121
	    key = PKEY(table, i);
1122
	    if (key == never) continue;
1123
	    val = PVAL(table, i);
1124
	    r_key = key;
1125
	    r_val = val;
1126
	    retval = (*func)(&r_key, &r_val, arg, 0);
1127
	    if (!table->entries_packed) {
1128
		ptr = table->head;
1129
		if (ptr == 0) goto unexcepted;
1130
		while(i--){
1131
		    ptr=ptr->fore;
1132
		    if (ptr == table->head) goto unexcepted;
1133
		}
1134
		goto unpacked;
1135
	    }
1136
	    switch (retval) {
1137
	      case ST_CHECK:
1138
		if (PKEY(table, i) == never) break; /* deleted */
1139
		PKEY_SET(table, i, r_key);
1140
		PVAL_SET(table, i, r_val);
1141
		PHASH_SET(table, i, do_hash(r_key, table));
1142
		/* fall through */
1143
	      case ST_CONTINUE:
1144
		break;
1145
	      case ST_STOP:
1146
		return 0;
1147
	      case ST_DELETE:
1148
		remove_safe_packed_entry(table, i, never);
1149
		break;
1150
	    }
1151
	}
1152
	return 0;
1153
    }
1154

  
1155
    ptr = table->head;
1156
    if (ptr != 0) {
1157
	do {
1158
	    if (ptr->key == never)
1159
		goto unpacked_continue;
1160
	    i = hash_pos(ptr->hash, table->num_bins);
1161
	    r_key = ptr->key;
1162
	    r_val = ptr->record;
1163
	    retval = (*func)(&r_key, &r_val, arg, 0);
1164
	  unpacked:
1165
	    switch (retval) {
1166
	      case ST_CHECK:
1167
		if (ptr->key != never) {
1168
		    ptr->key=r_key;
1169
		    ptr->record=r_val;
1170
		    update_direct(table,ptr);
1171
		}
1172
		/* fall through */
1173
	      case ST_CONTINUE:
1174
	      unpacked_continue:
1175
		ptr = ptr->fore;
1176
		break;
1177
	      case ST_STOP:
1178
		return 0;
1179
	      case ST_DELETE:
1180
		if (ptr->key == never) goto unpacked_continue;
1181
		last = &table->bins[hash_pos(ptr->hash, table->num_bins)];
1182
		for (; (tmp = *last) != 0; last = &tmp->next) {
1183
		    if (ptr == tmp) {
1184
			tmp = ptr->fore;
1185
			remove_entry(table, ptr);
1186
			ptr->key = ptr->record = never;
1187
			ptr->hash = 0;
1188
			ptr = tmp;
1189
			break;
1190
		    }
1191
		}
1192
		if (*last == 0) {
1193
		  unexcepted:
1194
		    retval = (*func)(NULL, NULL, arg, 1);
1195
		    return 1;
1196
		}
1197
	    }
1198
	} while (ptr && table->head);
1199
    }
1200
    return 0;
1201
}
1202

  
1203

  
1204

  
1028 1205
int
1029 1206
st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
1030 1207
{
1031
-