123456789_123456789_123456789_123456789_123456789_

Class: FFI::Buffer

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: FFI::AbstractMemory
Defined in: ext/ffi_c/Buffer.c

Overview

A Buffer is a function argument type. It should be use with functions playing with C arrays.

Constant Summary

AbstractMemory - Inherited

LONG_MAX

Class Method Summary

Instance Attribute Summary

AbstractMemory - Inherited

#size_limit?

Return true if self has a size limit.

Instance Method Summary

Constructor Details

.new(size, count = 1, clear = false) .new(instance)

[ GitHub ]

  
# File 'ext/ffi_c/Buffer.c', line 123

static VALUE
buffer_initialize(int argc, VALUE* argv, VALUE self)
{
    VALUE rbSize = Qnil, rbCount = Qnil, rbClear = Qnil;
    Buffer* p;
    int nargs;

    TypedData_Get_Struct(self, Buffer, &buffer_data_type, p);

    nargs = rb_scan_args(argc, argv, "12", &rbSize, &rbCount, &rbClear);
    p->memory.typeSize = rbffi_type_size(rbSize);
    p->memory.size = p->memory.typeSize * (nargs > 1 ? NUM2LONG(rbCount) : 1);

    if (p->memory.size > BUFFER_EMBED_MAXLEN) {
        p->data.storage = xmalloc(p->memory.size + 7);
        if (p->data.storage == NULL) {
            rb_raise(rb_eNoMemError, "Failed to allocate memory size=%lu bytes", p->memory.size);
            return Qnil;
        }

        /* ensure the memory is aligned on at least a 8 byte boundary */
        p->memory.address = (void *) (((uintptr_t) p->data.storage + 0x7) & (uintptr_t) ~0x7ULL);

        if (p->memory.size > 0 && (nargs < 3 || RTEST(rbClear))) {
            memset(p->memory.address, 0, p->memory.size);
        }

    } else {
        p->memory.flags |= MEM_EMBED;
        p->memory.address = (void *) &p->data.embed[0];
    }

    if (rb_block_given_p()) {
        return rb_ensure(rb_yield, self, buffer_free, self);
    }

    return self;
}

Class Method Details

.alloc_inout(*args) .a(new)
Also known as: .alloc_inout, .alloc_out

[ GitHub ]

  
# File 'ext/ffi_c/Buffer.c', line 194

static VALUE
buffer_alloc_inout(int argc, VALUE* argv, VALUE klass)
{
    return buffer_initialize(argc, argv, buffer_allocate(klass));
}

.alloc_inout(*args) .a(new)

Alias for .alloc_in.

.alloc_inout(*args) .a(new)

Alias for .alloc_in.

Instance Method Details

#+(offset) #a(Buffer)

[ GitHub ]

  
# File 'ext/ffi_c/Buffer.c', line 226

static VALUE
buffer_plus(VALUE self, VALUE rbOffset)
{
    Buffer* ptr;
    long offset = NUM2LONG(rbOffset);

    TypedData_Get_Struct(self, Buffer, &buffer_data_type, ptr);

    return slice(self, offset, ptr->memory.size - offset);
}

#initialize_copy(other) NOT(CALL)

[ GitHub ]

  
# File 'ext/ffi_c/Buffer.c', line 167

static VALUE
buffer_initialize_copy(VALUE self, VALUE other)
{
    AbstractMemory* src;
    Buffer* dst;

    TypedData_Get_Struct(self, Buffer, &buffer_data_type, dst);
    src = rbffi_AbstractMemory_Cast(other, &buffer_data_type);
    if ((dst->memory.flags & MEM_EMBED) == 0 && dst->data.storage != NULL) {
        xfree(dst->data.storage);
    }
    dst->data.storage = xmalloc(src->size + 7);
    if (dst->data.storage == NULL) {
        rb_raise(rb_eNoMemError, "failed to allocate memory size=%lu bytes", src->size);
        return Qnil;
    }

    dst->memory.address = (void *) (((uintptr_t) dst->data.storage + 0x7) & (uintptr_t) ~0x7ULL);
    dst->memory.size = src->size;
    dst->memory.typeSize = src->typeSize;

    /* finally, copy the actual buffer contents */
    memcpy(dst->memory.address, src->address, src->size);

    return self;
}

#inspect #a(Buffer)

[ GitHub ]

  
# File 'ext/ffi_c/Buffer.c', line 255

static VALUE
buffer_inspect(VALUE self)
{
    char tmp[100];
    Buffer* ptr;

    TypedData_Get_Struct(self, Buffer, &buffer_data_type, ptr);

    snprintf(tmp, sizeof(tmp), "#<FFI:Buffer:%p address=%p size=%ld>", ptr, ptr->memory.address, ptr->memory.size);

    return rb_str_new2(tmp);
}

#length

Alias for total.

[ GitHub ]

#order:big, :little #order(order) ⇒ self

Set or get endianness of Buffer.

[ GitHub ]

  
# File 'ext/ffi_c/Buffer.c', line 285

static VALUE
buffer_order(int argc, VALUE* argv, VALUE self)
{
    Buffer* ptr;

    TypedData_Get_Struct(self, Buffer, &buffer_data_type, ptr);
    if (argc == 0) {
        int order = (ptr->memory.flags & MEM_SWAP) == 0 ? BYTE_ORDER : SWAPPED_ORDER;
        return order == BIG_ENDIAN ? ID2SYM(rb_intern("big")) : ID2SYM(rb_intern("little"));
    } else {
        VALUE rbOrder = Qnil;
        int order = BYTE_ORDER;

        if (rb_scan_args(argc, argv, "1", &rbOrder) < 1) {
            rb_raise(rb_eArgError, "need byte order");
        }
        if (SYMBOL_P(rbOrder)) {
            ID id = SYM2ID(rbOrder);
            if (id == rb_intern("little")) {
                order = LITTLE_ENDIAN;

            } else if (id == rb_intern("big") || id == rb_intern("network")) {
                order = BIG_ENDIAN;
            }
        }
        if (order != BYTE_ORDER) {
            Buffer* p2;
            VALUE retval = slice(self, 0, ptr->memory.size);

            TypedData_Get_Struct(retval, Buffer, &buffer_data_type, p2);
            p2->memory.flags |= MEM_SWAP;
            return retval;
        }

        return self;
    }
}

#slice(offset, length) #an(existing)

[ GitHub ]

  
# File 'ext/ffi_c/Buffer.c', line 244

static VALUE
buffer_slice(VALUE self, VALUE rbOffset, VALUE rbLength)
{
    return slice(self, NUM2LONG(rbOffset), NUM2LONG(rbLength));
}