Skip to content

Commit

Permalink
Fix for STL containers static member and global variables
Browse files Browse the repository at this point in the history
For UTL languages. Previously a copy of the
STL container was made into a target language container when reading the
variable. Changes, such as adjusting an element or adding/erasing
elements, were made to the copy of the container rather the actual
underlying C++ container. Also applies to const reference STL static
members.

Issue swig#2745
  • Loading branch information
wsfulton committed Feb 18, 2024
1 parent f7761d7 commit f573a1c
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 2 deletions.
20 changes: 20 additions & 0 deletions CHANGES.current
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.2.1 (in progress)
===========================

2024-02-18: wsfulton
#2745 Fix for wrapping STL containers that are static member variables
or global variables (most scripting languages). Previously a copy of the
STL container was made into a target language container when reading the
variable. Changes, such as adjusting an element or adding/erasing
elements, were made to the copy of the container rather the actual
underlying C++ container. Also applies to const reference STL static
members.

If you really need the old behaviour, add in the typemap that provided
used to provide it. For example, for std::list< int > and
const std::list< int >&, use:

%typemap(varout,noblock=1,fragment="SWIG_" "Traits" "_" {std::list< int >})
std::list< int >, const std::list< int >& {
$result = swig::from(static_cast< std::list< int > >($1));
}

*** POTENTIAL INCOMPATIBILITY ***

2024-02-14: olly
SWIG now warns and ignores if %constant is used with an implicit
type which SWIG can't deduce.
Expand Down
14 changes: 14 additions & 0 deletions Examples/test-suite/li_std_vector.i
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,17 @@ int sum(int v) {
return v;
}
%}

// Variables
%inline %{
struct VariableHolder {
static std::vector<int> static_variable;
std::vector<int> instance_variable;
};
std::vector<int> VariableHolder::static_variable;
std::vector<int> global_variable;

void vector_append(std::vector<int>& vec, int val) {
vec.push_back(val);
}
%}
12 changes: 12 additions & 0 deletions Examples/test-suite/python/li_std_map_runme.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@
raise RuntimeError("iteritems")


# map global variable
li_std_map.populate(li_std_map.cvar.MyMap)
li_std_map.cvar.MyMap["eeeeee"] = 6
keys = " ".join([k for k in list(li_std_map.cvar.MyMap.keys())])
if keys != "a aa zzz xxxx aaaaa eeeeee":
raise RuntimeError("Keys are wrong or in wrong order: " + keys)

values = " ".join([str(v) for v in list(li_std_map.cvar.MyMap.values())])
if values != "1 2 3 4 5 6":
raise RuntimeError("Values are wrong or in wrong order: " + values)


slmap = li_std_map.StringLengthNumberMap()
li_std_map.populate(slmap)

Expand Down
24 changes: 24 additions & 0 deletions Examples/test-suite/python/li_std_vector_runme.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,27 @@
raise RuntimeError("Using None should result in a TypeError")
except TypeError:
pass


# Variables
vh = VariableHolder()
vector_append(vh.instance_variable, 10)
if vh.instance_variable[0] != 10:
raise RuntimeError("instance_variable check")
vh.instance_variable.clear()
if len(vh.instance_variable) != 0:
raise RuntimeError("instance_variable clear")

vector_append(cvar.VariableHolder_static_variable, 20)
if cvar.VariableHolder_static_variable[0] != 20:
raise RuntimeError("static_variable check")
cvar.VariableHolder_static_variable.clear()
if len(cvar.VariableHolder_static_variable) != 0:
raise RuntimeError("static_variable clear")

vector_append(cvar.global_variable, 30)
if cvar.global_variable[0] != 30:
raise RuntimeError("global_variable check")
cvar.global_variable.clear()
if len(cvar.global_variable) != 0:
raise RuntimeError("global_variable clear")
10 changes: 10 additions & 0 deletions Examples/test-suite/ruby/li_std_map_runme.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@
m.each_key { |k| swig_assert_equal("pm[#{k.inspect}]", "m[#{k.inspect}]", binding) }
EOF


Li_std_map::populate(Li_std_map.MyMap)
Li_std_map.MyMap["eeeeee"] = 6
swig_assert( "Li_std_map.MyMap['a'] == 1", binding )
swig_assert( "Li_std_map.MyMap['aa'] == 2", binding )
swig_assert( "Li_std_map.MyMap['zzz'] == 3", binding )
swig_assert( "Li_std_map.MyMap['xxxx'] == 4", binding )
swig_assert( "Li_std_map.MyMap['aaaaa'] == 5", binding )
swig_assert( "Li_std_map.MyMap['eeeeee'] == 6", binding )

