From 63b0768a55ee52abbd0705ce4c9f41875e9a1a0a Mon Sep 17 00:00:00 2001 From: Sokolov Yura aka funny_falcon Date: Wed, 10 Dec 2014 16:53:57 +0300 Subject: [PATCH 4/4] struct.c: speedup for big structs use simple custom open-addressing hash for big structs. --- struct.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 93 insertions(+), 33 deletions(-) diff --git a/struct.c b/struct.c index 90fcb68..63aeb48 100644 --- a/struct.c +++ b/struct.c @@ -12,12 +12,13 @@ #include "internal.h" #include "vm_core.h" #include "method.h" +#include "id.h" VALUE rb_method_for_self_aref(VALUE name, VALUE arg); VALUE rb_method_for_self_aset(VALUE name, VALUE arg); VALUE rb_cStruct; -static ID id_members; +static ID id_members, id_back_members; static VALUE struct_alloc(VALUE); @@ -66,6 +67,82 @@ rb_struct_members(VALUE s) return members; } +static void +struct_set_members(VALUE klass, VALUE members) +{ + VALUE back = rb_ary_new(); + members = rb_ary_dup(members); + if (RARRAY_LEN(members) <= 10) { + back = members; + } else { + long i, j, mask = 64; + VALUE name; + while (mask < RARRAY_LEN(members) * 5) mask *= 2; + rb_ary_resize(back, mask+1); + rb_ary_store(back, mask, INT2FIX(RARRAY_LEN(members))); + mask -= 2; /* mask = (2**k-1)*2 */ + for (i=0; i> (ID_SCOPE_SHIFT - 1)) & mask; /* j = (id & (mask/2)) * 2 */ + for (;;) { + if (!RTEST(RARRAY_AREF(back, j))) { + rb_ary_store(back, j, name); + rb_ary_store(back, j + 1, INT2FIX(i)); + break; + } + j = (j * 5 + 2) & mask; /* j=(((j/2)*5+1)&(mask/2))*2 */ + } + } + } + rb_obj_freeze(back); + rb_ivar_set(klass, id_members, members); + rb_ivar_set(klass, id_back_members, back); + RB_GC_GUARD(members); +} + +static inline int +struct_member_pos(VALUE s, VALUE name) +{ + VALUE back = struct_ivar_get(rb_obj_class(s), id_back_members); + VALUE const * p; + long j, mask; + + if (UNLIKELY(NIL_P(back))) { + rb_raise(rb_eTypeError, "uninitialized struct"); + } + if (UNLIKELY(!RB_TYPE_P(back, T_ARRAY))) { + rb_raise(rb_eTypeError, "corrupted struct"); + } + + p = RARRAY_CONST_PTR(back); + mask = RARRAY_LEN(back); + if (mask <= 10) { + if (UNLIKELY(RSTRUCT_LEN(s) != RARRAY_LEN(back))) { + rb_raise(rb_eTypeError, "struct size differs (%ld required %ld given)", + mask, RSTRUCT_LEN(s)); + } + for (j=0; j> (ID_SCOPE_SHIFT - 1)) & mask; + for (;;) { + if (p[j] == name) + return FIX2INT(p[j + 1]); + if (!RTEST(p[j])) { + return -1; + } + j = (j * 5 + 2) & mask; + } +} + static VALUE rb_struct_s_members_m(VALUE klass) { @@ -101,16 +178,10 @@ not_a_member(ID id) VALUE rb_struct_getmember(VALUE obj, ID id) { - VALUE members, slot; - long i, len; - - members = rb_struct_members(obj); - slot = ID2SYM(id); - len = RARRAY_LEN(members); - for (i=0; i