diff --git a/ChangeLog b/ChangeLog index ad63a4a6bd..ee2a8cf204 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +Wed Jul 1 05:43:58 2015 Eric Wong + + * struct.c (AREF_HASH_THRESHOLD): new macro + (id_back_members): new ID + (struct_member_pos_ideal): new function + (struct_member_pos_probe): ditto + (struct_set_members): ditto + (struct_member_pos): ditto + (rb_struct_getmember): use struct_member_pos for O(1) access + (rb_struct_aref_sym): ditto + (rb_struct_aset_sym): ditto + (setup_struct): call struct_set_members + (struct_define_without_accessor): ditto + (Init_Struct): initialize __members_back__ + [ruby-core:66851] [ruby-core:69705] [ruby-core:69821] + Tue Jun 30 23:12:08 2015 Nobuyoshi Nakada * io.c (rb_io_reopen): FilePathValue() ensures the path diff --git a/struct.c b/struct.c index ff4501d03e..eda56733e2 100644 --- a/struct.c +++ b/struct.c @@ -11,12 +11,16 @@ #include "internal.h" #include "vm_core.h" +#include "id.h" + +/* only for struct[:field] access */ +#define AREF_HASH_THRESHOLD (10) VALUE rb_method_for_self_aref(VALUE name, VALUE arg, rb_insn_func_t func); VALUE rb_method_for_self_aset(VALUE name, VALUE arg, rb_insn_func_t func); VALUE rb_cStruct; -static ID id_members; +static ID id_members, id_back_members; static VALUE struct_alloc(VALUE); @@ -66,6 +70,110 @@ rb_struct_members(VALUE s) return members; } +static long +struct_member_pos_ideal(VALUE name, long mask) +{ + /* (id & (mask/2)) * 2 */ + return (SYM2ID(name) >> (ID_SCOPE_SHIFT - 1)) & mask; +} + +static long +struct_member_pos_probe(long prev, long mask) +{ + /* (((prev/2) * 5 + 1) & (mask/2)) * 2 */ + return (prev * 5 + 2) & mask; +} + +static VALUE +struct_set_members(VALUE klass, VALUE members) +{ + VALUE back; + + members = rb_ary_dup(members); + rb_obj_freeze(members); + + if (RARRAY_LEN(members) <= AREF_HASH_THRESHOLD) { + back = members; + } else { + long i, j, mask = 64; + VALUE name; + + while (mask < RARRAY_LEN(members) * 5) mask *= 2; + + back = rb_ary_new2(mask + 1); + rb_ary_store(back, mask, INT2FIX(RARRAY_LEN(members))); + mask -= 2; /* mask = (2**k-1)*2 */ + + for (i=0; i