зеркало из https://github.com/github/ruby.git
Refactor hash iteration level
- Make it unsigned like as in-flags bits - Make it long since it should be fixable - Reduce it to in-flags bits after decrement
This commit is contained in:
Родитель
94f82a65f7
Коммит
9ab64b1d70
54
hash.c
54
hash.c
|
@ -1274,39 +1274,43 @@ hash_foreach_iter(st_data_t key, st_data_t value, st_data_t argp, int error)
|
||||||
return hash_iter_status_check(status);
|
return hash_iter_status_check(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static unsigned long
|
||||||
iter_lev_in_ivar(VALUE hash)
|
iter_lev_in_ivar(VALUE hash)
|
||||||
{
|
{
|
||||||
VALUE levval = rb_ivar_get(hash, id_hash_iter_lev);
|
VALUE levval = rb_ivar_get(hash, id_hash_iter_lev);
|
||||||
HASH_ASSERT(FIXNUM_P(levval));
|
HASH_ASSERT(FIXNUM_P(levval));
|
||||||
return FIX2INT(levval);
|
long lev = FIX2LONG(levval);
|
||||||
|
HASH_ASSERT(lev >= 0);
|
||||||
|
return (unsigned long)lev;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
|
void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
iter_lev_in_ivar_set(VALUE hash, int lev)
|
iter_lev_in_ivar_set(VALUE hash, unsigned long lev)
|
||||||
{
|
{
|
||||||
rb_ivar_set_internal(hash, id_hash_iter_lev, INT2FIX(lev));
|
HASH_ASSERT(lev >= RHASH_LEV_MAX);
|
||||||
|
HASH_ASSERT(POSFIXABLE(lev)); /* POSFIXABLE means fitting to long */
|
||||||
|
rb_ivar_set_internal(hash, id_hash_iter_lev, LONG2FIX((long)lev));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline unsigned long
|
||||||
iter_lev_in_flags(VALUE hash)
|
iter_lev_in_flags(VALUE hash)
|
||||||
{
|
{
|
||||||
unsigned int u = (unsigned int)((RBASIC(hash)->flags >> RHASH_LEV_SHIFT) & RHASH_LEV_MAX);
|
return (unsigned long)((RBASIC(hash)->flags >> RHASH_LEV_SHIFT) & RHASH_LEV_MAX);
|
||||||
return (int)u;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
iter_lev_in_flags_set(VALUE hash, int lev)
|
iter_lev_in_flags_set(VALUE hash, unsigned long lev)
|
||||||
{
|
{
|
||||||
|
HASH_ASSERT(lev <= RHASH_LEV_MAX);
|
||||||
RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((VALUE)lev << RHASH_LEV_SHIFT));
|
RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((VALUE)lev << RHASH_LEV_SHIFT));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static unsigned long
|
||||||
RHASH_ITER_LEV(VALUE hash)
|
RHASH_ITER_LEV(VALUE hash)
|
||||||
{
|
{
|
||||||
int lev = iter_lev_in_flags(hash);
|
unsigned long lev = iter_lev_in_flags(hash);
|
||||||
|
|
||||||
if (lev == RHASH_LEV_MAX) {
|
if (lev == RHASH_LEV_MAX) {
|
||||||
return iter_lev_in_ivar(hash);
|
return iter_lev_in_ivar(hash);
|
||||||
|
@ -1319,33 +1323,37 @@ RHASH_ITER_LEV(VALUE hash)
|
||||||
static void
|
static void
|
||||||
hash_iter_lev_inc(VALUE hash)
|
hash_iter_lev_inc(VALUE hash)
|
||||||
{
|
{
|
||||||
int lev = iter_lev_in_flags(hash);
|
unsigned long lev = iter_lev_in_flags(hash);
|
||||||
if (lev == RHASH_LEV_MAX) {
|
if (lev == RHASH_LEV_MAX) {
|
||||||
lev = iter_lev_in_ivar(hash);
|
lev = iter_lev_in_ivar(hash) + 1;
|
||||||
iter_lev_in_ivar_set(hash, lev+1);
|
if (!POSFIXABLE(lev)) { /* paranoiac check */
|
||||||
|
rb_raise(rb_eRuntimeError, "too much nested iterations");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lev += 1;
|
lev += 1;
|
||||||
iter_lev_in_flags_set(hash, lev);
|
iter_lev_in_flags_set(hash, lev);
|
||||||
if (lev == RHASH_LEV_MAX) {
|
if (lev < RHASH_LEV_MAX) return;
|
||||||
iter_lev_in_ivar_set(hash, lev);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
iter_lev_in_ivar_set(hash, lev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hash_iter_lev_dec(VALUE hash)
|
hash_iter_lev_dec(VALUE hash)
|
||||||
{
|
{
|
||||||
int lev = iter_lev_in_flags(hash);
|
unsigned long lev = iter_lev_in_flags(hash);
|
||||||
if (lev == RHASH_LEV_MAX) {
|
if (lev == RHASH_LEV_MAX) {
|
||||||
lev = iter_lev_in_ivar(hash);
|
lev = iter_lev_in_ivar(hash);
|
||||||
HASH_ASSERT(lev > 0);
|
if (lev > RHASH_LEV_MAX) {
|
||||||
iter_lev_in_ivar_set(hash, lev-1);
|
iter_lev_in_ivar_set(hash, lev-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rb_attr_delete(hash, id_hash_iter_lev);
|
||||||
}
|
}
|
||||||
else {
|
else if (lev == 0) {
|
||||||
HASH_ASSERT(lev > 0);
|
rb_raise(rb_eRuntimeError, "iteration level underflow");
|
||||||
iter_lev_in_flags_set(hash, lev - 1);
|
|
||||||
}
|
}
|
||||||
|
iter_lev_in_flags_set(hash, lev - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -2901,7 +2909,7 @@ NOINSERT_UPDATE_CALLBACK(hash_aset_str)
|
||||||
VALUE
|
VALUE
|
||||||
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
|
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
|
||||||
{
|
{
|
||||||
int iter_lev = RHASH_ITER_LEV(hash);
|
unsigned long iter_lev = RHASH_ITER_LEV(hash);
|
||||||
|
|
||||||
rb_hash_modify(hash);
|
rb_hash_modify(hash);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче