class Fiddle::Pointer
Fiddle::Pointer
is a class to handle C pointers
Attributes
Public Class Methods
Get the underlying pointer for ruby object val
and return it as a Fiddle::Pointer
object.
# File fiddle/lib/fiddle/ffi_backend.rb, line 235 def self.from_native(value, ctx) self.new(value) end
Examples¶ ↑
# Automatically freeing the pointer when the block is exited - recommended Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) do |pointer| ... end # Manually freeing but relying on the garbage collector otherwise pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) ... pointer.call_free # Relying on the garbage collector - may lead to unlimited memory allocated before freeing any, but safe pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) ... # Only manually freeing pointer = Fiddle::Pointer.malloc(size) begin ... ensure Fiddle.free pointer end # No free function and no call to free - the native memory will leak if the pointer is garbage collected pointer = Fiddle::Pointer.malloc(size) ...
Allocate size
bytes of memory and associate it with an optional freefunc
.
If a block is supplied, the pointer will be yielded to the block instead of being returned, and the return value of the block will be returned. A freefunc
must be supplied if a block is.
If a freefunc
is supplied it will be called once, when the pointer is garbage collected or when the block is left if a block is supplied or when the user calls call_free
, whichever happens first. freefunc
must be an address pointing to a function or an instance of Fiddle::Function
.
# File fiddle/lib/fiddle/ffi_backend.rb, line 335 def self.malloc(size, free = nil) if block_given? and free.nil? message = "a free function must be supplied to #{self}.malloc " + "when it is called with a block" raise ArgumentError, message end pointer = new(LibC.malloc(size), size, free) if block_given? begin yield(pointer) ensure pointer.call_free end else pointer end end
# File fiddle/lib/fiddle/ffi_backend.rb, line 299 def initialize(addr, size = nil, free = nil) ptr = if addr.is_a?(FFI::Pointer) addr elsif addr.is_a?(Integer) FFI::Pointer.new(addr) elsif addr.respond_to?(:to_ptr) fiddle_ptr = addr.to_ptr if fiddle_ptr.is_a?(Pointer) fiddle_ptr.ffi_ptr elsif fiddle_ptr.is_a?(FFI::AutoPointer) addr.ffi_ptr elsif fiddle_ptr.is_a?(FFI::Pointer) fiddle_ptr else raise DLError.new("to_ptr should return a Fiddle::Pointer object, was #{fiddle_ptr.class}") end elsif addr.is_a?(IO) raise NotImplementedError, "IO ptr isn't supported" end @size = size ? size : ptr.size @free = free @ffi_ptr = ptr @freed = false end
Create a new pointer to address
with an optional size
and freefunc
.
freefunc
will be called when the instance is garbage collected.
static VALUE rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self) { VALUE ptr, sym, size, wrap = 0, funcwrap = 0; struct ptr_data *data; void *p = NULL; freefunc_t f = NULL; long s = 0; if (rb_scan_args(argc, argv, "12", &ptr, &size, &sym) >= 1) { VALUE addrnum = rb_Integer(ptr); if (addrnum != ptr) wrap = ptr; p = NUM2PTR(addrnum); } if (argc >= 2) { s = NUM2LONG(size); } if (argc >= 3) { f = get_freefunc(sym, &funcwrap); } if (p) { TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data); if (data->ptr && data->free) { /* Free previous memory. Use of inappropriate initialize may cause SEGV. */ (*(data->free))(data->ptr); } RB_OBJ_WRITE(self, &data->wrap[0], wrap); RB_OBJ_WRITE(self, &data->wrap[1], funcwrap); data->ptr = p; data->size = s; data->free = f; } return Qnil; }
Or read the memory at address address
with length len
and return a string with that memory
# File fiddle/lib/fiddle/ffi_backend.rb, line 268 def self.read(addr, len) FFI::Pointer.new(addr).read_bytes(len) end
# File fiddle/lib/fiddle/ffi_backend.rb, line 223 def self.to_native(value, ctx) if value.is_a?(Pointer) value.ffi_ptr elsif value.is_a?(Integer) FFI::Pointer.new(value) elsif value.is_a?(String) value end end
Get the underlying pointer for ruby object val
and return it as a Fiddle::Pointer
object.
# File fiddle/lib/fiddle/ffi_backend.rb, line 239 def self.to_ptr(value) if value.is_a?(String) cptr = Pointer.malloc(value.bytesize) cptr.ffi_ptr.put_string(0, value) cptr elsif value.is_a?(Array) raise NotImplementedError, "array ptr" elsif value.respond_to?(:to_ptr) ptr = value.to_ptr case ptr when Pointer ptr when FFI::Pointer Pointer.new(ptr) else raise DLError.new("to_ptr should return a Fiddle::Pointer object, was #{ptr.class}") end else Pointer.new(value) end end
Write bytes in str
to the location pointed to by address
.
# File fiddle/lib/fiddle/ffi_backend.rb, line 264 def self.write(addr, bytes) FFI::Pointer.new(addr).write_bytes(bytes) end
Public Instance Methods
Returns a new pointer instance that has been advanced n
bytes.
# File fiddle/lib/fiddle/ffi_backend.rb, line 437 def +(delta) self.class.new(to_i + delta, @size - delta) end
Returns a new Fiddle::Pointer
instance that is a dereferenced pointer for this pointer.
Analogous to the star operator in C.
# File fiddle/lib/fiddle/ffi_backend.rb, line 465 def +@ ptr end
Returns a new pointer instance that has been moved back n
bytes.
# File fiddle/lib/fiddle/ffi_backend.rb, line 441 def -(delta) self.class.new(to_i - delta, @size + delta) end
Returns a new Fiddle::Pointer
instance that is a reference pointer for this pointer.
Analogous to the ampersand operator in C.
# File fiddle/lib/fiddle/ffi_backend.rb, line 469 def -@ ref end
Returns -1 if less than, 0 if equal to, 1 if greater than other
.
Returns nil if ptr
cannot be compared to other
.
# File fiddle/lib/fiddle/ffi_backend.rb, line 445 def <=>(other) return unless other.is_a?(Pointer) diff = self.to_i - other.to_i return 0 if diff == 0 diff > 0 ? 1 : -1 end
Returns true if other
wraps the same pointer, otherwise returns false.
# File fiddle/lib/fiddle/ffi_backend.rb, line 457 def ==(other) eql?(other) end
Returns integer stored at index.
If start and length are given, a string containing the bytes from start of length will be returned.
# File fiddle/lib/fiddle/ffi_backend.rb, line 393 def [](index, length = nil) if length ffi_ptr.get_bytes(index, length) else ffi_ptr.get_char(index) end rescue FFI::NullPointerError raise DLError.new("NULL pointer dereference") end
Set the value at index
to int
.
Or, set the memory at start
until length
with the contents of string
, the memory from dl_cptr
, or the memory pointed at by the memory address addr
.
# File fiddle/lib/fiddle/ffi_backend.rb, line 276 def []=(*args, value) if args.size == 2 if value.is_a?(Integer) value = self.class.new(value) end if value.is_a?(Fiddle::Pointer) value = value.to_str(args[1]) end @ffi_ptr.put_bytes(args[0], value, 0, args[1]) elsif args.size == 1 if value.is_a?(Fiddle::Pointer) value = value.to_str(args[0] + 1) else value = value.chr end @ffi_ptr.put_bytes(args[0], value, 0, 1) end rescue FFI::NullPointerError raise DLError.new("NULL pointer access") end
Call the free function for this pointer. Calling more than once will do nothing. Does nothing if there is no free function attached.
# File fiddle/lib/fiddle/ffi_backend.rb, line 374 def call_free return if @free.nil? return if @freed if @free == RUBY_FREE LibC::FREE.call(@ffi_ptr) else @free.call(@ffi_ptr) end @freed = true end
Returns true if other
wraps the same pointer, otherwise returns false.
# File fiddle/lib/fiddle/ffi_backend.rb, line 452 def eql?(other) return unless other.is_a?(Pointer) self.to_i == other.to_i end
Get the free function for this pointer.
Returns a new instance of Fiddle::Function
.
# File fiddle/lib/fiddle/ffi_backend.rb, line 366 def free @free end
Set the free function for this pointer to function
in the given Fiddle::Function
.
# File fiddle/lib/fiddle/ffi_backend.rb, line 370 def free=(free) @free = free end
Returns if the free function for this pointer has been called.
# File fiddle/lib/fiddle/ffi_backend.rb, line 385 def freed? @freed end
Returns a string formatted with an easily readable representation of the internal state of the pointer.
# File fiddle/lib/fiddle/ffi_backend.rb, line 433 def inspect "#<#{self.class.name} ptr=#{to_i.to_s(16)} size=#{@size} free=#{@free.inspect}>" end
Returns true
if this is a null pointer.
# File fiddle/lib/fiddle/ffi_backend.rb, line 354 def null? @ffi_ptr.null? end
Returns a new Fiddle::Pointer
instance that is a dereferenced pointer for this pointer.
Analogous to the star operator in C.
# File fiddle/lib/fiddle/ffi_backend.rb, line 461 def ptr Pointer.new(ffi_ptr.get_pointer(0)) end
Returns a new Fiddle::Pointer
instance that is a reference pointer for this pointer.
Analogous to the ampersand operator in C.
# File fiddle/lib/fiddle/ffi_backend.rb, line 473 def ref cptr = Pointer.malloc(FFI::Type::POINTER.size, RUBY_FREE) cptr.ffi_ptr.put_pointer(0, ffi_ptr) cptr end
Get the size of this pointer.
# File fiddle/lib/fiddle/ffi_backend.rb, line 362 def size defined?(@layout) ? @layout.size : @size end
Set the size of this pointer to size
# File fiddle/lib/fiddle/ffi_backend.rb, line 389 def size=(size) @size = size end
Returns the integer memory location of this pointer.
# File fiddle/lib/fiddle/ffi_backend.rb, line 403 def to_i ffi_ptr.to_i end
# File fiddle/lib/fiddle/ffi_backend.rb, line 358 def to_ptr @ffi_ptr end
without 0
# File fiddle/lib/fiddle/ffi_backend.rb, line 409 def to_s(len = nil) if len ffi_ptr.get_string(0, len) else ffi_ptr.get_string(0) end rescue FFI::NullPointerError raise DLError.new("NULL pointer access") end
Returns the pointer contents as a string.
When called with no arguments, this method will return the contents with the length of this pointer’s size
.
When called with len
, a string of len
bytes will be returned.
See to_s
# File fiddle/lib/fiddle/ffi_backend.rb, line 419 def to_str(len = nil) if len ffi_ptr.read_string(len) else ffi_ptr.read_string(@size) end rescue FFI::NullPointerError raise DLError.new("NULL pointer access") end
Cast this pointer to a ruby object.
# File fiddle/lib/fiddle/ffi_backend.rb, line 429 def to_value raise NotImplementedError, "to_value isn't supported" end