Merge branch 'director-unwrap-result'
* director-unwrap-result: Unwrap director classes only when returning a pointer or reference to an object
This commit is contained in:
commit
4a397869a2
9 changed files with 369 additions and 6 deletions
|
|
@ -218,6 +218,7 @@ CPP_TEST_CASES += \
|
||||||
director_smartptr \
|
director_smartptr \
|
||||||
director_thread \
|
director_thread \
|
||||||
director_unroll \
|
director_unroll \
|
||||||
|
director_unwrap_result \
|
||||||
director_using \
|
director_using \
|
||||||
director_using_member_scopes \
|
director_using_member_scopes \
|
||||||
director_void \
|
director_void \
|
||||||
|
|
|
||||||
82
Examples/test-suite/director_unwrap_result.i
Normal file
82
Examples/test-suite/director_unwrap_result.i
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
%module(directors="1") director_unwrap_result
|
||||||
|
|
||||||
|
%warnfilter(SWIGWARN_TYPEMAP_DIRECTOROUT_PTR) Storage;
|
||||||
|
%warnfilter(SWIGWARN_TYPEMAP_DIRECTOROUT_PTR) StorageTmpl;
|
||||||
|
|
||||||
|
%feature("director") Element;
|
||||||
|
%feature("director") Storage;
|
||||||
|
%feature("director") StorageTmpl;
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
|
||||||
|
class Element {
|
||||||
|
Element* self;
|
||||||
|
Element** selfptr;
|
||||||
|
public:
|
||||||
|
Element() {
|
||||||
|
self = this;
|
||||||
|
selfptr = &self;
|
||||||
|
}
|
||||||
|
virtual ~Element() {}
|
||||||
|
Element **getPtrPtr() {
|
||||||
|
return &self;
|
||||||
|
}
|
||||||
|
Element ***getPtrPtrPtr() {
|
||||||
|
return &selfptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Storage {
|
||||||
|
public:
|
||||||
|
virtual ~Storage() {}
|
||||||
|
virtual Element **getIt() = 0;
|
||||||
|
Element getElement() {
|
||||||
|
return **getIt();
|
||||||
|
}
|
||||||
|
Element* const getElementPtr() {
|
||||||
|
return *getIt();
|
||||||
|
}
|
||||||
|
Element& getElementRef() {
|
||||||
|
return **getIt();
|
||||||
|
}
|
||||||
|
Element* const *getElementPtrPtr() {
|
||||||
|
return getIt();
|
||||||
|
}
|
||||||
|
Element *&getElementPtrRef() {
|
||||||
|
return *getIt();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T> class StorageTmpl {
|
||||||
|
public:
|
||||||
|
virtual ~StorageTmpl() {}
|
||||||
|
virtual T &getIt() = 0;
|
||||||
|
T getVal() {
|
||||||
|
return getIt();
|
||||||
|
}
|
||||||
|
T *getPtr() {
|
||||||
|
return &getIt();
|
||||||
|
}
|
||||||
|
T &getRef() {
|
||||||
|
return getIt();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%template(ElementStorage) StorageTmpl<Element>;
|
||||||
|
%template(ElementPtrStorage) StorageTmpl<Element *>;
|
||||||
|
%template(ElementPtrPtrStorage) StorageTmpl<Element *const *>;
|
||||||
|
|
||||||
|
%inline %{
|
||||||
|
|
||||||
|
template<class T> T getParam(T t) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%template(getIntParam) getParam<int>;
|
||||||
|
%template(getIntPtrParam) getParam<int*>;
|
||||||
|
%template(getElementPtrParam) getParam<Element *>;
|
||||||
|
|
||||||
|
|
@ -59,6 +59,7 @@ ifeq (node,$(JSENGINE))
|
||||||
director_basic.cpptest: GYP_CFLAGS = \"-Wno-ignored-qualifiers\"
|
director_basic.cpptest: GYP_CFLAGS = \"-Wno-ignored-qualifiers\"
|
||||||
enum_thorough.cpptest: GYP_CFLAGS = \"-Wno-ignored-qualifiers\"
|
enum_thorough.cpptest: GYP_CFLAGS = \"-Wno-ignored-qualifiers\"
|
||||||
member_funcptr_galore.cpptest: GYP_CFLAGS = \"-Wno-ignored-qualifiers\"
|
member_funcptr_galore.cpptest: GYP_CFLAGS = \"-Wno-ignored-qualifiers\"
|
||||||
|
director_unwrap_result.cpptest: GYP_CFLAGS = \"-Wno-ignored-qualifiers\"
|
||||||
|
|
||||||
setup_node = \
|
setup_node = \
|
||||||
test -d $* || mkdir $* && \
|
test -d $* || mkdir $* && \
|
||||||
|
|
|
||||||
106
Examples/test-suite/ruby/director_unwrap_result_runme.rb
Normal file
106
Examples/test-suite/ruby/director_unwrap_result_runme.rb
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
#
|
||||||
|
# This test checks the proper unwrapping of director objects before returning
|
||||||
|
# a pointer to the (wrapped) instance.
|
||||||
|
# Unwrapping must not happen for return-by-value and returning higher
|
||||||
|
# reference levels (pointer to pointer, reference to pointer, etc.), but this
|
||||||
|
# is already checked by the C++ compiler.
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'swig_assert'
|
||||||
|
|
||||||
|
require 'director_unwrap_result'
|
||||||
|
|
||||||
|
############################
|
||||||
|
# test with a regular (non-template) class
|
||||||
|
|
||||||
|
class MyElement < Director_unwrap_result::Element
|
||||||
|
end
|
||||||
|
|
||||||
|
class MyStorage < Director_unwrap_result::Storage
|
||||||
|
def initialize(e)
|
||||||
|
super()
|
||||||
|
@elem = e
|
||||||
|
end
|
||||||
|
def getIt
|
||||||
|
@elem.getPtrPtr
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
e = MyElement.new
|
||||||
|
s = MyStorage.new(e)
|
||||||
|
|
||||||
|
swig_assert_equal('s.getElement.class', 'Director_unwrap_result::Element', binding)
|
||||||
|
swig_assert('s.getElement != e', binding)
|
||||||
|
|
||||||
|
# this shows that the director class was unwrapped:
|
||||||
|
swig_assert_equal('s.getElementPtr.class', 'MyElement', binding)
|
||||||
|
swig_assert_equal('s.getElementPtr', 'e', binding)
|
||||||
|
|
||||||
|
# this shows that the director class was unwrapped:
|
||||||
|
swig_assert_equal('s.getElementRef.class', 'MyElement', binding)
|
||||||
|
swig_assert_equal('s.getElementRef', 'e', binding)
|
||||||
|
|
||||||
|
swig_assert_equal('s.getElementPtrPtr.class', 'SWIG::TYPE_p_p_Element', binding)
|
||||||
|
swig_assert_equal('s.getElementPtrPtr.class', 'SWIG::TYPE_p_p_Element', binding)
|
||||||
|
|
||||||
|
swig_assert_equal('s.getElementPtrRef.class', 'SWIG::TYPE_p_p_Element', binding)
|
||||||
|
swig_assert_equal('s.getElementPtrRef.class', 'SWIG::TYPE_p_p_Element', binding)
|
||||||
|
|
||||||
|
############################
|
||||||
|
# test with a template class
|
||||||
|
|
||||||
|
class MyElementStorage < Director_unwrap_result::ElementStorage
|
||||||
|
def initialize(e)
|
||||||
|
super()
|
||||||
|
@elem = e
|
||||||
|
end
|
||||||
|
def getIt
|
||||||
|
@elem
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MyElementPtrStorage < Director_unwrap_result::ElementPtrStorage
|
||||||
|
def initialize(e)
|
||||||
|
super()
|
||||||
|
@elem = e
|
||||||
|
end
|
||||||
|
def getIt
|
||||||
|
@elem.getPtrPtr
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MyElementPtrPtrStorage < Director_unwrap_result::ElementPtrPtrStorage
|
||||||
|
def initialize(e)
|
||||||
|
super()
|
||||||
|
@elem = e
|
||||||
|
end
|
||||||
|
def getIt
|
||||||
|
@elem.getPtrPtrPtr
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
e = MyElement.new
|
||||||
|
|
||||||
|
s = MyElementStorage.new(e)
|
||||||
|
swig_assert_equal('s.getVal.class', 'Director_unwrap_result::Element', binding)
|
||||||
|
swig_assert('s.getVal != e', binding)
|
||||||
|
# this shows that the director class was unwrapped:
|
||||||
|
swig_assert_equal('s.getPtr.class', 'MyElement', binding)
|
||||||
|
swig_assert_equal('s.getPtr', 'e', binding)
|
||||||
|
# this shows that the director class was unwrapped:
|
||||||
|
swig_assert_equal('s.getRef.class', 'MyElement', binding)
|
||||||
|
swig_assert_equal('s.getRef', 'e', binding)
|
||||||
|
|
||||||
|
s = MyElementPtrStorage.new(e)
|
||||||
|
# this shows that the director class was unwrapped:
|
||||||
|
swig_assert_equal('s.getVal.class', 'MyElement', binding)
|
||||||
|
swig_assert_equal('s.getVal', 'e', binding)
|
||||||
|
swig_assert_equal('s.getPtr.class', 'SWIG::TYPE_p_p_Element', binding)
|
||||||
|
swig_assert_equal('s.getRef.class', 'SWIG::TYPE_p_p_Element', binding)
|
||||||
|
|
||||||
|
s = MyElementPtrPtrStorage.new(e)
|
||||||
|
swig_assert_equal('s.getVal.class', 'SWIG::TYPE_p_p_Element', binding)
|
||||||
|
swig_assert_equal('s.getPtr.class', 'SWIG::TYPE_p_p_p_Element', binding)
|
||||||
|
swig_assert_equal('s.getRef.class', 'SWIG::TYPE_p_p_p_Element', binding)
|
||||||
|
|
||||||
|
|
@ -234,6 +234,95 @@ static void cparse_template_expand(Node *templnode, Node *n, String *tname, Stri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* cparse_fix_function_decl()
|
||||||
|
*
|
||||||
|
* Move the prefix of the "type" attribute (excluding any trailing qualifier)
|
||||||
|
* to the end of the "decl" attribute.
|
||||||
|
* Examples:
|
||||||
|
* decl="f().", type="p.q(const).char" => decl="f().p.", type="q(const).char"
|
||||||
|
* decl="f().p.", type="p.SomeClass" => decl="f().p.p.", type="SomeClass"
|
||||||
|
* decl="f().", type="r.q(const).p.int" => decl="f().r.q(const).p.", type="int"
|
||||||
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void cparse_fix_function_decl(String *name, SwigType *decl, SwigType *type) {
|
||||||
|
String *prefix;
|
||||||
|
int prefixLen;
|
||||||
|
SwigType* last;
|
||||||
|
|
||||||
|
/* The type's prefix is what potentially has to be moved to the end of 'decl' */
|
||||||
|
prefix = SwigType_prefix(type);
|
||||||
|
|
||||||
|
/* First some parts (qualifier and array) have to be removed from prefix
|
||||||
|
in order to remain in the 'type' attribute. */
|
||||||
|
last = SwigType_last(prefix);
|
||||||
|
while (last) {
|
||||||
|
if (SwigType_isqualifier(last) || SwigType_isarray(last)) {
|
||||||
|
/* Keep this part in the 'type' */
|
||||||
|
Delslice(prefix, Len(prefix) - Len(last), DOH_END);
|
||||||
|
Delete(last);
|
||||||
|
last = SwigType_last(prefix);
|
||||||
|
} else {
|
||||||
|
/* Done with processing prefix */
|
||||||
|
Delete(last);
|
||||||
|
last = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transfer prefix from the 'type' to the 'decl' attribute */
|
||||||
|
prefixLen = Len(prefix);
|
||||||
|
if (prefixLen > 0) {
|
||||||
|
Append(decl, prefix);
|
||||||
|
Delslice(type, 0, prefixLen);
|
||||||
|
if (template_debug) {
|
||||||
|
Printf(stdout, " change function '%s' to type='%s', decl='%s'\n",
|
||||||
|
name, type, decl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Delete(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* cparse_postprocess_expanded_template()
|
||||||
|
*
|
||||||
|
* This function postprocesses the given node after template expansion.
|
||||||
|
* Currently the only task to perform is fixing function decl and type attributes.
|
||||||
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void cparse_postprocess_expanded_template(Node *n) {
|
||||||
|
String *nodeType;
|
||||||
|
if (!n)
|
||||||
|
return;
|
||||||
|
nodeType = nodeType(n);
|
||||||
|
if (Getattr(n, "error"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Equal(nodeType, "cdecl")) {
|
||||||
|
/* A simple C declaration */
|
||||||
|
SwigType *d = Getattr(n, "decl");
|
||||||
|
if (d && SwigType_isfunction(d)) {
|
||||||
|
/* A function node */
|
||||||
|
SwigType *t = Getattr(n, "type");
|
||||||
|
if (t) {
|
||||||
|
String *name = Getattr(n, "name");
|
||||||
|
cparse_fix_function_decl(name, d, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Look for any children */
|
||||||
|
Node *cn = firstChild(n);
|
||||||
|
while (cn) {
|
||||||
|
cparse_postprocess_expanded_template(cn);
|
||||||
|
cn = nextSibling(cn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* partial_arg()
|
||||||
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static
|
static
|
||||||
String *partial_arg(String *s, String *p) {
|
String *partial_arg(String *s, String *p) {
|
||||||
char *c;
|
char *c;
|
||||||
|
|
@ -422,6 +511,8 @@ int Swig_cparse_template_expand(Node *n, String *rname, ParmList *tparms, Symtab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cparse_postprocess_expanded_template(n);
|
||||||
|
|
||||||
/* Patch bases */
|
/* Patch bases */
|
||||||
{
|
{
|
||||||
List *bases = Getattr(n, "baselist");
|
List *bases = Getattr(n, "baselist");
|
||||||
|
|
|
||||||
|
|
@ -3159,9 +3159,7 @@ public:
|
||||||
#if 1
|
#if 1
|
||||||
int unwrap = 0;
|
int unwrap = 0;
|
||||||
String *decl = Getattr(n, "decl");
|
String *decl = Getattr(n, "decl");
|
||||||
int is_pointer = SwigType_ispointer_return(decl);
|
if (SwigType_refptr_count_return(decl) == 1) {
|
||||||
int is_reference = SwigType_isreference_return(decl);
|
|
||||||
if (is_pointer || is_reference) {
|
|
||||||
String *type = Getattr(n, "type");
|
String *type = Getattr(n, "type");
|
||||||
//Node *classNode = Swig_methodclass(n);
|
//Node *classNode = Swig_methodclass(n);
|
||||||
//Node *module = Getattr(classNode, "module");
|
//Node *module = Getattr(classNode, "module");
|
||||||
|
|
|
||||||
|
|
@ -1880,9 +1880,7 @@ public:
|
||||||
*/
|
*/
|
||||||
bool unwrap = false;
|
bool unwrap = false;
|
||||||
String *decl = Getattr(n, "decl");
|
String *decl = Getattr(n, "decl");
|
||||||
int is_pointer = SwigType_ispointer_return(decl);
|
if (SwigType_refptr_count_return(decl) == 1) {
|
||||||
int is_reference = SwigType_isreference_return(decl);
|
|
||||||
if (is_pointer || is_reference) {
|
|
||||||
String *type = Getattr(n, "type");
|
String *type = Getattr(n, "type");
|
||||||
Node *parent = Swig_methodclass(n);
|
Node *parent = Swig_methodclass(n);
|
||||||
Node *modname = Getattr(parent, "module");
|
Node *modname = Getattr(parent, "module");
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,8 @@ extern "C" {
|
||||||
extern List *SwigType_split(const SwigType *t);
|
extern List *SwigType_split(const SwigType *t);
|
||||||
extern String *SwigType_pop(SwigType *t);
|
extern String *SwigType_pop(SwigType *t);
|
||||||
extern void SwigType_push(SwigType *t, String *s);
|
extern void SwigType_push(SwigType *t, String *s);
|
||||||
|
extern SwigType *SwigType_last(SwigType *t);
|
||||||
|
extern int SwigType_refptr_count_return(const SwigType *t);
|
||||||
extern List *SwigType_parmlist(const SwigType *p);
|
extern List *SwigType_parmlist(const SwigType *p);
|
||||||
extern String *SwigType_parm(const SwigType *p);
|
extern String *SwigType_parm(const SwigType *p);
|
||||||
extern String *SwigType_str(const SwigType *s, const_String_or_char_ptr id);
|
extern String *SwigType_str(const SwigType *s, const_String_or_char_ptr id);
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,90 @@ SwigType *SwigType_pop(SwigType *t) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* SwigType_last()
|
||||||
|
*
|
||||||
|
* Return the last element of the given (partial) type.
|
||||||
|
* For example:
|
||||||
|
* t: q(const).p.
|
||||||
|
* result: p.
|
||||||
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
SwigType *SwigType_last(SwigType *t) {
|
||||||
|
SwigType *result;
|
||||||
|
char *c;
|
||||||
|
char *last;
|
||||||
|
int sz = 0;
|
||||||
|
|
||||||
|
if (!t)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Find the last element */
|
||||||
|
c = Char(t);
|
||||||
|
last = 0;
|
||||||
|
while (*c) {
|
||||||
|
last = c;
|
||||||
|
sz = element_size(c);
|
||||||
|
c = c + sz;
|
||||||
|
if (*c == '.') {
|
||||||
|
c++;
|
||||||
|
sz++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract the last element */
|
||||||
|
if (last) {
|
||||||
|
result = NewStringWithSize(last, sz);
|
||||||
|
} else {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------------
|
||||||
|
* SwigType_refptr_count_return()
|
||||||
|
*
|
||||||
|
* Returns the number of pointer and reference indirections found in the given
|
||||||
|
* type. For functions this concerns the return type.
|
||||||
|
* For example:
|
||||||
|
* r.p. => 2
|
||||||
|
* q(const).p. => 1
|
||||||
|
* r.f(int).p.p. => 2
|
||||||
|
* f().p.q(const).p. => 2
|
||||||
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
int SwigType_refptr_count_return(const SwigType *t) {
|
||||||
|
char *c;
|
||||||
|
char *last;
|
||||||
|
int sz;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
if (!t)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
c = Char(t);
|
||||||
|
last = c;
|
||||||
|
while (*c) {
|
||||||
|
last = c;
|
||||||
|
sz = element_size(c);
|
||||||
|
c = c + sz;
|
||||||
|
if (*(c-1) == '.') {
|
||||||
|
if (((last[0] == 'p') || (last[0] == 'r')) && (last[1] == '.')) {
|
||||||
|
result++;
|
||||||
|
} else if (strncmp(last, "f(", 2) == 0) {
|
||||||
|
/* restart counter if this is a function type */
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*c == '.') {
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
* SwigType_parm()
|
* SwigType_parm()
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue