I don't use tool/sync_default_gem.rb because the last sync was incomplete.

Co-authored-by: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
Co-authored-by: sinisterchipmunk <sinisterchipmunk@gmail.com>
Co-authored-by: Sutou Kouhei <kou@clear-code.com>
This commit is contained in:
Kenta Murata 2020-12-11 09:41:12 +09:00 коммит произвёл GitHub
Родитель 6b1d2de6cc
Коммит 9b0c36b390
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
23 изменённых файлов: 1816 добавлений и 252 удалений

Просмотреть файл

@ -275,15 +275,15 @@ mdview_get_memory_view(VALUE obj, rb_memory_view_t *view, int flags)
return 0;
}
ssize_t i, ndim = RARRAY_LEN(shape_v);
ssize_t *shape = ALLOC_N(ssize_t, ndim);
ssize_t *strides = NULL;
if (!NIL_P(strides_v)) {
if (RARRAY_LEN(strides_v) != ndim) {
rb_raise(rb_eArgError, "strides has an invalid dimension");
}
ssize_t ndim = RARRAY_LEN(shape_v);
if (!NIL_P(strides_v) && RARRAY_LEN(strides_v) != ndim) {
rb_raise(rb_eArgError, "strides has an invalid dimension");
}
strides = ALLOC_N(ssize_t, ndim);
ssize_t *shape = ALLOC_N(ssize_t, ndim);
ssize_t *strides = ALLOC_N(ssize_t, ndim);
ssize_t i;
if (!NIL_P(strides_v)) {
for (i = 0; i < ndim; ++i) {
shape[i] = NUM2SSIZET(RARRAY_AREF(shape_v, i));
strides[i] = NUM2SSIZET(RARRAY_AREF(strides_v, i));
@ -293,6 +293,12 @@ mdview_get_memory_view(VALUE obj, rb_memory_view_t *view, int flags)
for (i = 0; i < ndim; ++i) {
shape[i] = NUM2SSIZET(RARRAY_AREF(shape_v, i));
}
i = ndim - 1;
strides[i] = item_size;
for (; i > 0; --i) {
strides[i-1] = strides[i] * shape[i];
}
}
rb_memory_view_init_as_byte_array(view, obj, RSTRING_PTR(buf_v), RSTRING_LEN(buf_v), true);

Просмотреть файл

@ -22,6 +22,18 @@ rb_fiddle_type_ensure(VALUE type)
ID long_id;
#ifdef TYPE_LONG_LONG
ID long_long_id;
#endif
#ifdef TYPE_INT8_T
ID int8_t_id;
#endif
#ifdef TYPE_INT16_T
ID int16_t_id;
#endif
#ifdef TYPE_INT32_T
ID int32_t_id;
#endif
#ifdef TYPE_INT64_T
ID int64_t_id;
#endif
ID float_id;
ID double_id;
@ -40,6 +52,18 @@ rb_fiddle_type_ensure(VALUE type)
RUBY_CONST_ID(long_id, "long");
#ifdef TYPE_LONG_LONG
RUBY_CONST_ID(long_long_id, "long_long");
#endif
#ifdef TYPE_INT8_T
RUBY_CONST_ID(int8_t_id, "int8_t");
#endif
#ifdef TYPE_INT16_T
RUBY_CONST_ID(int16_t_id, "int16_t");
#endif
#ifdef TYPE_INT32_T
RUBY_CONST_ID(int32_t_id, "int32_t");
#endif
#ifdef TYPE_INT64_T
RUBY_CONST_ID(int64_t_id, "int64_t");
#endif
RUBY_CONST_ID(float_id, "float");
RUBY_CONST_ID(double_id, "double");
@ -72,6 +96,26 @@ rb_fiddle_type_ensure(VALUE type)
else if (type_id == long_long_id) {
return INT2NUM(TYPE_LONG_LONG);
}
#endif
#ifdef TYPE_INT8_T
else if (type_id == int8_t_id) {
return INT2NUM(TYPE_INT8_T);
}
#endif
#ifdef TYPE_INT16_T
else if (type_id == int16_t_id) {
return INT2NUM(TYPE_INT16_T);
}
#endif
#ifdef TYPE_INT32_T
else if (type_id == int32_t_id) {
return INT2NUM(TYPE_INT32_T);
}
#endif
#ifdef TYPE_INT64_T
else if (type_id == int64_t_id) {
return INT2NUM(TYPE_INT64_T);
}
#endif
else if (type_id == float_id) {
return INT2NUM(TYPE_FLOAT);

Просмотреть файл

@ -879,6 +879,172 @@ handle.o: conversions.h
handle.o: fiddle.h
handle.o: function.h
handle.o: handle.c
memory_view.o: $(RUBY_EXTCONF_H)
memory_view.o: $(arch_hdrdir)/ruby/config.h
memory_view.o: $(hdrdir)/ruby.h
memory_view.o: $(hdrdir)/ruby/assert.h
memory_view.o: $(hdrdir)/ruby/backward.h
memory_view.o: $(hdrdir)/ruby/backward/2/assume.h
memory_view.o: $(hdrdir)/ruby/backward/2/attributes.h
memory_view.o: $(hdrdir)/ruby/backward/2/bool.h
memory_view.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
memory_view.o: $(hdrdir)/ruby/backward/2/inttypes.h
memory_view.o: $(hdrdir)/ruby/backward/2/limits.h
memory_view.o: $(hdrdir)/ruby/backward/2/long_long.h
memory_view.o: $(hdrdir)/ruby/backward/2/stdalign.h
memory_view.o: $(hdrdir)/ruby/backward/2/stdarg.h
memory_view.o: $(hdrdir)/ruby/defines.h
memory_view.o: $(hdrdir)/ruby/intern.h
memory_view.o: $(hdrdir)/ruby/internal/anyargs.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/char.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/double.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/int.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/long.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/short.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
memory_view.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
memory_view.o: $(hdrdir)/ruby/internal/assume.h
memory_view.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
memory_view.o: $(hdrdir)/ruby/internal/attr/artificial.h
memory_view.o: $(hdrdir)/ruby/internal/attr/cold.h
memory_view.o: $(hdrdir)/ruby/internal/attr/const.h
memory_view.o: $(hdrdir)/ruby/internal/attr/constexpr.h
memory_view.o: $(hdrdir)/ruby/internal/attr/deprecated.h
memory_view.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
memory_view.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
memory_view.o: $(hdrdir)/ruby/internal/attr/error.h
memory_view.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
memory_view.o: $(hdrdir)/ruby/internal/attr/forceinline.h
memory_view.o: $(hdrdir)/ruby/internal/attr/format.h
memory_view.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noalias.h
memory_view.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noexcept.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noinline.h
memory_view.o: $(hdrdir)/ruby/internal/attr/nonnull.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noreturn.h
memory_view.o: $(hdrdir)/ruby/internal/attr/pure.h
memory_view.o: $(hdrdir)/ruby/internal/attr/restrict.h
memory_view.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
memory_view.o: $(hdrdir)/ruby/internal/attr/warning.h
memory_view.o: $(hdrdir)/ruby/internal/attr/weakref.h
memory_view.o: $(hdrdir)/ruby/internal/cast.h
memory_view.o: $(hdrdir)/ruby/internal/compiler_is.h
memory_view.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
memory_view.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
memory_view.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
memory_view.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
memory_view.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
memory_view.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
memory_view.o: $(hdrdir)/ruby/internal/compiler_since.h
memory_view.o: $(hdrdir)/ruby/internal/config.h
memory_view.o: $(hdrdir)/ruby/internal/constant_p.h
memory_view.o: $(hdrdir)/ruby/internal/core.h
memory_view.o: $(hdrdir)/ruby/internal/core/rarray.h
memory_view.o: $(hdrdir)/ruby/internal/core/rbasic.h
memory_view.o: $(hdrdir)/ruby/internal/core/rbignum.h
memory_view.o: $(hdrdir)/ruby/internal/core/rclass.h
memory_view.o: $(hdrdir)/ruby/internal/core/rdata.h
memory_view.o: $(hdrdir)/ruby/internal/core/rfile.h
memory_view.o: $(hdrdir)/ruby/internal/core/rhash.h
memory_view.o: $(hdrdir)/ruby/internal/core/robject.h
memory_view.o: $(hdrdir)/ruby/internal/core/rregexp.h
memory_view.o: $(hdrdir)/ruby/internal/core/rstring.h
memory_view.o: $(hdrdir)/ruby/internal/core/rstruct.h
memory_view.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
memory_view.o: $(hdrdir)/ruby/internal/ctype.h
memory_view.o: $(hdrdir)/ruby/internal/dllexport.h
memory_view.o: $(hdrdir)/ruby/internal/dosish.h
memory_view.o: $(hdrdir)/ruby/internal/error.h
memory_view.o: $(hdrdir)/ruby/internal/eval.h
memory_view.o: $(hdrdir)/ruby/internal/event.h
memory_view.o: $(hdrdir)/ruby/internal/fl_type.h
memory_view.o: $(hdrdir)/ruby/internal/gc.h
memory_view.o: $(hdrdir)/ruby/internal/glob.h
memory_view.o: $(hdrdir)/ruby/internal/globals.h
memory_view.o: $(hdrdir)/ruby/internal/has/attribute.h
memory_view.o: $(hdrdir)/ruby/internal/has/builtin.h
memory_view.o: $(hdrdir)/ruby/internal/has/c_attribute.h
memory_view.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
memory_view.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
memory_view.o: $(hdrdir)/ruby/internal/has/extension.h
memory_view.o: $(hdrdir)/ruby/internal/has/feature.h
memory_view.o: $(hdrdir)/ruby/internal/has/warning.h
memory_view.o: $(hdrdir)/ruby/internal/intern/array.h
memory_view.o: $(hdrdir)/ruby/internal/intern/bignum.h
memory_view.o: $(hdrdir)/ruby/internal/intern/class.h
memory_view.o: $(hdrdir)/ruby/internal/intern/compar.h
memory_view.o: $(hdrdir)/ruby/internal/intern/complex.h
memory_view.o: $(hdrdir)/ruby/internal/intern/cont.h
memory_view.o: $(hdrdir)/ruby/internal/intern/dir.h
memory_view.o: $(hdrdir)/ruby/internal/intern/enum.h
memory_view.o: $(hdrdir)/ruby/internal/intern/enumerator.h
memory_view.o: $(hdrdir)/ruby/internal/intern/error.h
memory_view.o: $(hdrdir)/ruby/internal/intern/eval.h
memory_view.o: $(hdrdir)/ruby/internal/intern/file.h
memory_view.o: $(hdrdir)/ruby/internal/intern/gc.h
memory_view.o: $(hdrdir)/ruby/internal/intern/hash.h
memory_view.o: $(hdrdir)/ruby/internal/intern/io.h
memory_view.o: $(hdrdir)/ruby/internal/intern/load.h
memory_view.o: $(hdrdir)/ruby/internal/intern/marshal.h
memory_view.o: $(hdrdir)/ruby/internal/intern/numeric.h
memory_view.o: $(hdrdir)/ruby/internal/intern/object.h
memory_view.o: $(hdrdir)/ruby/internal/intern/parse.h
memory_view.o: $(hdrdir)/ruby/internal/intern/proc.h
memory_view.o: $(hdrdir)/ruby/internal/intern/process.h
memory_view.o: $(hdrdir)/ruby/internal/intern/random.h
memory_view.o: $(hdrdir)/ruby/internal/intern/range.h
memory_view.o: $(hdrdir)/ruby/internal/intern/rational.h
memory_view.o: $(hdrdir)/ruby/internal/intern/re.h
memory_view.o: $(hdrdir)/ruby/internal/intern/ruby.h
memory_view.o: $(hdrdir)/ruby/internal/intern/select.h
memory_view.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
memory_view.o: $(hdrdir)/ruby/internal/intern/signal.h
memory_view.o: $(hdrdir)/ruby/internal/intern/sprintf.h
memory_view.o: $(hdrdir)/ruby/internal/intern/string.h
memory_view.o: $(hdrdir)/ruby/internal/intern/struct.h
memory_view.o: $(hdrdir)/ruby/internal/intern/thread.h
memory_view.o: $(hdrdir)/ruby/internal/intern/time.h
memory_view.o: $(hdrdir)/ruby/internal/intern/variable.h
memory_view.o: $(hdrdir)/ruby/internal/intern/vm.h
memory_view.o: $(hdrdir)/ruby/internal/interpreter.h
memory_view.o: $(hdrdir)/ruby/internal/iterator.h
memory_view.o: $(hdrdir)/ruby/internal/memory.h
memory_view.o: $(hdrdir)/ruby/internal/method.h
memory_view.o: $(hdrdir)/ruby/internal/module.h
memory_view.o: $(hdrdir)/ruby/internal/newobj.h
memory_view.o: $(hdrdir)/ruby/internal/rgengc.h
memory_view.o: $(hdrdir)/ruby/internal/scan_args.h
memory_view.o: $(hdrdir)/ruby/internal/special_consts.h
memory_view.o: $(hdrdir)/ruby/internal/static_assert.h
memory_view.o: $(hdrdir)/ruby/internal/stdalign.h
memory_view.o: $(hdrdir)/ruby/internal/stdbool.h
memory_view.o: $(hdrdir)/ruby/internal/symbol.h
memory_view.o: $(hdrdir)/ruby/internal/token_paste.h
memory_view.o: $(hdrdir)/ruby/internal/value.h
memory_view.o: $(hdrdir)/ruby/internal/value_type.h
memory_view.o: $(hdrdir)/ruby/internal/variable.h
memory_view.o: $(hdrdir)/ruby/internal/warning_push.h
memory_view.o: $(hdrdir)/ruby/internal/xmalloc.h
memory_view.o: $(hdrdir)/ruby/memory_view.h
memory_view.o: $(hdrdir)/ruby/missing.h
memory_view.o: $(hdrdir)/ruby/ruby.h
memory_view.o: $(hdrdir)/ruby/st.h
memory_view.o: $(hdrdir)/ruby/subst.h
memory_view.o: closure.h
memory_view.o: conversions.h
memory_view.o: fiddle.h
memory_view.o: function.h
memory_view.o: memory_view.c
pinned.o: $(RUBY_EXTCONF_H)
pinned.o: $(arch_hdrdir)/ruby/config.h
pinned.o: $(hdrdir)/ruby.h
@ -1202,6 +1368,7 @@ pointer.o: $(hdrdir)/ruby/internal/variable.h
pointer.o: $(hdrdir)/ruby/internal/warning_push.h
pointer.o: $(hdrdir)/ruby/internal/xmalloc.h
pointer.o: $(hdrdir)/ruby/io.h
pointer.o: $(hdrdir)/ruby/memory_view.h
pointer.o: $(hdrdir)/ruby/missing.h
pointer.o: $(hdrdir)/ruby/onigmo.h
pointer.o: $(hdrdir)/ruby/oniguruma.h

Просмотреть файл

@ -172,14 +172,19 @@ types.each do |type, signed|
if signed
check_signedness(type.downcase, "stddef.h")
end
else
check_signedness(type.downcase, "stddef.h")
end
end
if have_header("ruby/memory_view.h")
have_type("rb_memory_view_t", ["ruby/memory_view.h"])
end
if libffi
$LOCAL_LIBS.prepend("./#{libffi.a} ").strip! # to exts.mk
$INCFLAGS.gsub!(/-I#{libffi.dir}/, '-I$(LIBFFI_DIR)')
end
$INCFLAGS << " -I$(top_srcdir)"
create_makefile 'fiddle' do |conf|
if !libffi
next conf << "LIBFFI_CLEAN = none\n"

Просмотреть файл

@ -6,7 +6,6 @@ https://ftp.osuosl.org/pub/blfs/conglomeration/libffi/$(pkg).tar.gz \
sha512:980ca30a8d76f963fca722432b1fe5af77d7a4e4d2eac5144fbc5374d4c596609a293440573f4294207e1bdd9fda80ad1e1cafb2ffb543df5a275bc3bd546483 \
#
win32/$(pkg)-mswin.patch -p0
win32/$(pkg)-cygwin.patch -p0
$(pkg)/config.guess -> /tool/config.guess
$(pkg)/config.sub -> /tool/config.sub

Просмотреть файл

@ -7,6 +7,10 @@ VALUE rb_eFiddleError;
void Init_fiddle_pointer(void);
void Init_fiddle_pinned(void);
#ifdef FIDDLE_MEMORY_VIEW
void Init_fiddle_memory_view(void);
#endif
/*
* call-seq: Fiddle.malloc(size)
*
@ -204,6 +208,38 @@ Init_fiddle(void)
rb_define_const(mFiddle, "TYPE_LONG_LONG", INT2NUM(TYPE_LONG_LONG));
#endif
#ifdef TYPE_INT8_T
/* Document-const: TYPE_INT8_T
*
* C type - int8_t
*/
rb_define_const(mFiddle, "TYPE_INT8_T", INT2NUM(TYPE_INT8_T));
#endif
#ifdef TYPE_INT16_T
/* Document-const: TYPE_INT16_T
*
* C type - int16_t
*/
rb_define_const(mFiddle, "TYPE_INT16_T", INT2NUM(TYPE_INT16_T));
#endif
#ifdef TYPE_INT32_T
/* Document-const: TYPE_INT32_T
*
* C type - int32_t
*/
rb_define_const(mFiddle, "TYPE_INT32_T", INT2NUM(TYPE_INT32_T));
#endif
#ifdef TYPE_INT64_T
/* Document-const: TYPE_INT64_T
*
* C type - int64_t
*/
rb_define_const(mFiddle, "TYPE_INT64_T", INT2NUM(TYPE_INT64_T));
#endif
/* Document-const: TYPE_FLOAT
*
* C type - float
@ -298,6 +334,30 @@ Init_fiddle(void)
rb_define_const(mFiddle, "ALIGN_LONG_LONG", INT2NUM(ALIGN_LONG_LONG));
#endif
/* Document-const: ALIGN_INT8_T
*
* The alignment size of a int8_t
*/
rb_define_const(mFiddle, "ALIGN_INT8_T", INT2NUM(ALIGN_INT8_T));
/* Document-const: ALIGN_INT16_T
*
* The alignment size of a int16_t
*/
rb_define_const(mFiddle, "ALIGN_INT16_T", INT2NUM(ALIGN_INT16_T));
/* Document-const: ALIGN_INT32_T
*
* The alignment size of a int32_t
*/
rb_define_const(mFiddle, "ALIGN_INT32_T", INT2NUM(ALIGN_INT32_T));
/* Document-const: ALIGN_INT64_T
*
* The alignment size of a int64_t
*/
rb_define_const(mFiddle, "ALIGN_INT64_T", INT2NUM(ALIGN_INT64_T));
/* Document-const: ALIGN_FLOAT
*
* The alignment size of a float
@ -388,6 +448,30 @@ Init_fiddle(void)
rb_define_const(mFiddle, "SIZEOF_LONG_LONG", INT2NUM(sizeof(LONG_LONG)));
#endif
/* Document-const: SIZEOF_INT8_T
*
* size of a int8_t
*/
rb_define_const(mFiddle, "SIZEOF_INT8_T", INT2NUM(sizeof(int8_t)));
/* Document-const: SIZEOF_INT16_T
*
* size of a int16_t
*/
rb_define_const(mFiddle, "SIZEOF_INT16_T", INT2NUM(sizeof(int16_t)));
/* Document-const: SIZEOF_INT32_T
*
* size of a int32_t
*/
rb_define_const(mFiddle, "SIZEOF_INT32_T", INT2NUM(sizeof(int32_t)));
/* Document-const: SIZEOF_INT64_T
*
* size of a int64_t
*/
rb_define_const(mFiddle, "SIZEOF_INT64_T", INT2NUM(sizeof(int64_t)));
/* Document-const: SIZEOF_FLOAT
*
* size of a float
@ -461,5 +545,9 @@ Init_fiddle(void)
Init_fiddle_handle();
Init_fiddle_pointer();
Init_fiddle_pinned();
#ifdef FIDDLE_MEMORY_VIEW
Init_fiddle_memory_view();
#endif
}
/* vim: set noet sws=4 sw=4: */

Просмотреть файл

@ -1,18 +1,13 @@
# frozen_string_literal: true
source_version = ["", "ext/fiddle/"].find do |dir|
begin
break File.open(File.join(__dir__, "#{dir}lib/fiddle/version.rb")) {|f|
f.gets("\n VERSION = ")
f.gets[/\s*"(.+)"/, 1]
}
rescue Errno::ENOENT
end
version_module = Module.new do
version_rb = File.join(__dir__, "lib/fiddle/version.rb")
module_eval(File.read(version_rb), version_rb, __LINE__)
end
Gem::Specification.new do |spec|
spec.name = "fiddle"
spec.version = source_version
spec.version = version_module::Fiddle::VERSION
spec.authors = ["Aaron Patterson", "SHIBATA Hiroshi"]
spec.email = ["aaron@tenderlovemaking.com", "hsbt@ruby-lang.org"]
@ -39,6 +34,7 @@ Gem::Specification.new do |spec|
"ext/fiddle/function.c",
"ext/fiddle/function.h",
"ext/fiddle/handle.c",
"ext/fiddle/memory_view.c",
"ext/fiddle/pinned.c",
"ext/fiddle/pointer.c",
"ext/fiddle/win32/fficonfig.h",

Просмотреть файл

@ -58,38 +58,38 @@
# error "CHAR_BIT not supported"
#endif
# if SIZEOF_SHORT == 2
# define ffi_type_ushort ffi_type_uint16
# define ffi_type_sshort ffi_type_sint16
# elif SIZEOF_SHORT == 4
# define ffi_type_ushort ffi_type_uint32
# define ffi_type_sshort ffi_type_sint32
# else
# error "short size not supported"
# endif
#if SIZEOF_SHORT == 2
# define ffi_type_ushort ffi_type_uint16
# define ffi_type_sshort ffi_type_sint16
#elif SIZEOF_SHORT == 4
# define ffi_type_ushort ffi_type_uint32
# define ffi_type_sshort ffi_type_sint32
#else
# error "short size not supported"
#endif
# if SIZEOF_INT == 2
# define ffi_type_uint ffi_type_uint16
# define ffi_type_sint ffi_type_sint16
# elif SIZEOF_INT == 4
# define ffi_type_uint ffi_type_uint32
# define ffi_type_sint ffi_type_sint32
# elif SIZEOF_INT == 8
# define ffi_type_uint ffi_type_uint64
# define ffi_type_sint ffi_type_sint64
# else
# error "int size not supported"
# endif
#if SIZEOF_INT == 2
# define ffi_type_uint ffi_type_uint16
# define ffi_type_sint ffi_type_sint16
#elif SIZEOF_INT == 4
# define ffi_type_uint ffi_type_uint32
# define ffi_type_sint ffi_type_sint32
#elif SIZEOF_INT == 8
# define ffi_type_uint ffi_type_uint64
# define ffi_type_sint ffi_type_sint64
#else
# error "int size not supported"
#endif
# if SIZEOF_LONG == 4
# define ffi_type_ulong ffi_type_uint32
# define ffi_type_slong ffi_type_sint32
# elif SIZEOF_LONG == 8
# define ffi_type_ulong ffi_type_uint64
# define ffi_type_slong ffi_type_sint64
# else
# error "long size not supported"
# endif
#if SIZEOF_LONG == 4
# define ffi_type_ulong ffi_type_uint32
# define ffi_type_slong ffi_type_sint32
#elif SIZEOF_LONG == 8
# define ffi_type_ulong ffi_type_uint64
# define ffi_type_slong ffi_type_sint64
#else
# error "long size not supported"
#endif
#if HAVE_LONG_LONG
# if SIZEOF_LONG_LONG == 8
@ -118,6 +118,27 @@
#define TYPE_VARIADIC 9
#define TYPE_CONST_STRING 10
#define TYPE_INT8_T TYPE_CHAR
#if SIZEOF_SHORT == 2
# define TYPE_INT16_T TYPE_SHORT
#elif SIZEOF_INT == 2
# define TYPE_INT16_T TYPE_INT
#endif
#if SIZEOF_SHORT == 4
# define TYPE_INT32_T TYPE_SHORT
#elif SIZEOF_INT == 4
# define TYPE_INT32_T TYPE_INT
#elif SIZEOF_LONG == 4
# define TYPE_INT32_T TYPE_LONG
#endif
#if SIZEOF_INT == 8
# define TYPE_INT64_T TYPE_INT
#elif SIZEOF_LONG == 8
# define TYPE_INT64_T TYPE_LONG
#elif defined(TYPE_LONG_LONG)
# define TYPE_INT64_T TYPE_LONG_LONG
#endif
#ifndef TYPE_SSIZE_T
# if SIZEOF_SIZE_T == SIZEOF_INT
# define TYPE_SSIZE_T TYPE_INT
@ -153,8 +174,8 @@
#define ALIGN_OF(type) offsetof(struct {char align_c; type align_x;}, align_x)
#define ALIGN_VOIDP ALIGN_OF(void*)
#define ALIGN_SHORT ALIGN_OF(short)
#define ALIGN_CHAR ALIGN_OF(char)
#define ALIGN_SHORT ALIGN_OF(short)
#define ALIGN_INT ALIGN_OF(int)
#define ALIGN_LONG ALIGN_OF(long)
#if HAVE_LONG_LONG
@ -163,6 +184,15 @@
#define ALIGN_FLOAT ALIGN_OF(float)
#define ALIGN_DOUBLE ALIGN_OF(double)
#define ALIGN_INT8_T ALIGN_OF(int8_t)
#define ALIGN_INT16_T ALIGN_OF(int16_t)
#define ALIGN_INT32_T ALIGN_OF(int32_t)
#define ALIGN_INT64_T ALIGN_OF(int64_t)
#ifdef HAVE_TYPE_RB_MEMORY_VIEW_T
# define FIDDLE_MEMORY_VIEW
#endif
extern VALUE mFiddle;
extern VALUE rb_eFiddleDLError;

Просмотреть файл

@ -77,18 +77,6 @@ rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type)
return rb_class_new_instance(3, argv, cFiddleFunction);
}
static int
parse_keyword_arg_i(VALUE key, VALUE value, VALUE self)
{
if (key == ID2SYM(rb_intern("name"))) {
rb_iv_set(self, "@name", value);
} else {
rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE,
RB_OBJ_STRING(key));
}
return ST_CONTINUE;
}
static VALUE
normalize_argument_types(const char *name,
VALUE arg_types,
@ -134,15 +122,40 @@ static VALUE
initialize(int argc, VALUE argv[], VALUE self)
{
ffi_cif * cif;
VALUE ptr, arg_types, ret_type, abi, kwds;
VALUE ptr, arg_types, ret_type, abi, kwargs;
VALUE name = Qnil;
VALUE need_gvl = Qfalse;
int c_ret_type;
bool is_variadic = false;
ffi_abi c_ffi_abi;
void *cfunc;
rb_scan_args(argc, argv, "31:", &ptr, &arg_types, &ret_type, &abi, &kwds);
rb_scan_args(argc, argv, "31:", &ptr, &arg_types, &ret_type, &abi, &kwargs);
rb_iv_set(self, "@closure", ptr);
if (!NIL_P(kwargs)) {
enum {
kw_name,
kw_need_gvl,
kw_max_,
};
static ID kw[kw_max_];
VALUE args[kw_max_];
if (!kw[0]) {
kw[kw_name] = rb_intern_const("name");
kw[kw_need_gvl] = rb_intern_const("need_gvl");
}
rb_get_kwargs(kwargs, kw, 0, kw_max_, args);
if (args[kw_name] != Qundef) {
name = args[kw_name];
}
if (args[kw_need_gvl] != Qundef) {
need_gvl = args[kw_need_gvl];
}
}
rb_iv_set(self, "@name", name);
rb_iv_set(self, "@need_gvl", need_gvl);
ptr = rb_Integer(ptr);
cfunc = NUM2PTR(ptr);
PTR2NUM(cfunc);
@ -170,8 +183,6 @@ initialize(int argc, VALUE argv[], VALUE self)
rb_iv_set(self, "@abi", abi);
rb_iv_set(self, "@is_variadic", is_variadic ? Qtrue : Qfalse);
if (!NIL_P(kwds)) rb_hash_foreach(kwds, parse_keyword_arg_i, self);
TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);
cif->arg_types = NULL;
@ -205,6 +216,7 @@ function_call(int argc, VALUE argv[], VALUE self)
VALUE arg_types;
VALUE cPointer;
VALUE is_variadic;
VALUE need_gvl;
int n_arg_types;
int n_fixed_args = 0;
int n_call_args = 0;
@ -218,6 +230,7 @@ function_call(int argc, VALUE argv[], VALUE self)
arg_types = rb_iv_get(self, "@argument_types");
cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));
is_variadic = rb_iv_get(self, "@is_variadic");
need_gvl = rb_iv_get(self, "@need_gvl");
n_arg_types = RARRAY_LENINT(arg_types);
n_fixed_args = n_arg_types;
@ -355,7 +368,12 @@ function_call(int argc, VALUE argv[], VALUE self)
args.values[i_call] = NULL;
args.fn = (void(*)(void))NUM2PTR(cfunc);
(void)rb_thread_call_without_gvl(nogvl_ffi_call, &args, 0, 0);
if (RTEST(need_gvl)) {
ffi_call(args.cif, args.fn, &(args.retval), args.values);
}
else {
(void)rb_thread_call_without_gvl(nogvl_ffi_call, &args, 0, 0);
}
rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno));
#if defined(_WIN32)
@ -433,6 +451,10 @@ Init_fiddle_function(void)
* Caller must ensure the underlying function is called in a
* thread-safe manner if running in a multi-threaded process.
*
* Note that it is not thread-safe to use this method to
* directly or indirectly call many Ruby C-extension APIs unless
* you don't pass +need_gvl: true+ to Fiddle::Function#new.
*
* For an example see Fiddle::Function
*
*/
@ -440,13 +462,20 @@ Init_fiddle_function(void)
/*
* Document-method: new
* call-seq: new(ptr, args, ret_type, abi = DEFAULT)
* call-seq: new(ptr,
* args,
* ret_type,
* abi = DEFAULT,
* name: nil,
* need_gvl: false)
*
* Constructs a Function object.
* * +ptr+ is a referenced function, of a Fiddle::Handle
* * +args+ is an Array of arguments, passed to the +ptr+ function
* * +ret_type+ is the return type of the function
* * +abi+ is the ABI of the function
* * +name+ is the name of the function
* * +need_gvl+ is whether GVL is needed to call the function
*
*/
rb_define_method(cFiddleFunction, "initialize", initialize, -1);

