зеркало из https://github.com/github/ruby.git
Import fiddle-1.0.4 (#3860)
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:
Родитель
6b1d2de6cc
Коммит
9b0c36b390
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче