class IO::Buffer

Constants

BIG_ENDIAN
EXTERNAL
HOST_ENDIAN
IMMUTABLE
INTERNAL
LITTLE_ENDIAN
LOCKED
MAPPED
NETWORK_ENDIAN
PAGE_SIZE
PRIVATE

Public Class Methods

for(p1) click to toggle source
VALUE
rb_io_buffer_type_for(VALUE klass, VALUE string)
{
    StringValue(string);

    VALUE instance = rb_io_buffer_type_allocate(klass);

    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, data);

    rb_str_locktmp(string);

    io_buffer_initialize(data, RSTRING_PTR(string), RSTRING_LEN(string), RB_IO_BUFFER_EXTERNAL, string);

    return instance;
}
map(*args) click to toggle source
static VALUE
io_buffer_map(int argc, VALUE *argv, VALUE klass)
{
    if (argc < 1 || argc > 4) {
        rb_error_arity(argc, 2, 4);
    }

    VALUE io = argv[0];

    size_t size;
    if (argc >= 2) {
        size = RB_NUM2SIZE(argv[1]);
    }
    else {
        off_t file_size = rb_file_size(io);

        // Compiler can confirm that we handled file_size < 0 case:
        if (file_size < 0) {
            rb_raise(rb_eArgError, "Invalid negative file size!");
        }
        // Here, we assume that file_size is positive:
        else if ((uintmax_t)file_size > SIZE_MAX) {
            rb_raise(rb_eArgError, "File larger than address space!");
        }
        else {
            // This conversion shoud be safe:
            size = (size_t)file_size;
        }
    }

    off_t offset = 0;
    if (argc >= 3) {
        offset = NUM2OFFT(argv[2]);
    }

    enum rb_io_buffer_flags flags = RB_IO_BUFFER_IMMUTABLE;
    if (argc >= 4) {
        flags = RB_NUM2UINT(argv[3]);
    }

    return rb_io_buffer_map(io, size, offset, flags);
}
new(*args) click to toggle source
VALUE
rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self)
{
    if (argc < 1 || argc > 2) {
        rb_error_arity(argc, 1, 2);
    }

    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    size_t size = RB_NUM2SIZE(argv[0]);

    enum rb_io_buffer_flags flags = 0;
    if (argc >= 2) {
        flags = RB_NUM2UINT(argv[1]);
    }
    else {
        if (size > RUBY_IO_BUFFER_PAGE_SIZE) {
            flags |= RB_IO_BUFFER_MAPPED;
        }
        else {
            flags |= RB_IO_BUFFER_INTERNAL;
        }
    }

    io_buffer_initialize(data, NULL, size, flags, Qnil);

    return self;
}

Public Instance Methods

