класс Fiddle::Pointer
Fiddle::Pointer — это класс для работы с указателями C
Публичные методы класса
static VALUE
rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
{
VALUE ptr, wrap = val, vptr;
if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){
rb_io_t *fptr;
FILE *fp;
GetOpenFile(val, fptr);
fp = rb_io_stdio_file(fptr);
ptr = rb_fiddle_ptr_new(fp, 0, NULL);
}
else if (RTEST(rb_obj_is_kind_of(val, rb_cString))){
char *str = StringValuePtr(val);
wrap = val;
ptr = rb_fiddle_ptr_new(str, RSTRING_LEN(val), NULL);
}
else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){
if (rb_obj_is_kind_of(vptr, rb_cPointer)){
ptr = vptr;
wrap = 0;
}
else{
rb_raise(rb_eFiddleDLError, "to_ptr should return a Fiddle::Pointer object");
}
}
else{
VALUE num = rb_Integer(val);
if (num == val) wrap = 0;
ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
}
if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
return ptr;
} Получить базовый указатель для объекта Ruby val и вернуть его как объект Fiddle::Pointer.
static VALUE
rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
{
VALUE size, sym, obj, wrap = 0;
long s;
freefunc_t f;
switch (rb_scan_args(argc, argv, "11", &size, &sym)) {
case 1:
s = NUM2LONG(size);
f = NULL;
break;
case 2:
s = NUM2LONG(size);
f = get_freefunc(sym, &wrap);
break;
default:
rb_bug("rb_fiddle_ptr_s_malloc");
}
obj = rb_fiddle_ptr_malloc(klass, s,f);
if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
if (rb_block_given_p()) {
if (!f) {
rb_raise(rb_eArgError, "a free function must be supplied to Fiddle::Pointer.malloc when it is called with a block");
}
return rb_ensure(rb_yield, obj, rb_fiddle_ptr_call_free, obj);
} else {
return obj;
}
} Примеры
# 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.
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);
}
data->wrap[0] = wrap;
data->wrap[1] = funcwrap;
data->ptr = p;
data->size = s;
data->free = f;
}
return Qnil;
} Создать новый указатель на address с необязательной size и freefunc.
freefunc будет вызвана при удалении экземпляра из памяти.
static VALUE
rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
{
VALUE ptr, wrap = val, vptr;
if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){
rb_io_t *fptr;
FILE *fp;
GetOpenFile(val, fptr);
fp = rb_io_stdio_file(fptr);
ptr = rb_fiddle_ptr_new(fp, 0, NULL);
}
else if (RTEST(rb_obj_is_kind_of(val, rb_cString))){
char *str = StringValuePtr(val);
wrap = val;
ptr = rb_fiddle_ptr_new(str, RSTRING_LEN(val), NULL);
}
else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){
if (rb_obj_is_kind_of(vptr, rb_cPointer)){
ptr = vptr;
wrap = 0;
}
else{
rb_raise(rb_eFiddleDLError, "to_ptr should return a Fiddle::Pointer object");
}
}
else{
VALUE num = rb_Integer(val);
if (num == val) wrap = 0;
ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
}
if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
return ptr;
} Получить базовый указатель для объекта Ruby val и вернуть его как объект Fiddle::Pointer.
Общедоступные методы экземпляров
static VALUE
rb_fiddle_ptr_plus(VALUE self, VALUE other)
{
void *ptr;
long num, size;
ptr = rb_fiddle_ptr2cptr(self);
size = RPTR_DATA(self)->size;
num = NUM2LONG(other);
return rb_fiddle_ptr_new((char *)ptr + num, size - num, 0);
} Возвращает новый экземпляр указателя, смещённый на n байта.
Возвращает новый экземпляр Fiddle::Pointer, являющийся разыменованным указателем для данного указателя.
Аналогично оператору звездочки в C.
static VALUE
rb_fiddle_ptr_minus(VALUE self, VALUE other)
{
void *ptr;
long num, size;
ptr = rb_fiddle_ptr2cptr(self);
size = RPTR_DATA(self)->size;
num = NUM2LONG(other);
return rb_fiddle_ptr_new((char *)ptr - num, size + num, 0);
} Возвращает новый экземпляр указателя, смещённый назад на n байта.
Возвращает новый экземпляр Fiddle::Pointer, являющийся указателем ссылки для данного указателя.
Аналогично оператору амперсанда в C.
static VALUE
rb_fiddle_ptr_cmp(VALUE self, VALUE other)
{
void *ptr1, *ptr2;
SIGNED_VALUE diff;
if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qnil;
ptr1 = rb_fiddle_ptr2cptr(self);
ptr2 = rb_fiddle_ptr2cptr(other);
diff = (SIGNED_VALUE)ptr1 - (SIGNED_VALUE)ptr2;
if (!diff) return INT2FIX(0);
return diff > 0 ? INT2NUM(1) : INT2NUM(-1);
} Возвращает -1, если меньше, 0, если равно, 1, если больше other.
Возвращает nil, если ptr не может быть сравнено с other.
static VALUE
rb_fiddle_ptr_eql(VALUE self, VALUE other)
{
void *ptr1, *ptr2;
if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qfalse;
ptr1 = rb_fiddle_ptr2cptr(self);
ptr2 = rb_fiddle_ptr2cptr(other);
return ptr1 == ptr2 ? Qtrue : Qfalse;
} Возвращает true, если other оборачивает тот же указатель, в противном случае возвращает false.
static VALUE
rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
{
VALUE arg0, arg1;
VALUE retval = Qnil;
size_t offset, len;
struct ptr_data *data;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
case 1:
offset = NUM2ULONG(arg0);
retval = INT2NUM(*((char *)data->ptr + offset));
break;
case 2:
offset = NUM2ULONG(arg0);
len = NUM2ULONG(arg1);
retval = rb_str_new((char *)data->ptr + offset, len);
break;
default:
rb_bug("rb_fiddle_ptr_aref()");
}
return retval;
} Возвращает целое число, хранящееся по адресу index.
Если заданы start и length, возвращается строка, содержащая байты от start длиной length.
static VALUE
rb_fiddle_ptr_aset(int argc, VALUE argv[], VALUE self)
{
VALUE arg0, arg1, arg2;
VALUE retval = Qnil;
size_t offset, len;
void *mem;
struct ptr_data *data;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){
case 2:
offset = NUM2ULONG(arg0);
((char*)data->ptr)[offset] = NUM2UINT(arg1);
retval = arg1;
break;
case 3:
offset = NUM2ULONG(arg0);
len = NUM2ULONG(arg1);
if (RB_TYPE_P(arg2, T_STRING)) {
mem = StringValuePtr(arg2);
}
else if( rb_obj_is_kind_of(arg2, rb_cPointer) ){
mem = rb_fiddle_ptr2cptr(arg2);
}
else{
mem = NUM2PTR(arg2);
}
memcpy((char *)data->ptr + offset, mem, len);
retval = arg2;
break;
default:
rb_bug("rb_fiddle_ptr_aset()");
}
return retval;
} Set значение по адресу index на int.
Или, установите память по адресу start до length с содержимым string, памятью с dl_cptr, или памятью, на которую указывает адрес памяти addr.
static VALUE
rb_fiddle_ptr_call_free(VALUE self)
{
struct ptr_data *pdata;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
fiddle_ptr_free_ptr(pdata);
return Qnil;
} Вызов функции освобождения для этого указателя. Вызов более одного раза ничего не сделает. Ничего не делает, если прикреплённая функция освобождения отсутствует.
Возвращает true, если other оборачивает тот же указатель, в противном случае возвращает false.
static VALUE
rb_fiddle_ptr_free_get(VALUE self)
{
struct ptr_data *pdata;
VALUE address;
VALUE arg_types;
VALUE ret_type;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
if (!pdata->free)
return Qnil;
address = PTR2NUM(pdata->free);
ret_type = INT2NUM(TYPE_VOID);
arg_types = rb_ary_new();
rb_ary_push(arg_types, INT2NUM(TYPE_VOIDP));
return rb_fiddle_new_function(address, arg_types, ret_type);
} Получить функцию освобождения для этого указателя.
Возвращает новый экземпляр Fiddle::Function.
static VALUE
rb_fiddle_ptr_free_set(VALUE self, VALUE val)
{
struct ptr_data *data;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
data->free = get_freefunc(val, &data->wrap[1]);
return Qnil;
} Set функцию освобождения для этого указателя на function в заданном Fiddle::Function.
static VALUE
rb_fiddle_ptr_freed_p(VALUE self)
{
struct ptr_data *pdata;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
return pdata->freed ? Qtrue : Qfalse;
} Возвращает, была ли вызвана функция освобождения для этого указателя.
static VALUE
rb_fiddle_ptr_inspect(VALUE self)
{
struct ptr_data *data;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>",
RB_OBJ_CLASSNAME(self), (void *)data, data->ptr, data->size, (void *)data->free);
} Возвращает строку, отформатированную с удобным для чтения представлением внутреннего состояния указателя.
static VALUE
rb_fiddle_ptr_null_p(VALUE self)
{
struct ptr_data *data;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
return data->ptr ? Qfalse : Qtrue;
} Возвращает true, если это нулевой указатель.
static VALUE
rb_fiddle_ptr_ptr(VALUE self)
{
struct ptr_data *data;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
return rb_fiddle_ptr_new(*((void**)(data->ptr)),0,0);
} Возвращает новый экземпляр Fiddle::Pointer, являющийся разыменованным указателем для данного указателя.
Аналогично оператору звездочки в C.
static VALUE
rb_fiddle_ptr_ref(VALUE self)
{
struct ptr_data *data;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
return rb_fiddle_ptr_new(&(data->ptr),0,0);
} Возвращает новый экземпляр Fiddle::Pointer, являющийся указателем ссылки для данного указателя.
Аналогично оператору амперсанда в C.
static VALUE
rb_fiddle_ptr_size_get(VALUE self)
{
return LONG2NUM(RPTR_DATA(self)->size);
} Получить размер этого указателя.
static VALUE
rb_fiddle_ptr_size_set(VALUE self, VALUE size)
{
RPTR_DATA(self)->size = NUM2LONG(size);
return size;
} Set размер этого указателя на size
static VALUE
rb_fiddle_ptr_to_i(VALUE self)
{
struct ptr_data *data;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
return PTR2NUM(data->ptr);
} Возвращает целочисленное расположение памяти этого указателя.
static VALUE
rb_fiddle_ptr_to_s(int argc, VALUE argv[], VALUE self)
{
struct ptr_data *data;
VALUE arg1, val;
int len;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
switch (rb_scan_args(argc, argv, "01", &arg1)) {
case 0:
val = rb_str_new2((char*)(data->ptr));
break;
case 1:
len = NUM2INT(arg1);
val = rb_str_new((char*)(data->ptr), len);
break;
default:
rb_bug("rb_fiddle_ptr_to_s");
}
return val;
} Возвращает содержимое указателя в виде строки.
При вызове без аргументов этот метод вернёт содержимое до первого нулевого байта.
При вызове с len, вернётся строка из len байтов.
См. to_str
static VALUE
rb_fiddle_ptr_to_str(int argc, VALUE argv[], VALUE self)
{
struct ptr_data *data;
VALUE arg1, val;
int len;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
switch (rb_scan_args(argc, argv, "01", &arg1)) {
case 0:
val = rb_str_new((char*)(data->ptr),data->size);
break;
case 1:
len = NUM2INT(arg1);
val = rb_str_new((char*)(data->ptr), len);
break;
default:
rb_bug("rb_fiddle_ptr_to_str");
}
return val;
} Возвращает содержимое указателя в виде строки.
При вызове без аргументов этот метод вернёт содержимое длиной этого указателя size.
При вызове с len, вернётся строка из len байтов.
См. to_s
static VALUE
rb_fiddle_ptr_to_value(VALUE self)
{
struct ptr_data *data;
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
return (VALUE)(data->ptr);
} Преобразовать этот указатель в объект Ruby.
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.