Просмотреть файл

@ -35,12 +35,37 @@ module Fiddle
def parse_struct_signature(signature, tymap=nil)
if signature.is_a?(String)
signature = split_arguments(signature, /[,;]/)
elsif signature.is_a?(Hash)
signature = [signature]
end
mems = []
tys = []
signature.each{|msig|
msig = compact(msig)
msig = compact(msig) if msig.is_a?(String)
case msig
when Hash
msig.each do |struct_name, struct_signature|
struct_name = struct_name.to_s if struct_name.is_a?(Symbol)
struct_name = compact(struct_name)
struct_count = nil
if struct_name =~ /^([\w\*\s]+)\[(\d+)\]$/
struct_count = $2.to_i
struct_name = $1
end
if struct_signature.respond_to?(:entity_class)
struct_type = struct_signature
else
parsed_struct = parse_struct_signature(struct_signature, tymap)
struct_type = CStructBuilder.create(CStruct, *parsed_struct)
end
if struct_count
ty = [struct_type, struct_count]
else
ty = struct_type
end
mems.push([struct_name, struct_type.members])
tys.push(ty)
end
when /^[\w\*\s]+[\*\s](\w+)$/
mems.push($1)
tys.push(parse_ctype(msig, tymap))
@ -128,50 +153,90 @@ module Fiddle
return [parse_ctype(ty[0], tymap), ty[1]]
when 'void'
return TYPE_VOID
when /^(?:(?:signed\s+)?long\s+long(?:\s+int\s+)?|int64_t)(?:\s+\w+)?$/
if( defined?(TYPE_LONG_LONG) )
return TYPE_LONG_LONG
else
when /\A(?:(?:signed\s+)?long\s+long(?:\s+int\s+)?|int64_t)(?:\s+\w+)?\z/
unless Fiddle.const_defined?(:TYPE_LONG_LONG)
raise(RuntimeError, "unsupported type: #{ty}")
end
when /^(?:unsigned\s+long\s+long(?:\s+int\s+)?|uint64_t)(?:\s+\w+)?$/
if( defined?(TYPE_LONG_LONG) )
return -TYPE_LONG_LONG
else
return TYPE_LONG_LONG
when /\A(?:unsigned\s+long\s+long(?:\s+int\s+)?|uint64_t)(?:\s+\w+)?\z/
unless Fiddle.const_defined?(:TYPE_LONG_LONG)
raise(RuntimeError, "unsupported type: #{ty}")
end
when /^(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?$/
return -TYPE_LONG_LONG
when /\A(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?\z/
return TYPE_LONG
when /^unsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?$/
when /\Aunsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?\z/
return -TYPE_LONG
when /^(?:signed\s+)?int(?:\s+\w+)?$/
when /\A(?:signed\s+)?int(?:\s+\w+)?\z/
return TYPE_INT
when /^(?:unsigned\s+int|uint)(?:\s+\w+)?$/
when /\A(?:unsigned\s+int|uint)(?:\s+\w+)?\z/
return -TYPE_INT
when /^(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?$/
when /\A(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?\z/
return TYPE_SHORT
when /^unsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?$/
when /\Aunsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?\z/
return -TYPE_SHORT
when /^(?:signed\s+)?char(?:\s+\w+)?$/
when /\A(?:signed\s+)?char(?:\s+\w+)?\z/
return TYPE_CHAR
when /^unsigned\s+char(?:\s+\w+)?$/
when /\Aunsigned\s+char(?:\s+\w+)?\z/
return -TYPE_CHAR
when /^float(?:\s+\w+)?$/
when /\Aint8_t(?:\s+\w+)?\z/
unless Fiddle.const_defined?(:TYPE_INT8_T)
raise(RuntimeError, "unsupported type: #{ty}")
end
return TYPE_INT8_T
when /\Auint8_t(?:\s+\w+)?\z/
unless Fiddle.const_defined?(:TYPE_INT8_T)
raise(RuntimeError, "unsupported type: #{ty}")
end
return -TYPE_INT8_T
when /\Aint16_t(?:\s+\w+)?\z/
unless Fiddle.const_defined?(:TYPE_INT16_T)
raise(RuntimeError, "unsupported type: #{ty}")
end
return TYPE_INT16_T
when /\Auint16_t(?:\s+\w+)?\z/
unless Fiddle.const_defined?(:TYPE_INT16_T)
raise(RuntimeError, "unsupported type: #{ty}")
end
return -TYPE_INT16_T
when /\Aint32_t(?:\s+\w+)?\z/
unless Fiddle.const_defined?(:TYPE_INT32_T)
raise(RuntimeError, "unsupported type: #{ty}")
end
return TYPE_INT32_T
when /\Auint32_t(?:\s+\w+)?\z/
unless Fiddle.const_defined?(:TYPE_INT32_T)
raise(RuntimeError, "unsupported type: #{ty}")
end
return -TYPE_INT32_T
when /\Aint64_t(?:\s+\w+)?\z/
unless Fiddle.const_defined?(:TYPE_INT64_T)
raise(RuntimeError, "unsupported type: #{ty}")
end
return TYPE_INT64_T
when /\Auint64_t(?:\s+\w+)?\z/
unless Fiddle.const_defined?(:TYPE_INT64_T)
raise(RuntimeError, "unsupported type: #{ty}")
end
return -TYPE_INT64_T
when /\Afloat(?:\s+\w+)?\z/
return TYPE_FLOAT
when /^double(?:\s+\w+)?$/
when /\Adouble(?:\s+\w+)?\z/
return TYPE_DOUBLE
when /^size_t(?:\s+\w+)?$/
when /\Asize_t(?:\s+\w+)?\z/
return TYPE_SIZE_T
when /^ssize_t(?:\s+\w+)?$/
when /\Assize_t(?:\s+\w+)?\z/
return TYPE_SSIZE_T
when /^ptrdiff_t(?:\s+\w+)?$/
when /\Aptrdiff_t(?:\s+\w+)?\z/
return TYPE_PTRDIFF_T
when /^intptr_t(?:\s+\w+)?$/
when /\Aintptr_t(?:\s+\w+)?\z/
return TYPE_INTPTR_T
when /^uintptr_t(?:\s+\w+)?$/
when /\Auintptr_t(?:\s+\w+)?\z/
return TYPE_UINTPTR_T
when /\*/, /\[[\s\d]*\]/
return TYPE_VOIDP
when "..."
return TYPE_VARIADIC
else
ty = ty.split(' ', 2)[0]
if( tymap[ty] )
@ -186,7 +251,7 @@ module Fiddle
def split_arguments(arguments, sep=',')
return [] if arguments.strip == 'void'
arguments.scan(/([\w\*\s]+\(\*\w*\)\(.*?\)|[\w\*\s\[\]]+)(?:#{sep}\s*|$)/).collect {|m| m[0]}
arguments.scan(/([\w\*\s]+\(\*\w*\)\(.*?\)|[\w\*\s\[\]]+|\.\.\.)(?:#{sep}\s*|\z)/).collect {|m| m[0]}
end
def compact(signature)

Просмотреть файл

@ -10,6 +10,11 @@ module Fiddle
# The name of this function
attr_reader :name
# Whether GVL is needed to call this function
def need_gvl?
@need_gvl
end
# The integer memory location of this function
def to_i
ptr.to_i

Просмотреть файл

@ -4,15 +4,72 @@ require 'fiddle/value'
require 'fiddle/pack'
module Fiddle
# C struct shell
# A base class for objects representing a C structure
class CStruct
include Enumerable
# accessor to Fiddle::CStructEntity
def CStruct.entity_class
CStructEntity
end
def each
return enum_for(__function__) unless block_given?
self.class.members.each do |name,|
yield(self[name])
end
end
def each_pair
return enum_for(__function__) unless block_given?
self.class.members.each do |name,|
yield(name, self[name])
end
end
def to_h
hash = {}
each_pair do |name, value|
hash[name] = unstruct(value)
end
hash
end
def replace(another)
if another.nil?
self.class.members.each do |name,|
self[name] = nil
end
elsif another.respond_to?(:each_pair)
another.each_pair do |name, value|
self[name] = value
end
else
another.each do |name, value|
self[name] = value
end
end
self
end
private
def unstruct(value)
case value
when CStruct
value.to_h
when Array
value.collect do |v|
unstruct(v)
end
else
value
end
end
end
# C union shell
# A base class for objects representing a C union
class CUnion
# accessor to Fiddle::CUnionEntity
def CUnion.entity_class
@ -27,10 +84,14 @@ module Fiddle
def initialize(ptr, type, initial_values)
@ptr = ptr
@type = type
@align = PackInfo::ALIGN_MAP[type]
@size = Fiddle::PackInfo::SIZE_MAP[type]
@pack_format = Fiddle::PackInfo::PACK_MAP[type]
super(initial_values.collect { |v| unsigned_value(v, type) })
@is_struct = @type.respond_to?(:entity_class)
if @is_struct
super(initial_values)
else
@size = Fiddle::PackInfo::SIZE_MAP[type]
@pack_format = Fiddle::PackInfo::PACK_MAP[type]
super(initial_values.collect { |v| unsigned_value(v, type) })
end
end
def to_ptr
@ -42,8 +103,12 @@ module Fiddle
raise IndexError, 'index %d outside of array bounds 0...%d' % [index, size]
end
to_ptr[index * @size, @size] = [value].pack(@pack_format)
super(index, value)
if @is_struct
self[index].replace(value)
else
to_ptr[index * @size, @size] = [value].pack(@pack_format)
super(index, value)
end
end
end
@ -62,7 +127,7 @@ module Fiddle
# Fiddle::Importer#struct and Fiddle::Importer#union wrap this functionality in an
# easy-to-use manner.
#
# Example:
# Examples:
#
# require 'fiddle/struct'
# require 'fiddle/cparser'
@ -73,6 +138,17 @@ module Fiddle
#
# MyStruct = Fiddle::CStructBuilder.create(Fiddle::CUnion, types, members)
#
# MyStruct.malloc(Fiddle::RUBY_FREE) do |obj|
# ...
# end
#
# obj = MyStruct.malloc(Fiddle::RUBY_FREE)
# begin
# ...
# ensure
# obj.call_free
# end
#
# obj = MyStruct.malloc
# begin
# ...
@ -82,45 +158,78 @@ module Fiddle
#
def create(klass, types, members)
new_class = Class.new(klass){
define_method(:initialize){|addr|
@entity = klass.entity_class.new(addr, types)
define_method(:initialize){|addr, func = nil|
if addr.is_a?(self.class.entity_class)
@entity = addr
else
@entity = self.class.entity_class.new(addr, types, func)
end
@entity.assign_names(members)
}
define_method(:[]) { |*args| @entity.send(:[], *args) }
define_method(:[]=) { |*args| @entity.send(:[]=, *args) }
define_method(:to_ptr){ @entity }
define_method(:to_i){ @entity.to_i }
define_singleton_method(:types) { types }
define_singleton_method(:members) { members }
members.each{|name|
name = name[0] if name.is_a?(Array) # name is a nested struct
next if method_defined?(name)
define_method(name){ @entity[name] }
define_method(name + "="){|val| @entity[name] = val }
}
entity_class = klass.entity_class
alignment = entity_class.alignment(types)
size = entity_class.size(types)
define_singleton_method(:alignment) { alignment }
define_singleton_method(:size) { size }
define_singleton_method(:malloc) do |func=nil, &block|
if block
entity_class.malloc(types, func, size) do |entity|
block.call(new(entity))
end
else
new(entity_class.malloc(types, func, size))
end
end
}
size = klass.entity_class.size(types)
new_class.module_eval(<<-EOS, __FILE__, __LINE__+1)
def new_class.size()
#{size}
end
def new_class.malloc()
addr = Fiddle.malloc(#{size})
new(addr)
end
EOS
return new_class
end
module_function :create
end
# A C struct wrapper
# A pointer to a C structure
class CStructEntity < Fiddle::Pointer
include PackInfo
include ValueUtil
def CStructEntity.alignment(types)
max = 1
types.each do |type, count = 1|
if type.respond_to?(:entity_class)
n = type.alignment
else
n = ALIGN_MAP[type]
end
max = n if n > max
end
max
end
# Allocates a C struct with the +types+ provided.
#
# See Fiddle::Pointer.malloc for memory management issues.
def CStructEntity.malloc(types, func = nil)
addr = Fiddle.malloc(CStructEntity.size(types))
CStructEntity.new(addr, types, func)
def CStructEntity.malloc(types, func = nil, size = size(types), &block)
if block_given?
super(size, func) do |struct|
struct.set_ctypes types
yield struct
end
else
struct = super(size, func)
struct.set_ctypes types
struct
end
end
# Returns the offset for the packed sizes for the given +types+.
@ -136,9 +245,15 @@ module Fiddle
max_align = types.map { |type, count = 1|
last_offset = offset
align = PackInfo::ALIGN_MAP[type]
if type.respond_to?(:entity_class)
align = type.alignment
type_size = type.size
else
align = PackInfo::ALIGN_MAP[type]
type_size = PackInfo::SIZE_MAP[type]
end
offset = PackInfo.align(last_offset, align) +
(PackInfo::SIZE_MAP[type] * count)
(type_size * count)
align
}.max
@ -152,13 +267,37 @@ module Fiddle
#
# See also Fiddle::Pointer.new
def initialize(addr, types, func = nil)
if func && addr.is_a?(Pointer) && addr.free
raise ArgumentError, 'free function specified on both underlying struct Pointer and when creating a CStructEntity - who do you want to free this?'
end
set_ctypes(types)
super(addr, @size, func)
end
# Set the names of the +members+ in this C struct
def assign_names(members)
@members = members
@members = []
@nested_structs = {}
members.each_with_index do |member, index|
if member.is_a?(Array) # nested struct
member_name = member[0]
struct_type, struct_count = @ctypes[index]
if struct_count.nil?
struct = struct_type.new(to_i + @offset[index])
else
structs = struct_count.times.map do |i|
struct_type.new(to_i + @offset[index] + i * struct_type.size)
end
struct = StructArray.new(to_i + @offset[index],
struct_type,
structs)
end
@nested_structs[member_name] = struct
else
member_name = member
end
@members << member_name
end
end
# Calculates the offsets and sizes for the given +types+ in the struct.
@ -169,12 +308,18 @@ module Fiddle
max_align = types.map { |type, count = 1|
orig_offset = offset
align = ALIGN_MAP[type]
if type.respond_to?(:entity_class)
align = type.alignment
type_size = type.size
else
align = ALIGN_MAP[type]
type_size = SIZE_MAP[type]
end
offset = PackInfo.align(orig_offset, align)
@offset << offset
offset += (SIZE_MAP[type] * count)
offset += (type_size * count)
align
}.max
@ -203,7 +348,13 @@ module Fiddle
end
ty = @ctypes[idx]
if( ty.is_a?(Array) )
r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1])
if ty.first.respond_to?(:entity_class)
return @nested_structs[name]
else
r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1])
end
elsif ty.respond_to?(:entity_class)
return @nested_structs[name]
else
r = super(@offset[idx], SIZE_MAP[ty.abs])
end
@ -243,6 +394,24 @@ module Fiddle
def []=(*args)
return super(*args) if args.size > 2
name, val = *args
name = name.to_s if name.is_a?(Symbol)
nested_struct = @nested_structs[name]
if nested_struct
if nested_struct.is_a?(StructArray)
if val.nil?
nested_struct.each do |s|
s.replace(nil)
end
else
val.each_with_index do |v, i|
nested_struct[i] = v
end
end
else
nested_struct.replace(val)
end
return val
end
idx = @members.index(name)
if( idx.nil? )
raise(ArgumentError, "no such member: #{name}")
@ -261,23 +430,16 @@ module Fiddle
end
end
undef_method :size=
def to_s() # :nodoc:
super(@size)
end
end
# A C union wrapper
# A pointer to a C union
class CUnionEntity < CStructEntity
include PackInfo
# Allocates a C union the +types+ provided.
#
# See Fiddle::Pointer.malloc for memory management issues.
def CUnionEntity.malloc(types, func=nil)
addr = Fiddle.malloc(CUnionEntity.size(types))
CUnionEntity.new(addr, types, func)
end
# Returns the size needed for the union with the given +types+.
#
# Fiddle::CUnionEntity.size(
@ -287,7 +449,11 @@ module Fiddle
# Fiddle::TYPE_VOIDP ]) #=> 8
def CUnionEntity.size(types)
types.map { |type, count = 1|
PackInfo::SIZE_MAP[type] * count
if type.respond_to?(:entity_class)
type.size * count
else
PackInfo::SIZE_MAP[type] * count
end
}.max
end
@ -300,4 +466,3 @@ module Fiddle
end
end
end

Просмотреть файл

@ -1,3 +1,3 @@
module Fiddle
VERSION = "1.0.2"
VERSION = "1.0.4"
end

254
ext/fiddle/memory_view.c Normal file
Просмотреть файл

@ -0,0 +1,254 @@
#include <stdbool.h>
#include <ruby/ruby.h>
#ifdef HAVE_RUBY_MEMORY_VIEW_H
# include <ruby/memory_view.h>
#endif
#if SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
# define INTPTR2NUM LL2NUM
# define UINTPTR2NUM ULL2NUM
#elif SIZEOF_INTPTR_T == SIZEOF_LONG
# define INTPTR2NUM LONG2NUM
# define UINTPTR2NUM ULONG2NUM
#else
# define INTPTR2NUM INT2NUM
# define UINTPTR2NUM UINT2NUM
#endif
#include <fiddle.h>
#ifdef FIDDLE_MEMORY_VIEW
VALUE rb_cMemoryView = Qnil;
struct memview_data {
rb_memory_view_t view;
rb_memory_view_item_component_t *members;
size_t n_members;
};
static void
fiddle_memview_mark(void *ptr)
{
const struct memview_data *data = ptr;
rb_gc_mark(data->view.obj);
}
static void
fiddle_memview_free(void *ptr)
{
struct memview_data *data = ptr;
rb_memory_view_release(&data->view);
if (data->members)
xfree(data->members);
xfree(ptr);
}
static size_t
fiddle_memview_memsize(const void *ptr)
{
const struct memview_data *data = ptr;
return sizeof(*data) + sizeof(rb_memory_view_item_component_t)*data->n_members + (size_t)data->view.len;
}
static const rb_data_type_t fiddle_memview_data_type = {
"fiddle/memory_view",
{fiddle_memview_mark, fiddle_memview_free, fiddle_memview_memsize,},
};
static VALUE
rb_fiddle_memview_s_allocate(VALUE klass)
{
struct memview_data *data;
VALUE obj = TypedData_Make_Struct(klass, struct memview_data, &fiddle_memview_data_type, data);
data->view.obj = Qnil;
data->members = NULL;
data->n_members = 0;
return obj;
}
static VALUE
rb_fiddle_memview_initialize(VALUE obj, VALUE target)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
if (!rb_memory_view_get(target, &data->view, 0)) {
rb_raise(rb_eArgError, "Unable to get a memory view from %+"PRIsVALUE, target);
}
return Qnil;
}
static VALUE
rb_fiddle_memview_get_obj(VALUE obj)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
return data->view.obj;
}
static VALUE
rb_fiddle_memview_get_length(VALUE obj)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
if (NIL_P(data->view.obj)) return Qnil;
return SSIZET2NUM(data->view.len);
}
static VALUE
rb_fiddle_memview_get_readonly(VALUE obj)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
if (NIL_P(data->view.obj)) return Qnil;
return data->view.readonly ? Qtrue : Qfalse;
}
static VALUE
rb_fiddle_memview_get_format(VALUE obj)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
if (NIL_P(data->view.obj)) return Qnil;
return data->view.format == NULL ? Qnil : rb_str_new_cstr(data->view.format);
}
static VALUE
rb_fiddle_memview_get_item_size(VALUE obj)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
if (NIL_P(data->view.obj)) return Qnil;
return SSIZET2NUM(data->view.item_size);
}
static VALUE
rb_fiddle_memview_get_ndim(VALUE obj)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
if (NIL_P(data->view.obj)) return Qnil;
return SSIZET2NUM(data->view.ndim);
}
static VALUE
rb_fiddle_memview_get_shape(VALUE obj)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
if (NIL_P(data->view.obj)) return Qnil;
if (data->view.shape == NULL) return Qnil;
const ssize_t ndim = data->view.ndim;
VALUE shape = rb_ary_new_capa(ndim);
ssize_t i;
for (i = 0; i < ndim; ++i) {
rb_ary_push(shape, SSIZET2NUM(data->view.shape[i]));
}
return shape;
}
static VALUE
rb_fiddle_memview_get_strides(VALUE obj)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
if (NIL_P(data->view.obj)) return Qnil;
if (data->view.strides == NULL) return Qnil;
const ssize_t ndim = data->view.ndim;
VALUE strides = rb_ary_new_capa(ndim);
ssize_t i;
for (i = 0; i < ndim; ++i) {
rb_ary_push(strides, SSIZET2NUM(data->view.strides[i]));
}
return strides;
}
static VALUE
rb_fiddle_memview_get_sub_offsets(VALUE obj)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
if (NIL_P(data->view.obj)) return Qnil;
if (data->view.sub_offsets == NULL) return Qnil;
const ssize_t ndim = data->view.ndim;
VALUE sub_offsets = rb_ary_new_capa(ndim);
ssize_t i;
for (i = 0; i < ndim; ++i) {
rb_ary_push(sub_offsets, SSIZET2NUM(data->view.sub_offsets[i]));
}
return sub_offsets;
}
static VALUE
rb_fiddle_memview_aref(int argc, VALUE *argv, VALUE obj)
{
struct memview_data *data;
TypedData_Get_Struct(obj, struct memview_data, &fiddle_memview_data_type, data);
if (NIL_P(data->view.obj)) return Qnil;
const ssize_t ndim = data->view.ndim;
if (argc != ndim) {
rb_raise(rb_eIndexError, "wrong number of index (%d for %"PRIdSIZE")", argc, ndim);
}
VALUE indices_v = 0;
ssize_t *indices = ALLOCV_N(ssize_t, indices_v, ndim);
ssize_t i;
for (i = 0; i < ndim; ++i) {
ssize_t x = NUM2SSIZET(argv[i]);
indices[i] = x;
}
uint8_t *ptr = rb_memory_view_get_item_pointer(&data->view, indices);
ALLOCV_END(indices_v);
if (data->view.format == NULL) {
return INT2FIX(*ptr);
}
if (!data->members) {
const char *err;
if (rb_memory_view_parse_item_format(data->view.format, &data->members, &data->n_members, &err) < 0) {
rb_raise(rb_eRuntimeError, "Unable to recognize item format at %"PRIdSIZE" in \"%s\"",
err - data->view.format, data->view.format);
}
}
return rb_memory_view_extract_item_members(ptr, data->members, data->n_members);
}
void
Init_fiddle_memory_view(void)
{
rb_cMemoryView = rb_define_class_under(mFiddle, "MemoryView", rb_cObject);
rb_define_alloc_func(rb_cMemoryView, rb_fiddle_memview_s_allocate);
rb_define_method(rb_cMemoryView, "initialize", rb_fiddle_memview_initialize, 1);
rb_define_method(rb_cMemoryView, "obj", rb_fiddle_memview_get_obj, 0);
rb_define_method(rb_cMemoryView, "length", rb_fiddle_memview_get_length, 0);
rb_define_method(rb_cMemoryView, "readonly?", rb_fiddle_memview_get_readonly, 0);
rb_define_method(rb_cMemoryView, "format", rb_fiddle_memview_get_format, 0);
rb_define_method(rb_cMemoryView, "item_size", rb_fiddle_memview_get_item_size, 0);
rb_define_method(rb_cMemoryView, "ndim", rb_fiddle_memview_get_ndim, 0);
rb_define_method(rb_cMemoryView, "shape", rb_fiddle_memview_get_shape, 0);
rb_define_method(rb_cMemoryView, "strides", rb_fiddle_memview_get_strides, 0);
rb_define_method(rb_cMemoryView, "sub_offsets", rb_fiddle_memview_get_sub_offsets, 0);
rb_define_method(rb_cMemoryView, "[]", rb_fiddle_memview_aref, -1);
}
#endif /* FIDDLE_MEMORY_VIEW */

