class Fiddle::Pointer
Fiddle::Pointer — это класс для работы с указателями C
Атрибуты
Публичные методы класса
Получает базовый указатель для объекта Ruby val и возвращает его как объект Fiddle::Pointer.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 236 def self.from_native(value, ctx) self.new(value) end
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 338
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 Примеры
# 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) ...
Выделяет size байт памяти и связывает их с необязательным freefunc.
Если передан блок, указатель будет передан ему вместо возврата, а возвращено будет значение блока. Если передан блок, необходимо указать freefunc.
Если передан freefunc, он будет вызван один раз — когда указатель будет собран сборщиком мусора, при выходе из блока (если блок передан) или при вызове пользователем call_free, в зависимости от того, что произойдёт раньше. freefunc должен быть адресом, указывающим на функцию, или экземпляром Fiddle::Function.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 300
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"
else
FFI::Pointer.new(Integer(addr))
end
@size = size ? size : ptr.size
@free = free
@ffi_ptr = ptr
@freed = false
end 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;
} Создаёт новый указатель на address с необязательными size и freefunc.
freefunc будет вызван при сборке экземпляра сборщиком мусора.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 269 def self.read(addr, len) FFI::Pointer.new(addr).read_bytes(len) end
Или считывает память по адресу address длиной len и возвращает строку с содержимым этой памяти
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 224
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 # File ext/fiddle/lib/fiddle/ffi_backend.rb, line 240
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 Получает базовый указатель для объекта Ruby val и возвращает его как объект Fiddle::Pointer.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 265 def self.write(addr, bytes) FFI::Pointer.new(addr).write_bytes(bytes) end
Записывает байты из str в область памяти, на которую указывает address.
Публичные методы экземпляра
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 440 def +(delta) self.class.new(to_i + delta, @size - delta) end
Возвращает новый экземпляр указателя, смещённый вперёд на n байт.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 468 def +@ ptr end
Возвращает новый экземпляр Fiddle::Pointer, представляющий собой разыменованный указатель для этого указателя.
Аналог оператора звёздочки в C.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 444 def -(delta) self.class.new(to_i - delta, @size + delta) end
Возвращает новый экземпляр указателя, смещённый назад на n байт.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 472 def -@ ref end
Возвращает новый экземпляр Fiddle::Pointer, представляющий собой указатель-ссылку на этот указатель.
Аналог оператора амперсанда в C.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 448 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
Возвращает -1, если значение меньше, 0, если равно, и 1, если больше other.
Возвращает nil, если ptr нельзя сравнить с other.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 460 def ==(other) eql?(other) end
Возвращает true, если other содержит тот же указатель, и false в противном случае.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 396
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 Возвращает целое число, хранящееся по индексу index.
Если указаны start и length, будет возвращена строка, содержащая байты длиной length, начиная с start.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 277
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 Устанавливает значение index равным int.
Или записывает в память по адресу start до length содержимое string, данные из памяти dl_cptr или данные по адресу памяти addr.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 377
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 Вызывает функцию освобождения для этого указателя. Повторный вызов ничего не делает. Если функция освобождения не назначена, метод ничего не делает.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 455 def eql?(other) return unless other.is_a?(Pointer) self.to_i == other.to_i end
Возвращает true, если other содержит тот же указатель, и false в противном случае.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 369 def free @free end
Получает функцию освобождения для этого указателя.
Возвращает новый экземпляр Fiddle::Function.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 373 def free=(free) @free = free end
Назначает для этого указателя функцию освобождения function в указанном объекте Fiddle::Function.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 388 def freed? @freed end
Возвращает информацию о том, была ли вызвана функция освобождения для этого указателя.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 436
def inspect
"#<#{self.class.name} ptr=#{to_i.to_s(16)} size=#{@size} free=#{@free.inspect}>"
end Возвращает строку с удобным для чтения представлением внутреннего состояния указателя.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 357 def null? @ffi_ptr.null? end
Возвращает true, если это нулевой указатель.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 464 def ptr Pointer.new(ffi_ptr.get_pointer(0)) end
Возвращает новый экземпляр Fiddle::Pointer, представляющий собой разыменованный указатель для этого указателя.
Аналог оператора звёздочки в C.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 476 def ref cptr = Pointer.malloc(FFI::Type::POINTER.size, RUBY_FREE) cptr.ffi_ptr.put_pointer(0, ffi_ptr) cptr end
Возвращает новый экземпляр Fiddle::Pointer, представляющий собой указатель-ссылку на этот указатель.
Аналог оператора амперсанда в C.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 365 def size defined?(@layout) ? @layout.size : @size end
Получает размер этого указателя.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 392 def size=(size) @size = size end
Устанавливает размер этого указателя равным size
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 406 def to_i ffi_ptr.to_i end
Возвращает целочисленный адрес памяти этого указателя.
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 361 def to_ptr @ffi_ptr end
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 412
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 без 0
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 422
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 ptr.to_str => string ptr.to_str(len) => string
Возвращает содержимое указателя в виде строки.
При вызове без аргументов этот метод возвращает содержимое длиной size этого указателя.
При вызове с len будет возвращена строка длиной len байт.
См. to_s
# File ext/fiddle/lib/fiddle/ffi_backend.rb, line 432 def to_value raise NotImplementedError, "to_value isn't supported" end
Преобразует этот указатель в объект Ruby.
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.