123456789_123456789_123456789_123456789_123456789_

Class: FFI::Pointer

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: FFI::AbstractMemory
Defined in: ext/ffi_c/Pointer.c,
lib/ffi/pointer.rb

Overview

Pointer class is used to manage C pointers with ease. A Pointer object is defined by his #address (as a C pointer). It permits additions with an integer for pointer arithmetic.

Autorelease

By default a pointer object frees its content when it’s garbage collected. Therefore it’s usually not necessary to call #free explicit. This behaviour may be changed with #autorelease= method. If it’s set to false, the memory isn’t freed by the garbage collector, but stays valid until free() is called on C level or when the process terminates.

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

AbstractMemory - Inherited

Constructor Details

.new(address) ⇒ self .new(type, address) ⇒ self

A new instance of Pointer.

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 106

static VALUE
ptr_initialize(int argc, VALUE* argv, VALUE self)
{
    Pointer* p;
    VALUE rbType = Qnil, rbAddress = Qnil;
    int typeSize = 1;

    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_data_type, p);

    switch (rb_scan_args(argc, argv, "11", &rbType, &rbAddress)) {
        case 1:
            rbAddress = rbType;
            typeSize = 1;
            break;
        case 2:
            typeSize = rbffi_type_size(rbType);
            break;
        default:
            rb_raise(rb_eArgError, "Invalid arguments");
    }

    switch (TYPE(rbAddress)) {
        case T_FIXNUM:
        case T_BIGNUM:
            p->memory.address = (void*) (uintptr_t) NUM2ULL(rbAddress);
            p->memory.size = LONG_MAX;
            if (p->memory.address == NULL) {
                p->memory.flags = 0;
            }
            break;

        default:
            if (rb_obj_is_kind_of(rbAddress, rbffi_PointerClass)) {
                Pointer* orig;

                RB_OBJ_WRITE(self, &p->rbParent, rbAddress);
                TypedData_Get_Struct(rbAddress, Pointer, &rbffi_pointer_data_type, orig);
                p->memory = orig->memory;
            } else {
                rb_raise(rb_eTypeError, "wrong argument type, expected Integer or FFI::Pointer");
            }
            break;
    }

    p->memory.typeSize = typeSize;

    return self;
}

Class Method Details

.sizeInteger

Return the size of a pointer on the current platform, in bytes

[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 49

def self.size
  SIZE
end

Instance Attribute Details

#autorelease=(autorelease) (rw) Set({autorelease} attribute. See also Autorelease section.)

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 439

static VALUE
ptr_autorelease(VALUE self, VALUE autorelease)
{
    Pointer* ptr;

    rb_check_frozen(self);
    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_data_type, ptr);
    ptr->autorelease = RB_TEST(autorelease);

    return autorelease;
}

#autorelease?Boolean (rw) Get({autorelease} attribute. See also Autorelease section.)

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 456

static VALUE
ptr_autorelease_p(VALUE self)
{
    Pointer* ptr;

    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_data_type, ptr);

    return ptr->autorelease ? Qtrue : Qfalse;
}

#null?Boolean (readonly) Return({true} if {self} is a {NULL} pointer.)

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 288

static VALUE
ptr_null_p(VALUE self)
{
    Pointer* ptr;

    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_data_type, ptr);

    return ptr->memory.address == NULL ? Qtrue : Qfalse;
}

Instance Method Details

#+(offset) #a(new)

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 234

static VALUE
ptr_plus(VALUE self, VALUE offset)
{
    AbstractMemory* ptr;
    long off = NUM2LONG(offset);

    TypedData_Get_Struct(self, AbstractMemory, &rbffi_abstract_memory_data_type, ptr);

    return slice(self, off, ptr->size == LONG_MAX ? LONG_MAX : ptr->size - off);
}

#==(other) #equality(between)

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 304

static VALUE
ptr_equals(VALUE self, VALUE other)
{
    Pointer* ptr;

    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_data_type, ptr);

    if (NIL_P(other)) {
        return ptr->memory.address == NULL ? Qtrue : Qfalse;
    }

    if (!rb_obj_is_kind_of(other, rbffi_PointerClass)) {
        return Qfalse;
    }
    else {
        return ptr->memory.address == POINTER(other)->address ? Qtrue : Qfalse;
    }
}

#address Return(+self+'s base address (alias: #to_i).)

Alias for #to_i.

#free #memory(pointed)

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 399

static VALUE
ptr_free(VALUE self)
{
    Pointer* ptr;

    rb_check_frozen(self);
    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_data_type, ptr);

    if (ptr->allocated) {
        if (ptr->storage != NULL) {
            xfree(ptr->storage);
            ptr->storage = NULL;
        }
        ptr->allocated = false;

    } else {
        VALUE caller = rb_funcall(rb_funcall(Qnil, rb_intern("caller"), 0), rb_intern("first"), 0);

        rb_warn("calling free on non allocated pointer %s from %s", RSTRING_PTR(ptr_inspect(self)), RSTRING_PTR(rb_str_to_str(caller)));
    }

    return self;
}

#initialize_copy(other) NOT(CALL)

This method is internally used by #dup and #clone. Memory content is copied from other.

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 165

static VALUE
ptr_initialize_copy(VALUE self, VALUE other)
{
    AbstractMemory* src;
    Pointer* dst;

    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_data_type, dst);
    src = POINTER(other);
    if (src->size == LONG_MAX) {
        rb_raise(rb_eRuntimeError, "cannot duplicate unbounded memory area");
        return Qnil;
    }

    if ((dst->memory.flags & (MEM_RD | MEM_WR)) != (MEM_RD | MEM_WR)) {
        rb_raise(rb_eRuntimeError, "cannot duplicate unreadable/unwritable memory area");
        return Qnil;
    }

    if (dst->storage != NULL) {
        xfree(dst->storage);
        dst->storage = NULL;
    }

    dst->storage = xmalloc(src->size + 7);
    if (dst->storage == NULL) {
        rb_raise(rb_eNoMemError, "failed to allocate memory size=%lu bytes", src->size);
        return Qnil;
    }

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

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

    return self;
}

#inspect #pointer(object)

Alias for #to_s.

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

Get or set self‘s endianness

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 353

static VALUE
ptr_order(int argc, VALUE* argv, VALUE self)
{
    Pointer* ptr;

    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_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;
            } else {
                rb_raise(rb_eArgError, "unknown byte order");
            }
        }
        if (order != BYTE_ORDER) {
            Pointer* p2;
            VALUE retval = slice(self, 0, ptr->memory.size);

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

        return self;
    }
}

#read(type) ⇒ Object

Read pointer’s contents as type

Same as:

ptr.get(type, 0)

Parameters:

  • type (Symbol, Type)

    of data to read

[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 152

def read(type)
  get(type, 0)
end

#read_array_of_type(type, reader, length) ⇒ Array

Read an array of type of length length.

Examples:

ptr.read_array_of_type(TYPE_UINT8, :read_uint8, 4) # -> [1, 2, 3, 4]

Parameters:

  • type (Type)

    type of data to read from pointer’s contents

  • reader (Symbol)

    method to send to self to read type

  • length (Integer)
[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 114

def read_array_of_type(type, reader, length)
  ary = []
  size = FFI.type_size(type)
  tmp = self
  length.times { |j|
    ary << tmp.send(reader)
    tmp += size unless j == length-1 # avoid OOB
  }
  ary
end

#read_string(len = nil) ⇒ String

Read pointer’s contents as a string, or the first len bytes of the equivalent string if len is not nil.

Parameters:

  • len (nil, Integer) (defaults to: nil)

    length of string to return

[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 57

def read_string(len=nil)
  if len
    return ''.b if len == 0
    get_bytes(0, len)
  else
    get_string(0)
  end
end

#read_string_length(len) ⇒ String

Read the first len bytes of pointer’s contents as a string.

Same as:

ptr.read_string(len)  # with len not nil

Parameters:

  • len (Integer)

    length of string to return

[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 72

def read_string_length(len)
  get_bytes(0, len)
end

#read_string_to_nullString

Read pointer’s contents as a string.

Same as:

ptr.read_string  # with no len
[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 81

def read_string_to_null
  get_string(0)
end

#slice(offset, length) #a(new) #from({offset} for a length {length}.)

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 253

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

#address Return(+self+'s base address (alias: #to_i).)
Also known as: #address

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 328

static VALUE
ptr_address(VALUE self)
{
    Pointer* ptr;

    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_data_type, ptr);

    return ULL2NUM((uintptr_t) ptr->memory.address);
}

#to_ptrself

[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 142

def to_ptr
  self
end

#inspect #pointer(object)
Also known as: #inspect

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 264

static VALUE
ptr_inspect(VALUE self)
{
    char buf[100];
    Pointer* ptr;

    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_data_type, ptr);

    if (ptr->memory.size != LONG_MAX) {
        snprintf(buf, sizeof(buf), "#<%s address=%p size=%lu>",
                rb_obj_classname(self), ptr->memory.address, ptr->memory.size);
    } else {
        snprintf(buf, sizeof(buf), "#<%s address=%p>", rb_obj_classname(self), ptr->memory.address);
    }

    return rb_str_new2(buf);
}

#type_size

[ GitHub ]

  
# File 'ext/ffi_c/Pointer.c', line 423

static VALUE
ptr_type_size(VALUE self)
{
    Pointer* ptr;

    TypedData_Get_Struct(self, Pointer, &rbffi_pointer_data_type, ptr);

    return INT2NUM(ptr->memory.typeSize);
}

#write(type, value) ⇒ nil

Write value of type type to pointer’s content

Same as:

ptr.put(type, 0)

Parameters:

  • type (Symbol, Type)

    of data to read

  • value (Object)

    to write

[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 163

def write(type, value)
  put(type, 0, value)
end

#write_array_of_type(type, writer, ary) ⇒ self

Write ary in pointer’s contents as type.

Examples:

ptr.write_array_of_type(TYPE_UINT8, :put_uint8, [1, 2, 3 ,4])

Parameters:

  • type (Type)

    type of data to write to pointer’s contents

  • writer (Symbol)

    method to send to self to write type

  • ary (Array)
[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 132

def write_array_of_type(type, writer, ary)
  size = FFI.type_size(type)
  ary.each_with_index { |val, i|
    break unless i < self.size
    self.send(writer, i * size, val)
  }
  self
end

#write_string(str, len = nil) ⇒ self

Write str in pointer’s contents, or first len bytes if len is not nil.

Parameters:

  • str (String)

    string to write

  • len (Integer) (defaults to: nil)

    length of string to return

[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 101

def write_string(str, len=nil)
  len = str.bytesize unless len
  # Write the string data without NUL termination
  put_bytes(0, str, 0, len)
end

#write_string_length(str, len) ⇒ self

Write len first bytes of str in pointer’s contents.

Same as:

ptr.write_string(str, len)   # with len not nil

Parameters:

  • str (String)

    string to write

  • len (Integer)

    length of string to return

[ GitHub ]

  
# File 'lib/ffi/pointer.rb', line 92

def write_string_length(str, len)
  put_bytes(0, str, 0, len)
end