From: Vincent Isambart Date: 2008-01-21T02:02:28+09:00 Subject: [ruby-dev:33222] Re: Ruby1.9String  バイト列へのインデックス アクセス バンサンです。 On Jan 20, 2008, at 12:44 PM, Vincent Isambart wrote: > これはどうでしょうか: > s = 'a' > s.bytes[0] # => 97 > s.bytes[0] = 98 > s # => 'b' > s.bytes[0] = 'c' # 'c'の長さが1バイトじゃなかったら例 > 外を発生 > s # => 'c' 概念実証のため、作ってみました。 注意:実装はひどい(特にEnumeratorからStringを読 み込む方法)しRangeも対応できないです(実はRange を受けるべきかどうかはわかりません)。 Index: string.c =================================================================== --- string.c (revision 15145) +++ string.c (working copy) @@ -4521,7 +4521,80 @@ return str; } +struct enumerator { + VALUE method; + VALUE proc; + VALUE args; + rb_block_call_func *iter; + VALUE fib; + VALUE dst; + VALUE no_next; +}; +static VALUE +rb_str_bytes_aref(VALUE obj, VALUE indx) +{ + long idx, len; + struct enumerator *ptr; + VALUE str; + + Data_Get_Struct(obj, struct enumerator, ptr); + + str = rb_funcall(ptr->method, rb_intern("receiver"), 0); + + idx = FIX2LONG(indx); + len = RSTRING_LEN(str); + if (idx < 0) + idx += len; + + if ((idx < 0) || (idx >= len)) + return Qnil; + + return INT2FIX(RSTRING_PTR(str)[idx] & 0xff); +} + +static VALUE +rb_str_bytes_aset(VALUE obj, VALUE indx, VALUE val) +{ + long idx, len, v; + struct enumerator *ptr; + VALUE str; + + Data_Get_Struct(obj, struct enumerator, ptr); + + str = rb_funcall(ptr->method, rb_intern("receiver"), 0); + + idx = FIX2LONG(indx); + len = RSTRING_LEN(str); + if (idx < 0) + idx += len; + + if ((idx < 0) || (idx >= len)) + rb_raise(rb_eIndexError, "index %ld out of string", FIX2LONG(indx)); + + switch (TYPE(val)) { + case T_FIXNUM: + v = FIX2LONG(val); + RSTRING_PTR(str)[idx] = (v & 0xff); + break; + + case T_STRING: + if (RSTRING_LEN(val) != 1) { + rb_raise(rb_eTypeError, + "type mismatch: the string must be one byte long", + rb_obj_classname(val)); + } + RSTRING_PTR(str)[idx] = RSTRING_PTR(val)[0]; + break; + + default: + rb_raise(rb_eTypeError, "type mismatch: %s given", + rb_obj_classname(val)); + } + + return val; +} + /* * Document-method: bytes * call-seq: @@ -4553,7 +4626,14 @@ { long i; - RETURN_ENUMERATOR(str, 0, 0); + if (!rb_block_given_p()) { + VALUE enumerator; + + enumerator = rb_enumeratorize(str, ID2SYM(rb_frame_this_func()), 0, 0); + rb_define_singleton_method(enumerator, "[]", rb_str_bytes_aref, 1); + rb_define_singleton_method(enumerator, "[]=", rb_str_bytes_aset, 2); + return enumerator; + } for (i=0; i