module IOPositioningReadWrite::StringIO

Public Instance Methods

readat(offset) → nil or string click to toggle source
readat(offset, length) → nil or string
readat(offset, length, buffer) → nil or buffer

IO#readat と同じ。

ただし、例外の搬出は挙動が異なります。このあたりは将来的に (200年後くらいには) 改善される見込みです。

処理中は Ruby のすべてのスレッドが停止します (GVL を開放しないため)。

static VALUE
strio_readat(int argc, VALUE argv[], VALUE io)
{
    VALUE offset, length = Qnil, buffer = Qnil;

    rb_scan_args(argc, argv, "12", &offset, &length, &buffer);

    VALUE str = strio_getread(io);

    VALUE tmp = Qnil;
    if (NIL_P(buffer)) {
        tmp = buffer = rb_str_buf_new(0);
    }

    ssize_t lenmax = RSTRING_LEN(str);
    ssize_t len = NIL_P(length) ? lenmax : NUM2SSIZET(length);

    ssize_t off = NUM2SSIZET(offset);
    if (off < 0) {
        off += lenmax;
    }

    if (len == 0) {
        if (NIL_P(buffer)) {
            buffer = rb_str_new(0, 0);
        } else {
            rb_str_modify(buffer);
            rb_str_set_len(buffer, 0);
        }
        OBJ_INFECT(buffer, io);
        return buffer;
    }

    if (off >= lenmax) { return Qnil; }

    if (off + len < 0) {
        rb_raise(rb_eRangeError, "offset and length are too small or too large");
    }

    if (off + len > lenmax) { len = lenmax - off; }

    StringValue(buffer);
    rb_str_modify(buffer);
    rb_str_resize(buffer, len);
    rb_str_set_len(buffer, len);

    memcpy(RSTRING_PTR(buffer), RSTRING_PTR(str) + off, len);

    OBJ_INFECT(buffer, str);

    return buffer;
}
writeat(offset, buffer) → integer click to toggle source

IO#writeat と同じ。

ただし、例外の搬出は挙動が異なります。このあたりは将来的に (200年後くらいには) 改善される見込みです。

処理中は Ruby のすべてのスレッドが停止します (GVL を開放しないため)。

static VALUE
strio_writeat(VALUE io, VALUE offset, VALUE buffer)
{
    rb_secure(4);

    VALUE str = strio_getwrite(io);

    ssize_t off = NUM2SSIZET(offset);
    if (off < 0) { NUM2SSIZET(SIZET2NUM(off)); } // EXCEPTION!
    StringValue(buffer);
    ssize_t len = RSTRING_LEN(buffer);
    if (len < 0) { NUM2SSIZET(SIZET2NUM(len)); } // EXCEPTION!
    if (off + len < 0) {
        rb_raise(rb_eRangeError,
                 "offset and buffer size are too large");
    }

    if (off + len > RSTRING_LEN(str)) {
        ssize_t p = RSTRING_LEN(str);
        rb_str_modify(buffer);
        rb_str_resize(str, off + len);
        rb_str_set_len(str, off + len);
        if (off > p) {
            memset(RSTRING_PTR(str) + p, 0, off - p);
        }
    } else {
        rb_str_modify(str);
    }

    memcpy(RSTRING_PTR(str) + off, RSTRING_PTR(buffer), len);

    return SSIZET2NUM(len);
}