mii = Li_std_map::IntIntMap.new

mii[1] = 1
Expand Down
17 changes: 17 additions & 0 deletions Examples/test-suite/ruby/li_std_vector_runme.rb
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,20 @@ def set_slice(i, length, expect_nil_expanded_elements)
lv = LanguageVector.new('crapola')
rescue
end

# Variables
vh = VariableHolder.new
vector_append(vh.instance_variable, 10)
swig_assert_equal("vh.instance_variable[0]", "10", binding)
vh.instance_variable.clear
swig_assert_equal("vh.instance_variable.empty?", "true", binding)

vector_append(VariableHolder.static_variable, 20)
swig_assert_equal("VariableHolder.static_variable[0]", "20", binding)
VariableHolder.static_variable.clear
swig_assert_equal("VariableHolder.static_variable.empty?", "true", binding)

vector_append(Li_std_vector::global_variable, 30)
swig_assert_equal("Li_std_vector::global_variable[0]", "30", binding)
Li_std_vector::global_variable.clear
swig_assert_equal("Li_std_vector::global_variable.empty?", "true", binding)
23 changes: 22 additions & 1 deletion Lib/typemaps/ptrtypes.swg
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,32 @@
%ptr_input_typemap(%arg(CheckCode),%arg(AsPtrMeth),%arg(AsPtrFrag),Type);
%enddef

/*---------------------------------------------------------------------
* typemap definition for types with from method for ptr types
* Same as typemaps_from but without varout typemap
*---------------------------------------------------------------------*/

%define %ptr_typemaps_from(FromMeth, FromFrag, Type...)
%value_out_typemap(%arg(FromMeth), %arg(FromFrag), Type);
/* No varout typemap */
%value_constcode_typemap(%arg(FromMeth), %arg(FromFrag), Type);
%value_directorin_typemap(%arg(FromMeth), %arg(FromFrag), Type);
%value_throws_typemap(%arg(FromMeth), %arg(FromFrag), Type);
%value_output_typemap(%arg(FromMeth), %arg(FromFrag), Type);
%enddef

/*---------------------------------------------------------------------
* typemap definition for types with asptr/from methods
*---------------------------------------------------------------------*/

%define %typemaps_asptrfrom(CheckCode, AsPtrMeth, FromMeth, AsPtrFrag, FromFrag, Type...)
%typemaps_asptr(%arg(CheckCode), %arg(AsPtrMeth), %arg(AsPtrFrag), Type)
%ptr_typemaps_from(%arg(FromMeth), %arg(FromFrag), Type);
%ptr_inout_typemap(Type);
%enddef

// Same as typemaps_asptrfrom but defines a varout typemap to wrap with value semantics instead of the default pointer semantics
%define %_typemaps_asptrfrom(CheckCode, AsPtrMeth, FromMeth, AsPtrFrag, FromFrag, Type...)
%typemaps_asptr(%arg(CheckCode), %arg(AsPtrMeth), %arg(AsPtrFrag), Type)
%typemaps_from(%arg(FromMeth), %arg(FromFrag), Type);
%ptr_inout_typemap(Type);
Expand All @@ -198,7 +219,7 @@
*---------------------------------------------------------------------*/

%define %typemaps_asptrfromn(CheckCode, Type...)
%typemaps_asptrfrom(%arg(CheckCode),
%_typemaps_asptrfrom(%arg(CheckCode),
%arg(SWIG_AsPtr(Type)),
%arg(SWIG_From(Type)),
%arg(SWIG_AsPtr_frag(Type)),
Expand Down
3 changes: 2 additions & 1 deletion Lib/typemaps/valtypes.swg
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@
/*---------------------------------------------------------------------
* typemap definition for types with from method
*---------------------------------------------------------------------*/

%define %typemaps_from(FromMeth, FromFrag, Type...)
%value_out_typemap(%arg(FromMeth), %arg(FromFrag), Type);
%value_varout_typemap(%arg(FromMeth), %arg(FromFrag), Type);
Expand All @@ -191,7 +192,7 @@


/*---------------------------------------------------------------------
* typemap definition for types with alval/from method
* typemap definition for types with asval/from method
*---------------------------------------------------------------------*/

%define %typemaps_asvalfrom(CheckCode, AsValMeth, FromMeth,
Expand Down

0 comments on commit f573a1c

Please sign in to comment.