Class: FFI::Pointer
| Relationships & Source Files | |
| Extension / Inclusion / Inheritance Descendants | |
|
Subclasses:
|
|
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
AbstractMemory
|
|
|
Instance Chain:
self,
AbstractMemory
|
|
| 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
-
NULL =
# File 'ext/ffi_c/Pointer.c', line 547
NULLpointerrbffi_NullPointerSingleton -
SIZE =
# File 'lib/ffi/pointer.rb', line 45
PointersizePlatform::ADDRESS_SIZE / 8
AbstractMemory - Inherited
Class Method Summary
-
.new(address) ⇒ self
constructor
A new instance of
Pointer. -
.size ⇒ Integer
Return the size of a pointer on the current platform, in bytes.
Instance Attribute Summary
- #autorelease=(autorelease) rw
- #autorelease? ⇒ Boolean rw
- #null? ⇒ Boolean readonly
AbstractMemory - Inherited
| #size_limit? | Return |
Instance Method Summary
- #+(offset)
- #==(other)
-
#address
Alias for #to_i.
- #free
-
#initialize_copy(other)
This method is internally used by
#dupand#clone. -
#inspect
Alias for #to_s.
-
#order ⇒ :big, :little
Get or set
self‘s endianness. -
#read(type) ⇒ Object
Read pointer’s contents as
type -
#read_array_of_type(type, reader, length) ⇒ Array
Read an array of
typeof lengthlength. -
#read_string(len = nil) ⇒ String
Read pointer’s contents as a string, or the first
lenbytes of the equivalent string iflenis notnil. -
#read_string_length(len) ⇒ String
Read the first
lenbytes of pointer’s contents as a string. -
#read_string_to_null ⇒ String
Read pointer’s contents as a string.
- #slice(offset, length)
- #address (also: #address)
- #to_ptr ⇒ self
- #inspect (also: #inspect)
- #type_size
-
#write(type, value) ⇒ nil
Write
valueof typetypeto pointer’s content. -
#write_array_of_type(type, writer, ary) ⇒ self
Write
aryin pointer’s contents astype. -
#write_string(str, len = nil) ⇒ self
Write
strin pointer’s contents, or firstlenbytes iflenis notnil. -
#write_string_length(str, len) ⇒ self
Write
lenfirst bytes ofstrin pointer’s contents.
AbstractMemory - Inherited
Constructor Details
.new(address) ⇒ self
.new(type, address) ⇒ self
self
.new(type, address) ⇒ self
A new instance of Pointer.
# 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
.size ⇒ Integer
Return the size of a pointer on the current platform, in bytes
# 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.)
# 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.)
Boolean (rw)
Get({autorelease} attribute. See also Autorelease section.)
# 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.)
Boolean (readonly)
Return({true} if {self} is a {NULL} pointer.)
# 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)
# 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)
# 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)
# 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.
# 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
:big, :little
#order(order) ⇒ Object
Get or set self‘s endianness
# 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)
# 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.
#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.
# 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
# File 'lib/ffi/pointer.rb', line 72
def read_string_length(len) get_bytes(0, len) end
#read_string_to_null ⇒ String
# 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}.)
# 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
# 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_ptr ⇒ self
# File 'lib/ffi/pointer.rb', line 142
def to_ptr self end
#inspect
#pointer(object)
Also known as: #inspect
# 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)
# 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.
#write_string(str, len = nil) ⇒ self
Write str in pointer’s contents, or first len bytes if len is not nil.
# 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
# File 'lib/ffi/pointer.rb', line 92
def write_string_length(str, len) put_bytes(0, str, 0, len) end