Просмотреть файл

@ -2,8 +2,14 @@
* $Id$
*/
#include <stdbool.h>
#include <ruby/ruby.h>
#include <ruby/io.h>
#ifdef HAVE_RUBY_MEMORY_VIEW_H
# include <ruby/memory_view.h>
#endif
#include <ctype.h>
#include <fiddle.h>
@ -24,6 +30,7 @@ struct ptr_data {
void *ptr;
long size;
freefunc_t free;
bool freed;
VALUE wrap[2];
};
@ -57,14 +64,19 @@ fiddle_ptr_mark(void *ptr)
}
static void
fiddle_ptr_free(void *ptr)
fiddle_ptr_free_ptr(void *ptr)
{
struct ptr_data *data = ptr;
if (data->ptr) {
if (data->free) {
(*(data->free))(data->ptr);
}
if (data->ptr && data->free && !data->freed) {
data->freed = true;
(*(data->free))(data->ptr);
}
}
static void
fiddle_ptr_free(void *ptr)
{
fiddle_ptr_free_ptr(ptr);
xfree(ptr);
}
@ -80,6 +92,38 @@ static const rb_data_type_t fiddle_ptr_data_type = {
{fiddle_ptr_mark, fiddle_ptr_free, fiddle_ptr_memsize,},
};
#ifdef FIDDLE_MEMORY_VIEW
static struct ptr_data *
fiddle_ptr_check_memory_view(VALUE obj)
{
struct ptr_data *data;
TypedData_Get_Struct(obj, struct ptr_data, &fiddle_ptr_data_type, data);
if (data->ptr == NULL || data->size == 0) return NULL;
return data;
}
static int
fiddle_ptr_memory_view_available_p(VALUE obj)
{
return fiddle_ptr_check_memory_view(obj) != NULL;
}
static int
fiddle_ptr_get_memory_view(VALUE obj, rb_memory_view_t *view, int flags)
{
struct ptr_data *data = fiddle_ptr_check_memory_view(obj);
rb_memory_view_init_as_byte_array(view, obj, data->ptr, data->size, true);
return 1;
}
static const rb_memory_view_entry_t fiddle_ptr_memory_view_entry = {
fiddle_ptr_get_memory_view,
NULL,
fiddle_ptr_memory_view_available_p
};
#endif
static VALUE
rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
{
@ -89,6 +133,7 @@ rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
val = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
data->ptr = ptr;
data->free = func;
data->freed = false;
data->size = size;
return val;
@ -101,13 +146,13 @@ rb_fiddle_ptr_new(void *ptr, long size, freefunc_t func)
}
static VALUE
rb_fiddle_ptr_malloc(long size, freefunc_t func)
rb_fiddle_ptr_malloc(VALUE klass, long size, freefunc_t func)
{
void *ptr;
ptr = ruby_xmalloc((size_t)size);
memset(ptr,0,(size_t)size);
return rb_fiddle_ptr_new(ptr, size, func);
return rb_fiddle_ptr_new2(klass, ptr, size, func);
}
static void *
@ -140,6 +185,7 @@ rb_fiddle_ptr_s_allocate(VALUE klass)
data->ptr = 0;
data->size = 0;
data->free = 0;
data->freed = false;
return obj;
}
@ -191,17 +237,31 @@ rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
return Qnil;
}
static VALUE
rb_fiddle_ptr_call_free(VALUE self);
/*
* call-seq:
* Fiddle::Pointer.malloc(size, freefunc = nil) => fiddle pointer instance
* Fiddle::Pointer.malloc(size, freefunc) { |pointer| ... } => ...
*
* == 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)
* ...
*
* # Manual freeing
* # Only manually freeing
* pointer = Fiddle::Pointer.malloc(size)
* begin
* ...
@ -214,13 +274,16 @@ rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
* ...
*
* Allocate +size+ bytes of memory and associate it with an optional
* +freefunc+ that will be called when the pointer is garbage collected.
* +freefunc+ must be an address pointing to a function or an instance of
* +Fiddle::Function+. Using +freefunc+ may lead to unlimited memory being
* allocated before any is freed as the native memory the pointer references
* does not contribute to triggering the Ruby garbage collector. Consider
* manually freeing the memory as illustrated above. You cannot combine
* the techniques as this may lead to a double-free.
* +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+.
*/
static VALUE
rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
@ -242,10 +305,17 @@ rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
rb_bug("rb_fiddle_ptr_s_malloc");
}
obj = rb_fiddle_ptr_malloc(s,f);
obj = rb_fiddle_ptr_malloc(klass, s,f);
if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
return obj;
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;
}
}
/*
@ -370,6 +440,34 @@ rb_fiddle_ptr_free_get(VALUE self)
return rb_fiddle_new_function(address, arg_types, ret_type);
}
/*
* call-seq: call_free => nil
*
* Call the free function for this pointer. Calling more than once will do
* nothing. Does nothing if there is no free function attached.
*/
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;
}
/*
* call-seq: freed? => bool
*
* Returns if the free function for this pointer has been called.
*/
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;
}
/*
* call-seq:
*
@ -711,6 +809,8 @@ Init_fiddle_pointer(void)
rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
rb_define_method(rb_cPointer, "free", rb_fiddle_ptr_free_get, 0);
rb_define_method(rb_cPointer, "call_free", rb_fiddle_ptr_call_free, 0);
rb_define_method(rb_cPointer, "freed?", rb_fiddle_ptr_freed_p, 0);
rb_define_method(rb_cPointer, "to_i", rb_fiddle_ptr_to_i, 0);
rb_define_method(rb_cPointer, "to_int", rb_fiddle_ptr_to_i, 0);
rb_define_method(rb_cPointer, "to_value", rb_fiddle_ptr_to_value, 0);
@ -732,6 +832,10 @@ Init_fiddle_pointer(void)
rb_define_method(rb_cPointer, "size", rb_fiddle_ptr_size_get, 0);
rb_define_method(rb_cPointer, "size=", rb_fiddle_ptr_size_set, 1);
#ifdef FIDDLE_MEMORY_VIEW
rb_memory_view_register(rb_cPointer, &fiddle_ptr_memory_view_entry);
#endif
/* Document-const: NULL
*
* A NULL pointer

Просмотреть файл

@ -1,11 +0,0 @@
--- libffi-3.2.1/src/closures.c 2014-11-08 21:47:24.000000000 +0900
+++ libffi-3.2.1/src/closures.c 2020-05-26 19:09:26.334088215 +0900
@@ -26,7 +26,7 @@
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
-#if defined __linux__ && !defined _GNU_SOURCE
+#if (defined __linux__ || defined __CYGWIN__) && !defined _GNU_SOURCE
#define _GNU_SOURCE 1
#endif

Просмотреть файл

@ -43,35 +43,123 @@ module Fiddle
end
def test_set_ctypes
union = CStructEntity.malloc [TYPE_INT, TYPE_LONG], Fiddle::RUBY_FREE
union.assign_names %w[int long]
CStructEntity.malloc([TYPE_INT, TYPE_LONG], Fiddle::RUBY_FREE) do |struct|
struct.assign_names %w[int long]
# this test is roundabout because the stored ctypes are not accessible
union['long'] = 1
union['int'] = 2
# this test is roundabout because the stored ctypes are not accessible
struct['long'] = 1
struct['int'] = 2
assert_equal 1, union['long']
assert_equal 2, union['int']
assert_equal 1, struct['long']
assert_equal 2, struct['int']
end
end
def test_aref_pointer_array
team = CStructEntity.malloc([[TYPE_VOIDP, 2]], Fiddle::RUBY_FREE)
team.assign_names(["names"])
alice = Fiddle::Pointer.malloc(6, Fiddle::RUBY_FREE)
alice[0, 6] = "Alice\0"
bob = Fiddle::Pointer.malloc(4, Fiddle::RUBY_FREE)
bob[0, 4] = "Bob\0"
team["names"] = [alice, bob]
assert_equal(["Alice", "Bob"], team["names"].map(&:to_s))
CStructEntity.malloc([[TYPE_VOIDP, 2]], Fiddle::RUBY_FREE) do |team|
team.assign_names(["names"])
Fiddle::Pointer.malloc(6, Fiddle::RUBY_FREE) do |alice|
alice[0, 6] = "Alice\0"
Fiddle::Pointer.malloc(4, Fiddle::RUBY_FREE) do |bob|
bob[0, 4] = "Bob\0"
team["names"] = [alice, bob]
assert_equal(["Alice", "Bob"], team["names"].map(&:to_s))
end
end
end
end
def test_aref_pointer
user = CStructEntity.malloc([TYPE_VOIDP], Fiddle::RUBY_FREE)
user.assign_names(["name"])
alice = Fiddle::Pointer.malloc(6, Fiddle::RUBY_FREE)
alice[0, 6] = "Alice\0"
user["name"] = alice
assert_equal("Alice", user["name"].to_s)
CStructEntity.malloc([TYPE_VOIDP], Fiddle::RUBY_FREE) do |user|
user.assign_names(["name"])
Fiddle::Pointer.malloc(6, Fiddle::RUBY_FREE) do |alice|
alice[0, 6] = "Alice\0"
user["name"] = alice
assert_equal("Alice", user["name"].to_s)
end
end
end
def test_new_double_free
types = [TYPE_INT]
Pointer.malloc(CStructEntity.size(types), Fiddle::RUBY_FREE) do |pointer|
assert_raise ArgumentError do
CStructEntity.new(pointer, types, Fiddle::RUBY_FREE)
end
end
end
def test_malloc_block
escaped_struct = nil
returned = CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE) do |struct|
assert_equal Fiddle::SIZEOF_INT, struct.size
assert_equal Fiddle::RUBY_FREE, struct.free.to_i
escaped_struct = struct
:returned
end
assert_equal :returned, returned
assert escaped_struct.freed?
end
def test_malloc_block_no_free
assert_raise ArgumentError do
CStructEntity.malloc([TYPE_INT]) { |struct| }
end
end
def test_free
struct = CStructEntity.malloc([TYPE_INT])
begin
assert_nil struct.free
ensure
Fiddle.free struct
end
end
def test_free_with_func
struct = CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE)
refute struct.freed?
struct.call_free
assert struct.freed?
struct.call_free # you can safely run it again
assert struct.freed?
GC.start # you can safely run the GC routine
assert struct.freed?
end
def test_free_with_no_func
struct = CStructEntity.malloc([TYPE_INT])
refute struct.freed?
struct.call_free
refute struct.freed?
struct.call_free # you can safely run it again
refute struct.freed?
end
def test_freed?
struct = CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE)
refute struct.freed?
struct.call_free
assert struct.freed?
end
def test_null?
struct = CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE)
refute struct.null?
end
def test_size
CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE) do |struct|
assert_equal Fiddle::SIZEOF_INT, struct.size
end
end
def test_size=
CStructEntity.malloc([TYPE_INT], Fiddle::RUBY_FREE) do |struct|
assert_raise NoMethodError do
struct.size = 1
end
end
end
end
end if defined?(Fiddle)

Просмотреть файл

@ -21,15 +21,16 @@ module Fiddle
end
def test_set_ctypes
union = CUnionEntity.malloc [TYPE_INT, TYPE_LONG], Fiddle::RUBY_FREE
union.assign_names %w[int long]
CUnionEntity.malloc([TYPE_INT, TYPE_LONG], Fiddle::RUBY_FREE) do |union|
union.assign_names %w[int long]
# this test is roundabout because the stored ctypes are not accessible
union['long'] = 1
assert_equal 1, union['long']
# this test is roundabout because the stored ctypes are not accessible
union['long'] = 1
assert_equal 1, union['long']
union['int'] = 1
assert_equal 1, union['int']
union['int'] = 1
assert_equal 1, union['int']
end
end
end
end if defined?(Fiddle)

Просмотреть файл

@ -2,6 +2,7 @@
begin
require_relative 'helper'
require 'fiddle/cparser'
require 'fiddle/import'
rescue LoadError
end
@ -68,6 +69,19 @@ module Fiddle
assert_equal(-TYPE_LONG, parse_ctype('DWORD', {"DWORD" => "unsigned long"}))
end
def expand_struct_types(types)
types.collect do |type|
case type
when Class
[expand_struct_types(type.types)]
when Array
[expand_struct_types([type[0]])[0][0], type[1]]
else
type
end
end
end
def test_struct_basic
assert_equal [[TYPE_INT, TYPE_CHAR], ['i', 'c']], parse_struct_signature(['int i', 'char c'])
end
@ -76,6 +90,93 @@ module Fiddle
assert_equal [[[TYPE_CHAR,80],[TYPE_INT,5]], ['buffer','x']], parse_struct_signature(['char buffer[80]', 'int[5] x'])
end
def test_struct_nested_struct
types, members = parse_struct_signature([
'int x',
{inner: ['int i', 'char c']},
])
assert_equal([[TYPE_INT, [[TYPE_INT, TYPE_CHAR]]],
['x', ['inner', ['i', 'c']]]],
[expand_struct_types(types),
members])
end
def test_struct_nested_defined_struct
inner = Fiddle::Importer.struct(['int i', 'char c'])
assert_equal([[TYPE_INT, inner],
['x', ['inner', ['i', 'c']]]],
parse_struct_signature([
'int x',
{inner: inner},
]))
end
def test_struct_double_nested_struct
types, members = parse_struct_signature([
'int x',
{
outer: [
'int y',
{inner: ['int i', 'char c']},
],
},
])
assert_equal([[TYPE_INT, [[TYPE_INT, [[TYPE_INT, TYPE_CHAR]]]]],
['x', ['outer', ['y', ['inner', ['i', 'c']]]]]],
[expand_struct_types(types),
members])
end
def test_struct_nested_struct_array
types, members = parse_struct_signature([
'int x',
{
'inner[2]' => [
'int i',
'char c',
],
},
])
assert_equal([[TYPE_INT, [[TYPE_INT, TYPE_CHAR], 2]],
['x', ['inner', ['i', 'c']]]],
[expand_struct_types(types),
members])
end
def test_struct_double_nested_struct_inner_array
types, members = parse_struct_signature(outer: [
'int x',
{
'inner[2]' => [
'int i',
'char c',
],
},
])
assert_equal([[[[TYPE_INT, [[TYPE_INT, TYPE_CHAR], 2]]]],
[['outer', ['x', ['inner', ['i', 'c']]]]]],
[expand_struct_types(types),
members])
end
def test_struct_double_nested_struct_outer_array
types, members = parse_struct_signature([
'int x',
{
'outer[2]' => {
inner: [
'int i',
'char c',
],
},
},
])
assert_equal([[TYPE_INT, [[[[TYPE_INT, TYPE_CHAR]]], 2]],
['x', ['outer', [['inner', ['i', 'c']]]]]],
[expand_struct_types(types),
members])
end
def test_struct_array_str
assert_equal [[[TYPE_CHAR,80],[TYPE_INT,5]], ['buffer','x']], parse_struct_signature('char buffer[80], int[5] x')
end
@ -179,6 +280,18 @@ module Fiddle
assert_equal [TYPE_VOIDP, TYPE_INT, TYPE_INT], args
end
def test_signature_variadic_arguments
unless Fiddle.const_defined?("TYPE_VARIADIC")
skip "libffi doesn't support variadic arguments"
end
assert_equal([
"printf",
TYPE_INT,
[TYPE_VOIDP, TYPE_VARIADIC],
],
parse_signature('int printf(const char *format, ...)'))
end
def test_signature_return_pointer
func, ret, args = parse_signature('void* malloc(size_t)')
assert_equal 'malloc', func

Просмотреть файл

@ -21,6 +21,17 @@ module Fiddle
assert_equal 'sin', func.name
end
def test_need_gvl?
libruby = Fiddle.dlopen(nil)
rb_str_dup = Function.new(libruby['rb_str_dup'],
[:voidp],
:voidp,
need_gvl: true)
assert(rb_str_dup.need_gvl?)
assert_equal('Hello',
Fiddle.dlunwrap(rb_str_dup.call(Fiddle.dlwrap('Hello'))))
end
def test_argument_errors
assert_raise(TypeError) do
Function.new(@libm['sin'], TYPE_DOUBLE, TYPE_DOUBLE)
@ -111,8 +122,7 @@ module Fiddle
n1 = f.call(nil, 0, msec)
n2 = th.value
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
delta = EnvUtil.apply_timeout_scale(180)
assert_in_delta(msec, t1 - t0, delta, 'slept amount of time')
assert_in_delta(msec, t1 - t0, 180, 'slept amount of time')
assert_equal(0, n1, perror("poll(2) in main-thread"))
assert_equal(0, n2, perror("poll(2) in sub-thread"))
end

Просмотреть файл

@ -36,6 +36,29 @@ module Fiddle
"char c",
"unsigned char buff[7]",
]
StructNestedStruct = struct [
{
"vertices[2]" => {
position: ["float x", "float y", "float z"],
texcoord: ["float u", "float v"]
},
object: ["int id", "void *user_data"],
},
"int id"
]
UnionNestedStruct = union [
{
keyboard: [
'unsigned int state',
'char key'
],
mouse: [
'unsigned int button',
'unsigned short x',
'unsigned short y'
]
}
]
CallCallback = bind("void call_callback(void*, void*)"){ | ptr1, ptr2|
f = Function.new(ptr1.to_i, [TYPE_VOIDP], TYPE_VOID)
@ -56,22 +79,18 @@ module Fiddle
def test_struct_memory_access()
# check memory operations performed directly on struct
my_struct = Fiddle::Importer.struct(['int id']).malloc
begin
Fiddle::Importer.struct(['int id']).malloc(Fiddle::RUBY_FREE) do |my_struct|
my_struct[0, Fiddle::SIZEOF_INT] = "\x01".b * Fiddle::SIZEOF_INT
assert_equal 0x01010101, my_struct.id
my_struct.id = 0
assert_equal "\x00".b * Fiddle::SIZEOF_INT, my_struct[0, Fiddle::SIZEOF_INT]
ensure
Fiddle.free my_struct.to_ptr
end
end
def test_struct_ptr_array_subscript_multiarg()
# check memory operations performed on struct#to_ptr
struct = Fiddle::Importer.struct([ 'int x' ]).malloc
begin
Fiddle::Importer.struct([ 'int x' ]).malloc(Fiddle::RUBY_FREE) do |struct|
ptr = struct.to_ptr
struct.x = 0x02020202
@ -79,35 +98,25 @@ module Fiddle
ptr[0, Fiddle::SIZEOF_INT] = "\x01".b * Fiddle::SIZEOF_INT
assert_equal 0x01010101, struct.x
ensure
Fiddle.free struct.to_ptr
end
end
def test_malloc()
s1 = LIBC::Timeval.malloc()
begin
s2 = LIBC::Timeval.malloc()
begin
LIBC::Timeval.malloc(Fiddle::RUBY_FREE) do |s1|
LIBC::Timeval.malloc(Fiddle::RUBY_FREE) do |s2|
refute_equal(s1.to_ptr.to_i, s2.to_ptr.to_i)
ensure
Fiddle.free s2.to_ptr
end
ensure
Fiddle.free s1.to_ptr
end
end
def test_sizeof()
assert_equal(SIZEOF_VOIDP, LIBC.sizeof("FILE*"))
assert_equal(LIBC::MyStruct.size(), LIBC.sizeof(LIBC::MyStruct))
my_struct = LIBC::MyStruct.malloc()
begin
LIBC::MyStruct.malloc(Fiddle::RUBY_FREE) do |my_struct|
assert_equal(LIBC::MyStruct.size(), LIBC.sizeof(my_struct))
ensure
Fiddle.free my_struct.to_ptr
end
assert_equal(SIZEOF_LONG_LONG, LIBC.sizeof("long long")) if defined?(SIZEOF_LONG_LONG)
assert_equal(LIBC::StructNestedStruct.size(), LIBC.sizeof(LIBC::StructNestedStruct))
end
Fiddle.constants.grep(/\ATYPE_(?!VOID|VARIADIC\z)(.*)/) do
@ -158,8 +167,7 @@ module Fiddle
end
def test_struct_array_assignment()
instance = Fiddle::Importer.struct(["unsigned int stages[3]"]).malloc
begin
Fiddle::Importer.struct(["unsigned int stages[3]"]).malloc(Fiddle::RUBY_FREE) do |instance|
instance.stages[0] = 1024
instance.stages[1] = 10
instance.stages[2] = 100
@ -170,39 +178,279 @@ module Fiddle
instance.to_ptr[0, 3 * Fiddle::SIZEOF_INT]
assert_raise(IndexError) { instance.stages[-1] = 5 }
assert_raise(IndexError) { instance.stages[3] = 5 }
ensure
Fiddle.free instance.to_ptr
end
end
def test_nested_struct_reusing_other_structs()
position_struct = Fiddle::Importer.struct(['float x', 'float y', 'float z'])
texcoord_struct = Fiddle::Importer.struct(['float u', 'float v'])
vertex_struct = Fiddle::Importer.struct(position: position_struct, texcoord: texcoord_struct)
mesh_struct = Fiddle::Importer.struct([
{
"vertices[2]" => vertex_struct,
object: [
"int id",
"void *user_data",
],
},
"int id",
])
assert_equal LIBC::StructNestedStruct.size, mesh_struct.size
keyboard_event_struct = Fiddle::Importer.struct(['unsigned int state', 'char key'])
mouse_event_struct = Fiddle::Importer.struct(['unsigned int button', 'unsigned short x', 'unsigned short y'])
event_union = Fiddle::Importer.union([{ keboard: keyboard_event_struct, mouse: mouse_event_struct}])
assert_equal LIBC::UnionNestedStruct.size, event_union.size
end
def test_nested_struct_alignment_is_not_its_size()
inner = Fiddle::Importer.struct(['int x', 'int y', 'int z', 'int w'])
outer = Fiddle::Importer.struct(['char a', { 'nested' => inner }, 'char b'])
outer.malloc(Fiddle::RUBY_FREE) do |instance|
offset = instance.to_ptr.instance_variable_get(:"@offset")
assert_equal Fiddle::SIZEOF_INT * 5, offset.last
assert_equal Fiddle::SIZEOF_INT * 6, outer.size
assert_equal instance.to_ptr.size, outer.size
end
end
def test_struct_nested_struct_members()
LIBC::StructNestedStruct.malloc(Fiddle::RUBY_FREE) do |s|
Fiddle::Pointer.malloc(24, Fiddle::RUBY_FREE) do |user_data|
s.vertices[0].position.x = 1
s.vertices[0].position.y = 2
s.vertices[0].position.z = 3
s.vertices[0].texcoord.u = 4
s.vertices[0].texcoord.v = 5
s.vertices[1].position.x = 6
s.vertices[1].position.y = 7
s.vertices[1].position.z = 8
s.vertices[1].texcoord.u = 9
s.vertices[1].texcoord.v = 10
s.object.id = 100
s.object.user_data = user_data
s.id = 101
assert_equal({
"vertices" => [
{
"position" => {
"x" => 1,
"y" => 2,
"z" => 3,
},
"texcoord" => {
"u" => 4,
"v" => 5,
},
},
{
"position" => {
"x" => 6,
"y" => 7,
"z" => 8,
},
"texcoord" => {
"u" => 9,
"v" => 10,
},
},
],
"object" => {
"id" => 100,
"user_data" => user_data,
},
"id" => 101,
},
s.to_h)
end
end
end
def test_union_nested_struct_members()
LIBC::UnionNestedStruct.malloc(Fiddle::RUBY_FREE) do |s|
s.keyboard.state = 100
s.keyboard.key = 101
assert_equal(100, s.mouse.button)
refute_equal( 0, s.mouse.x)
end
end
def test_struct_nested_struct_replace_array_element()
LIBC::StructNestedStruct.malloc(Fiddle::RUBY_FREE) do |s|
s.vertices[0].position.x = 5
vertex_struct = Fiddle::Importer.struct [{
position: ["float x", "float y", "float z"],
texcoord: ["float u", "float v"]
}]
vertex_struct.malloc(Fiddle::RUBY_FREE) do |vertex|
vertex.position.x = 100
s.vertices[0] = vertex
# make sure element was copied by value, but things like memory address
# should not be changed
assert_equal(100, s.vertices[0].position.x)
refute_equal(vertex.object_id, s.vertices[0].object_id)
refute_equal(vertex.to_ptr, s.vertices[0].to_ptr)
end
end
end
def test_struct_nested_struct_replace_array_element_nil()
LIBC::StructNestedStruct.malloc(Fiddle::RUBY_FREE) do |s|
s.vertices[0].position.x = 5
s.vertices[0] = nil
assert_equal({
"position" => {
"x" => 0.0,
"y" => 0.0,
"z" => 0.0,
},
"texcoord" => {
"u" => 0.0,
"v" => 0.0,
},
},
s.vertices[0].to_h)
end
end
def test_struct_nested_struct_replace_array_element_hash()
LIBC::StructNestedStruct.malloc(Fiddle::RUBY_FREE) do |s|
s.vertices[0] = {
position: {
x: 10,
y: 100,
}
}
assert_equal({
"position" => {
"x" => 10.0,
"y" => 100.0,
"z" => 0.0,
},
"texcoord" => {
"u" => 0.0,
"v" => 0.0,
},
},
s.vertices[0].to_h)
end
end
def test_struct_nested_struct_replace_entire_array()
LIBC::StructNestedStruct.malloc(Fiddle::RUBY_FREE) do |s|
vertex_struct = Fiddle::Importer.struct [{
position: ["float x", "float y", "float z"],
texcoord: ["float u", "float v"]
}]
vertex_struct.malloc(Fiddle::RUBY_FREE) do |same0|
vertex_struct.malloc(Fiddle::RUBY_FREE) do |same1|
same = [same0, same1]
same[0].position.x = 1; same[1].position.x = 6
same[0].position.y = 2; same[1].position.y = 7
same[0].position.z = 3; same[1].position.z = 8
same[0].texcoord.u = 4; same[1].texcoord.u = 9
same[0].texcoord.v = 5; same[1].texcoord.v = 10
s.vertices = same
assert_equal([
{
"position" => {
"x" => 1.0,
"y" => 2.0,
"z" => 3.0,
},
"texcoord" => {
"u" => 4.0,
"v" => 5.0,
},
},
{
"position" => {
"x" => 6.0,
"y" => 7.0,
"z" => 8.0,
},
"texcoord" => {
"u" => 9.0,
"v" => 10.0,
},
}
],
s.vertices.collect(&:to_h))
end
end
end
end
def test_struct_nested_struct_replace_entire_array_with_different_struct()
LIBC::StructNestedStruct.malloc(Fiddle::RUBY_FREE) do |s|
different_struct_same_size = Fiddle::Importer.struct [{
a: ['float i', 'float j', 'float k'],
b: ['float l', 'float m']
}]
different_struct_same_size.malloc(Fiddle::RUBY_FREE) do |different0|
different_struct_same_size.malloc(Fiddle::RUBY_FREE) do |different1|
different = [different0, different1]
different[0].a.i = 11; different[1].a.i = 16
different[0].a.j = 12; different[1].a.j = 17
different[0].a.k = 13; different[1].a.k = 18
different[0].b.l = 14; different[1].b.l = 19
different[0].b.m = 15; different[1].b.m = 20
s.vertices[0][0, s.vertices[0].class.size] = different[0].to_ptr
s.vertices[1][0, s.vertices[1].class.size] = different[1].to_ptr
assert_equal([
{
"position" => {
"x" => 11.0,
"y" => 12.0,
"z" => 13.0,
},
"texcoord" => {
"u" => 14.0,
"v" => 15.0,
},
},
{
"position" => {
"x" => 16.0,
"y" => 17.0,
"z" => 18.0,
},
"texcoord" => {
"u" => 19.0,
"v" => 20.0,
},
}
],
s.vertices.collect(&:to_h))
end
end
end
end
def test_struct()
s = LIBC::MyStruct.malloc()
begin
LIBC::MyStruct.malloc(Fiddle::RUBY_FREE) do |s|
s.num = [0,1,2,3,4]
s.c = ?a.ord
s.buff = "012345\377"
assert_equal([0,1,2,3,4], s.num)
assert_equal(?a.ord, s.c)
assert_equal([?0.ord,?1.ord,?2.ord,?3.ord,?4.ord,?5.ord,?\377.ord], s.buff)
ensure
Fiddle.free s.to_ptr
end
end
def test_gettimeofday()
if( defined?(LIBC.gettimeofday) )
timeval = LIBC::Timeval.malloc()
begin
timezone = LIBC::Timezone.malloc()
begin
LIBC::Timeval.malloc(Fiddle::RUBY_FREE) do |timeval|
LIBC::Timezone.malloc(Fiddle::RUBY_FREE) do |timezone|
LIBC.gettimeofday(timeval, timezone)
ensure
Fiddle.free timezone.to_ptr
end
cur = Time.now()
assert(cur.to_i - 2 <= timeval.tv_sec && timeval.tv_sec <= cur.to_i)
ensure
Fiddle.free timeval.to_ptr
end
end
end
@ -227,9 +475,5 @@ module Fiddle
r = LIBC.atof("12.34")
assert_includes(12.00..13.00, r)
end
def test_no_message_with_debug
assert_in_out_err(%w[--debug --disable=gems -rfiddle/import], 'p Fiddle::Importer', ['Fiddle::Importer'])
end
end
end if defined?(Fiddle)

Просмотреть файл

@ -0,0 +1,115 @@
# frozen_string_literal: true
begin
require_relative 'helper'
rescue LoadError
end
begin
require '-test-/memory_view'
rescue LoadError
end
module Fiddle
class TestMemoryView < TestCase
def setup
skip "MemoryView is unavailable" unless defined? Fiddle::MemoryView
end
def test_null_ptr
assert_raise(ArgumentError) do
MemoryView.new(Fiddle::NULL)
end
end
def test_memory_view_from_unsupported_obj
obj = Object.new
assert_raise(ArgumentError) do
MemoryView.new(obj)
end
end
def test_memory_view_from_pointer
str = Marshal.load(Marshal.dump("hello world"))
ptr = Pointer[str]
mview = MemoryView.new(ptr)
assert_same(ptr, mview.obj)
assert_equal(str.length, mview.length)
assert_equal(true, mview.readonly?)
assert_equal(nil, mview.format)
assert_equal(1, mview.item_size)
assert_equal(1, mview.ndim)
assert_equal(nil, mview.shape)
assert_equal(nil, mview.strides)
assert_equal(nil, mview.sub_offsets)
codes = str.codepoints
assert_equal(codes, (0...str.length).map {|i| mview[i] })
end
def test_memory_view_multi_dimensional
skip "MemoryViewTestUtils is unavailable" unless defined? MemoryViewTestUtils
buf = [ 1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12 ].pack("l!*")
shape = [3, 4]
md = MemoryViewTestUtils::MultiDimensionalView.new(buf, "l!", shape, nil)
mview = Fiddle::MemoryView.new(md)
assert_equal(buf.length, mview.length)
assert_equal("l!", mview.format)
assert_equal(Fiddle::SIZEOF_LONG, mview.item_size)
assert_equal(2, mview.ndim)
assert_equal(shape, mview.shape)
assert_equal([Fiddle::SIZEOF_LONG*4, Fiddle::SIZEOF_LONG], mview.strides)
assert_equal(nil, mview.sub_offsets)
assert_equal(1, mview[0, 0])
assert_equal(4, mview[0, 3])
assert_equal(6, mview[1, 1])
assert_equal(10, mview[2, 1])
end
def test_memory_view_multi_dimensional_with_strides
skip "MemoryViewTestUtils is unavailable" unless defined? MemoryViewTestUtils
buf = [ 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16 ].pack("l!*")
shape = [2, 8]
strides = [4*Fiddle::SIZEOF_LONG*2, Fiddle::SIZEOF_LONG*2]
md = MemoryViewTestUtils::MultiDimensionalView.new(buf, "l!", shape, strides)
mview = Fiddle::MemoryView.new(md)
assert_equal("l!", mview.format)
assert_equal(Fiddle::SIZEOF_LONG, mview.item_size)
assert_equal(buf.length, mview.length)
assert_equal(2, mview.ndim)
assert_equal(shape, mview.shape)
assert_equal(strides, mview.strides)
assert_equal(nil, mview.sub_offsets)
assert_equal(1, mview[0, 0])
assert_equal(5, mview[0, 2])
assert_equal(9, mview[1, 0])
assert_equal(15, mview[1, 3])
end
def test_memory_view_multi_dimensional_with_multiple_members
skip "MemoryViewTestUtils is unavailable" unless defined? MemoryViewTestUtils
buf = [ 1, 2, 3, 4, 5, 6, 7, 8,
-1, -2, -3, -4, -5, -6, -7, -8].pack("s*")
shape = [2, 4]
strides = [4*Fiddle::SIZEOF_SHORT*2, Fiddle::SIZEOF_SHORT*2]
md = MemoryViewTestUtils::MultiDimensionalView.new(buf, "ss", shape, strides)
mview = Fiddle::MemoryView.new(md)
assert_equal("ss", mview.format)
assert_equal(Fiddle::SIZEOF_SHORT*2, mview.item_size)
assert_equal(buf.length, mview.length)
assert_equal(2, mview.ndim)
assert_equal(shape, mview.shape)
assert_equal(strides, mview.strides)
assert_equal(nil, mview.sub_offsets)
assert_equal([1, 2], mview[0, 0])
assert_equal([5, 6], mview[0, 2])
assert_equal([-1, -2], mview[1, 0])
assert_equal([-7, -8], mview[1, 3])
end
end
end

Просмотреть файл

@ -32,6 +32,31 @@ module Fiddle
assert_equal free.to_i, ptr.free.to_i
end
def test_malloc_block
escaped_ptr = nil
returned = Pointer.malloc(10, Fiddle::RUBY_FREE) do |ptr|
assert_equal 10, ptr.size
assert_equal Fiddle::RUBY_FREE, ptr.free.to_i
escaped_ptr = ptr
:returned
end
assert_equal :returned, returned
assert escaped_ptr.freed?
end
def test_malloc_block_no_free
assert_raise ArgumentError do
Pointer.malloc(10) { |ptr| }
end
end
def test_malloc_subclass
subclass = Class.new(Pointer)
subclass.malloc(10, Fiddle::RUBY_FREE) do |ptr|
assert ptr.is_a?(subclass)
end
end
def test_to_str
str = Marshal.load(Marshal.dump("hello world"))
ptr = Pointer[str]
@ -84,17 +109,18 @@ module Fiddle
end
def test_to_ptr_io
buf = Pointer.malloc(10, Fiddle::RUBY_FREE)
File.open(__FILE__, 'r') do |f|
ptr = Pointer.to_ptr f
fread = Function.new(@libc['fread'],
[TYPE_VOIDP, TYPE_INT, TYPE_INT, TYPE_VOIDP],
TYPE_INT)
fread.call(buf.to_i, Fiddle::SIZEOF_CHAR, buf.size - 1, ptr.to_i)
end
Pointer.malloc(10, Fiddle::RUBY_FREE) do |buf|
File.open(__FILE__, 'r') do |f|
ptr = Pointer.to_ptr f
fread = Function.new(@libc['fread'],
[TYPE_VOIDP, TYPE_INT, TYPE_INT, TYPE_VOIDP],
TYPE_INT)
fread.call(buf.to_i, Fiddle::SIZEOF_CHAR, buf.size - 1, ptr.to_i)
end
File.open(__FILE__, 'r') do |f|
assert_equal f.read(9), buf.to_s
File.open(__FILE__, 'r') do |f|
assert_equal f.read(9), buf.to_s
end
end
end
@ -170,27 +196,48 @@ module Fiddle
assert_equal free.ptr, ptr.free.ptr
end
def test_free_with_func
ptr = Pointer.malloc(4, Fiddle::RUBY_FREE)
refute ptr.freed?
ptr.call_free
assert ptr.freed?
ptr.call_free # you can safely run it again
assert ptr.freed?
GC.start # you can safely run the GC routine
assert ptr.freed?
end
def test_free_with_no_func
ptr = Pointer.malloc(4)
refute ptr.freed?
ptr.call_free
refute ptr.freed?
ptr.call_free # you can safely run it again
refute ptr.freed?
end
def test_freed?
ptr = Pointer.malloc(4, Fiddle::RUBY_FREE)
refute ptr.freed?
ptr.call_free
assert ptr.freed?
end
def test_null?
ptr = Pointer.new(0)
assert ptr.null?
end
def test_size
ptr = Pointer.malloc(4)
begin
Pointer.malloc(4, Fiddle::RUBY_FREE) do |ptr|
assert_equal 4, ptr.size
ensure
Fiddle.free ptr
end
end
def test_size=
ptr = Pointer.malloc(4)
begin
Pointer.malloc(4, Fiddle::RUBY_FREE) do |ptr|
ptr.size = 10
assert_equal 10, ptr.size
ensure
Fiddle.free ptr
end
end