Fix for STL containers static member and global variables

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 #2745
This commit is contained in:
William S Fulton 2024-02-18 13:27:00 +00:00
parent d82dc29c41
commit 747c3ff18a
8 changed files with 121 additions and 2 deletions

View File

@ -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-15: olly
Improve type deduction for enum values in expressions.

View File

@ -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);
}
%}

View File

@ -68,6 +68,18 @@ if [i for i in mii.items()] != [(1, 2)]:
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)

View File

@ -8,3 +8,27 @@ try:
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")

View File

@ -43,6 +43,16 @@ m.each_key { |k| pm[k] = m[k] }
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

View File

@ -260,3 +260,20 @@ begin
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)

View File

@ -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);
@ -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)),

View File

@ -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);
@ -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,