<=>(p1) click to toggle source
static VALUE
rb_io_buffer_compare(VALUE self, VALUE other)
{
    const void *ptr1, *ptr2;
    size_t size1, size2;

    rb_io_buffer_get_immutable(self, &ptr1, &size1);
    rb_io_buffer_get_immutable(other, &ptr2, &size2);

    if (size1 < size2) {
        return RB_INT2NUM(-1);
    }

    if (size1 > size2) {
        return RB_INT2NUM(1);
    }

    return RB_INT2NUM(memcmp(ptr1, ptr2, size1));
}
clear(*args) click to toggle source
static VALUE
io_buffer_clear(int argc, VALUE *argv, VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    if (argc > 3) {
        rb_error_arity(argc, 0, 3);
    }

    uint8_t value = 0;
    if (argc >= 1) {
        value = NUM2UINT(argv[0]);
    }

    size_t offset = 0;
    if (argc >= 2) {
        offset = NUM2SIZET(argv[1]);
    }

    size_t length = data->size;
    if (argc >= 3) {
        length = NUM2SIZET(argv[2]);
    }

    rb_io_buffer_clear(self, value, offset, length);

    return self;
}
copy(p1, p2) click to toggle source
static VALUE
io_buffer_copy(VALUE self, VALUE source, VALUE offset)
{
    size_t size = rb_io_buffer_copy(self, source, NUM2SIZET(offset));

    return RB_SIZE2NUM(size);
}
external?() click to toggle source
static VALUE
rb_io_buffer_external_p(VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    return data->flags & (RB_IO_BUFFER_INTERNAL | RB_IO_BUFFER_MAPPED) ? Qfalse : Qtrue;
}
free() click to toggle source
VALUE
rb_io_buffer_free(VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    if (data->flags & RB_IO_BUFFER_LOCKED) {
        rb_raise(rb_eRuntimeError, "Buffer is locked!");
    }

    io_buffer_free(data);

    return self;
}
get(p1, p2) click to toggle source
static VALUE
io_buffer_get(VALUE self, VALUE type, VALUE _offset)
{
    const void *base;
    size_t size;
    size_t offset = NUM2SIZET(_offset);

    rb_io_buffer_get_immutable(self, &base, &size);

    return rb_io_buffer_get(base, size, RB_SYM2ID(type), offset);
}
immutable?() click to toggle source
static VALUE
rb_io_buffer_immutable_p(VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    return data->flags & RB_IO_BUFFER_IMMUTABLE ? Qtrue : Qfalse;
}
inspect() click to toggle source
VALUE
rb_io_buffer_inspect(VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    VALUE result = rb_io_buffer_to_s(self);

    if (io_buffer_validate(data)) {
        io_buffer_hexdump(result, 16, data->base, data->size);
    }

    return result;
}
internal?() click to toggle source
static VALUE
rb_io_buffer_internal_p(VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    return data->flags & RB_IO_BUFFER_INTERNAL ? Qtrue : Qfalse;
}
locked() click to toggle source
VALUE
rb_io_buffer_locked(VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    if (data->flags & RB_IO_BUFFER_LOCKED) {
        rb_raise(rb_eRuntimeError, "Buffer already locked!");
    }

    data->flags |= RB_IO_BUFFER_LOCKED;

    VALUE result = rb_yield(self);

    data->flags &= ~RB_IO_BUFFER_LOCKED;

    return result;
}
locked?() click to toggle source
static VALUE
rb_io_buffer_locked_p(VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    return data->flags & RB_IO_BUFFER_LOCKED ? Qtrue : Qfalse;
}
mapped?() click to toggle source
static VALUE
rb_io_buffer_mapped_p(VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    return data->flags & RB_IO_BUFFER_MAPPED ? Qtrue : Qfalse;
}
resize(p1, p2) click to toggle source
static VALUE
io_buffer_resize(VALUE self, VALUE size, VALUE preserve)
{
    rb_io_buffer_resize(self, NUM2SIZET(size), NUM2SIZET(preserve));

    return self;
}
set(p1, p2, p3) click to toggle source
static VALUE
io_buffer_set(VALUE self, VALUE type, VALUE _offset, VALUE value)
{
    void *base;
    size_t size;
    size_t offset = NUM2SIZET(_offset);

    rb_io_buffer_get_mutable(self, &base, &size);

    rb_io_buffer_set(base, size, RB_SYM2ID(type), offset, value);

    return SIZET2NUM(offset);
}
size() click to toggle source
VALUE
rb_io_buffer_size(VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    return SIZET2NUM(data->size);
}
slice(p1, p2) click to toggle source
VALUE
rb_io_buffer_slice(VALUE self, VALUE _offset, VALUE _length)
{
    // TODO fail on negative offets/lengths.
    size_t offset = NUM2SIZET(_offset);
    size_t length = NUM2SIZET(_length);

    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    rb_io_buffer_validate(data, offset, length);

    VALUE instance = rb_io_buffer_type_allocate(rb_class_of(self));
    struct rb_io_buffer *slice = NULL;
    TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, slice);

    slice->base = (char*)data->base + offset;
    slice->size = length;

    // The source should be the root buffer:
    if (data->source != Qnil)
        slice->source = data->source;
    else
        slice->source = self;

    return instance;
}
to_s() click to toggle source
VALUE
rb_io_buffer_to_s(VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    VALUE result = rb_str_new_cstr("#<");

    rb_str_append(result, rb_class_name(CLASS_OF(self)));
    rb_str_catf(result, " %p+%"PRIdSIZE, data->base, data->size);

    if (data->flags & RB_IO_BUFFER_INTERNAL) {
        rb_str_cat2(result, " INTERNAL");
    }

    if (data->flags & RB_IO_BUFFER_MAPPED) {
        rb_str_cat2(result, " MAPPED");
    }

    if (data->flags & RB_IO_BUFFER_LOCKED) {
        rb_str_cat2(result, " LOCKED");
    }

    if (data->flags & RB_IO_BUFFER_IMMUTABLE) {
        rb_str_cat2(result, " IMMUTABLE");
    }

    if (data->source != Qnil) {
        rb_str_cat2(result, " SLICE");
    }

    if (!io_buffer_validate(data)) {
        rb_str_cat2(result, " INVALID");
    }

    return rb_str_cat2(result, ">");
}
to_str(*args) click to toggle source
VALUE
rb_io_buffer_to_str(int argc, VALUE *argv, VALUE self)
{
    struct rb_io_buffer *data = NULL;
    TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data);

    size_t offset = 0;
    size_t length = data->size;

    if (argc == 0) {
        // Defaults.
    }
    else if (argc == 1) {
        offset = NUM2SIZET(argv[0]);
        length = data->size - offset;
    }
    else if (argc == 2) {
        offset = NUM2SIZET(argv[0]);
        length = NUM2SIZET(argv[1]);
    }
    else {
        rb_error_arity(argc, 0, 2);
    }

    rb_io_buffer_validate(data, offset, length);

    return rb_usascii_str_new((char*)data->base + offset, length);
}