From 6085a9661edd6bbfbe0dbffd187afda8be8aefd0 Mon Sep 17 00:00:00 2001 From: Olly Betts Date: Mon, 8 May 2023 15:56:37 +1200 Subject: Initial support for std::string_view So far C#, Java, Lua and PHP are supported. Closes: #2540 See #1567 --- Examples/test-suite/common.mk | 1 + Examples/test-suite/cpp17_string_view.i | 112 +++++++++++++++++++++ .../test-suite/csharp/cpp17_string_view_runme.cs | 84 ++++++++++++++++ .../csharp/director_string_view_runme.cs | 52 ++++++++++ Examples/test-suite/director_string_view.i | 56 +++++++++++ .../test-suite/java/cpp17_string_view_runme.java | 92 +++++++++++++++++ .../java/director_string_view_runme.java | 55 ++++++++++ .../test-suite/lua/cpp17_string_view_runme.lua | 50 +++++++++ .../test-suite/php/cpp17_string_view_runme.php | 44 ++++++++ .../test-suite/php/director_string_view_runme.php | 34 +++++++ 10 files changed, 580 insertions(+) create mode 100644 Examples/test-suite/cpp17_string_view.i create mode 100644 Examples/test-suite/csharp/cpp17_string_view_runme.cs create mode 100644 Examples/test-suite/csharp/director_string_view_runme.cs create mode 100644 Examples/test-suite/director_string_view.i create mode 100644 Examples/test-suite/java/cpp17_string_view_runme.java create mode 100644 Examples/test-suite/java/director_string_view_runme.java create mode 100644 Examples/test-suite/lua/cpp17_string_view_runme.lua create mode 100644 Examples/test-suite/php/cpp17_string_view_runme.php create mode 100644 Examples/test-suite/php/director_string_view_runme.php (limited to 'Examples') diff --git a/Examples/test-suite/common.mk b/Examples/test-suite/common.mk index c781bd930..7b007a2ac 100644 --- a/Examples/test-suite/common.mk +++ b/Examples/test-suite/common.mk @@ -657,6 +657,7 @@ CPP17_TEST_CASES += \ cpp17_hex_floating_literals \ cpp17_nested_namespaces \ cpp17_nspace_nested_namespaces \ + cpp17_string_view \ cpp17_u8_char_literals \ # Broken C++17 test cases. diff --git a/Examples/test-suite/cpp17_string_view.i b/Examples/test-suite/cpp17_string_view.i new file mode 100644 index 000000000..864cc97eb --- /dev/null +++ b/Examples/test-suite/cpp17_string_view.i @@ -0,0 +1,112 @@ +%module cpp17_string_view +#if defined SWIGCSHARP || defined SWIGJAVA || defined SWIGLUA || defined SWIGPHP +%include + +// throw is invalid in C++17 and later, only SWIG to use it +#define TESTCASE_THROW1(T1) throw(T1) +%{ +#define TESTCASE_THROW1(T1) +%} + +%inline %{ + +std::string_view test_value(std::string_view x) { + return x; +} + +const std::string_view& test_const_reference(const std::string_view &x) { + return x; +} + +void test_const_reference_returning_void(const std::string_view &) { +} + +void test_const_reference_returning_void(const std::string_view &, int) { +} + +void test_pointer(std::string_view *x) { +} + +std::string_view *test_pointer_out() { + static std::string_view x = "x"; + return &x; +} + +void test_const_pointer(const std::string_view *x) { +} + +const std::string_view *test_const_pointer_out() { + static std::string_view x = "x"; + return &x; +} + +void test_reference(std::string_view &x) { +} + +std::string_view& test_reference_out() { + static std::string_view x = "test_reference_out message"; + return x; +} + +std::string_view test_reference_input(std::string_view &input) { + return input; +} + +void test_throw() TESTCASE_THROW1(std::string_view){ + static std::string_view x = "test_throw message"; + throw x; +} + +void test_const_reference_throw() TESTCASE_THROW1(const std::string_view &){ + static const std::string_view x = "test_const_reference_throw message"; + throw x; +} + +void test_pointer_throw() TESTCASE_THROW1(std::string_view *) { + throw new std::string_view("foo"); +} + +void test_const_pointer_throw() TESTCASE_THROW1(const std::string_view *) { + throw static_cast(new std::string_view("foo")); +} +%} + +#ifdef SWIGSCILAB +%rename(ConstStr) ConstMemberString; +%rename(ConstStaticStr) ConstStaticMemberString; +#endif + +%inline %{ +const std::string_view ConstGlobalString = "const global string"; + +struct Structure { + const std::string_view ConstMemberString; + static const std::string_view ConstStaticMemberString; + + Structure() : ConstMemberString("const member string") {} +}; +%} + +%{ + const std::string_view Structure::ConstStaticMemberString = "const static member string"; +%} + + +%inline %{ + std::string_view stdstring_empty() { + return std::string_view(); + } + + char *c_empty() { + return (char *)""; + } + + char *c_null() { + return 0; + } + + const char *get_null(const char *a) { + return a == 0 ? a : "non-null"; + } +%} +#endif diff --git a/Examples/test-suite/csharp/cpp17_string_view_runme.cs b/Examples/test-suite/csharp/cpp17_string_view_runme.cs new file mode 100644 index 000000000..eba25f4de --- /dev/null +++ b/Examples/test-suite/csharp/cpp17_string_view_runme.cs @@ -0,0 +1,84 @@ +using System; +using cpp17_string_viewNamespace; + +public class runme +{ + static void Main() + { + // Checking expected use of %typemap(in) std::string {} + cpp17_string_view.test_value("Fee"); + + // Checking expected result of %typemap(out) std::string {} + if (cpp17_string_view.test_value("Fi") != "Fi") + throw new Exception("Test 1 failed"); + + // Verify type-checking for %typemap(in) std::string {} + try { + cpp17_string_view.test_value(null); + throw new Exception("Test 2 failed"); + } catch (ArgumentNullException) { + } + + // Checking expected use of %typemap(in) const std::string & {} + cpp17_string_view.test_const_reference("Fo"); + + // Checking expected result of %typemap(out) const std::string& {} + if (cpp17_string_view.test_const_reference("Fum") != "Fum") + throw new Exception("Test 3 failed"); + + // Verify type-checking for %typemap(in) const std::string & {} + try { + cpp17_string_view.test_const_reference(null); + throw new Exception("Test 4 failed"); + } catch (ArgumentNullException) { + } + + // + // Input and output typemaps for pointers and non-const references to + // std::string are *not* supported; the following tests confirm + // that none of these cases are slipping through. + // + + SWIGTYPE_p_std__string_view stringPtr = null; + + stringPtr = cpp17_string_view.test_pointer_out(); + + cpp17_string_view.test_pointer(stringPtr); + + stringPtr = cpp17_string_view.test_const_pointer_out(); + + cpp17_string_view.test_const_pointer(stringPtr); + + stringPtr = cpp17_string_view.test_reference_out(); + + cpp17_string_view.test_reference(stringPtr); + + // Check throw exception specification + try { + cpp17_string_view.test_throw(); + throw new Exception("Test 5 failed"); + } catch (ApplicationException e) { + if (e.Message != "test_throw message") + throw new Exception("Test 5 string check: " + e.Message); + } + try { + cpp17_string_view.test_const_reference_throw(); + throw new Exception("Test 6 failed"); + } catch (ApplicationException e) { + if (e.Message != "test_const_reference_throw message") + throw new Exception("Test 6 string check: " + e.Message); + } + + // Global variables + if (cpp17_string_view.ConstGlobalString != "const global string") + throw new Exception("ConstGlobalString test"); + + // Member variables + Structure myStructure = new Structure(); + if (myStructure.ConstMemberString != "const member string") + throw new Exception("ConstMemberString test"); + + if (Structure.ConstStaticMemberString != "const static member string") + throw new Exception("ConstStaticMemberString test"); + } +} diff --git a/Examples/test-suite/csharp/director_string_view_runme.cs b/Examples/test-suite/csharp/director_string_view_runme.cs new file mode 100644 index 000000000..7060b28a8 --- /dev/null +++ b/Examples/test-suite/csharp/director_string_view_runme.cs @@ -0,0 +1,52 @@ +using System; +using director_string_viewNamespace; + +public class runme +{ + static void Main() + { + runme r = new runme(); + r.run(); + } + + void run() + { + String s; + + director_string_view_A c = new director_string_view_A("hi"); + for (int i=0; i<3; i++) { + s = c.call_get(i); + Object ii = i; + if (s != ii.ToString()) throw new Exception("director_string_view_A.get(" + i + ") failed. Got:" + s); + } + + director_string_view_B b = new director_string_view_B("hello"); + + s = b.call_get_first(); + if (s != "director_string_view_B.get_first") throw new Exception("call_get_first() failed"); + + s = b.call_get(0); + if (s != "director_string_view_B.get: hello") throw new Exception("get(0) failed"); + } +} + +class director_string_view_B : A { + public director_string_view_B(String first) : base(first) { + } + public override String get_first() { + return "director_string_view_B.get_first"; + } + + public override String get(int n) { + return "director_string_view_B.get: " + base.get(n); + } +} + +class director_string_view_A : A { + public director_string_view_A(String first) : base(first) { + } + public override String get(int n) { + Object nn = n; + return nn.ToString(); + } +} diff --git a/Examples/test-suite/director_string_view.i b/Examples/test-suite/director_string_view.i new file mode 100644 index 000000000..19c2dbf01 --- /dev/null +++ b/Examples/test-suite/director_string_view.i @@ -0,0 +1,56 @@ +%module(directors="1") director_string_view; + +#if defined SWIGCSHARP || defined SWIGJAVA || defined SWIGLUA || defined SWIGPHP + +%include std_string.i +%include std_string_view.i + +// Using thread unsafe wrapping +%warnfilter(SWIGWARN_TYPEMAP_THREAD_UNSAFE,SWIGWARN_TYPEMAP_DIRECTOROUT_PTR) A; + +%{ +#include +#include +#include +%} + +%feature("director") A; +%inline %{ + +struct A +{ + A(const std::string& first) + : m_strings(1, first) + {} + + virtual ~A() {} + + virtual std::string_view get_first() const + { return get(0); } + + virtual std::string_view get(int n) const + { return m_strings[n]; } + + virtual std::string_view call_get_first() const + { return get_first(); } + + virtual std::string_view call_get(int n) const + { return get(n); } + + virtual int string_length(std::string_view s) const + { return (int)s.size(); } + + + virtual void process_text(const char *text) + { + } + + void call_process_func() { process_text("hello"); } + +private: + std::vector m_strings; +}; + +%} + +#endif diff --git a/Examples/test-suite/java/cpp17_string_view_runme.java b/Examples/test-suite/java/cpp17_string_view_runme.java new file mode 100644 index 000000000..903970e39 --- /dev/null +++ b/Examples/test-suite/java/cpp17_string_view_runme.java @@ -0,0 +1,92 @@ +import cpp17_string_view.*; + +public class cpp17_string_view_runme { + + static { + try { + System.loadLibrary("cpp17_string_view"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void main(String argv[]) throws Throwable + { + // Checking expected use of %typemap(in) std::string_view {} + cpp17_string_view.test_value("Fee"); + + // Checking expected result of %typemap(out) std::string_view {} + if (!cpp17_string_view.test_value("Fi").equals("Fi")) + throw new RuntimeException("Test 1 failed"); + + // Verify type-checking for %typemap(in) std::string_view {} + try { + cpp17_string_view.test_value(null); + throw new RuntimeException("Test 2 failed"); + } catch (NullPointerException e) { + } + + // Checking expected use of %typemap(in) const std::string_view & {} + cpp17_string_view.test_const_reference("Fo"); + + // Checking expected result of %typemap(out) const std::string_view& {} + if (!cpp17_string_view.test_const_reference("Fum").equals("Fum")) + throw new RuntimeException("Test 3 failed"); + + // Verify type-checking for %typemap(in) const std::string_view & {} + try { + cpp17_string_view.test_const_reference(null); + throw new RuntimeException("Test 4 failed"); + } catch (NullPointerException e) { + } + + // + // Input and output typemaps for pointers and non-const references to + // std::string_view are *not* supported; the following tests confirm + // that none of these cases are slipping through. + // + + SWIGTYPE_p_std__string_view stringPtr = null; + + stringPtr = cpp17_string_view.test_pointer_out(); + + cpp17_string_view.test_pointer(stringPtr); + + stringPtr = cpp17_string_view.test_const_pointer_out(); + + cpp17_string_view.test_const_pointer(stringPtr); + + stringPtr = cpp17_string_view.test_reference_out(); + + cpp17_string_view.test_reference(stringPtr); + + // Check throw exception specification + try { + cpp17_string_view.test_throw(); + throw new Throwable("Test 5 failed"); + } catch (RuntimeException e) { + if (!e.getMessage().equals("test_throw message")) + throw new Exception("Test 5 string check: " + e.getMessage()); + } + try { + cpp17_string_view.test_const_reference_throw(); + throw new Throwable("Test 6 failed"); + } catch (RuntimeException e) { + if (!e.getMessage().equals("test_const_reference_throw message")) + throw new Exception("Test 6 string check: " + e.getMessage()); + } + + // Global variables + if (!cpp17_string_view.getConstGlobalString().equals("const global string")) + throw new Exception("ConstGlobalString test"); + + // Member variables + Structure myStructure = new Structure(); + if (!myStructure.getConstMemberString().equals("const member string")) + throw new Exception("ConstMemberString test"); + + if (!Structure.getConstStaticMemberString().equals("const static member string")) + throw new Exception("ConstStaticMemberString test"); + } +} diff --git a/Examples/test-suite/java/director_string_view_runme.java b/Examples/test-suite/java/director_string_view_runme.java new file mode 100644 index 000000000..7aabf7d96 --- /dev/null +++ b/Examples/test-suite/java/director_string_view_runme.java @@ -0,0 +1,55 @@ + +import director_string_view.*; + +public class director_string_view_runme { + + static { + try { + System.loadLibrary("director_string_view"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" + e); + System.exit(1); + } + } + + public static void main(String argv[]) { + + String s; + + director_string_view_A c = new director_string_view_A("hi"); + for (int i=0; i<3; i++) { + s = c.call_get(i); + if (!s.equals(Integer.valueOf(i).toString())) throw new RuntimeException("director_string_view_A.get(" + i + ") failed. Got:" + s); + } + + director_string_view_B b = new director_string_view_B("hello"); + + s = b.call_get_first(); + if (!s.equals("director_string_view_B.get_first")) throw new RuntimeException("call_get_first() failed"); + + s = b.call_get(0); + if (!s.equals("director_string_view_B.get: hello")) throw new RuntimeException("get(0) failed"); + } +} + +class director_string_view_B extends A { + public director_string_view_B(String first) { + super(first); + } + public String get_first() { + return "director_string_view_B.get_first"; + } + + public String get(int n) { + return "director_string_view_B.get: " + super.get(n); + } +} + +class director_string_view_A extends A { + public director_string_view_A(String first) { + super(first); + } + public String get(int n) { + return Integer.valueOf(n).toString(); + } +} diff --git a/Examples/test-suite/lua/cpp17_string_view_runme.lua b/Examples/test-suite/lua/cpp17_string_view_runme.lua new file mode 100644 index 000000000..b30d99273 --- /dev/null +++ b/Examples/test-suite/lua/cpp17_string_view_runme.lua @@ -0,0 +1,50 @@ +require("import") -- the import fn +import("cpp17_string_view") -- import lib + +for k,v in pairs(cpp17_string_view) do _G[k]=v end -- move to global + +-- catch "undefined" global variables +local env = _ENV -- Lua 5.2 +if not env then env = getfenv () end -- Lua 5.1 +setmetatable(env, {__index=function (t,i) error("undefined global variable `"..i.."'",2) end}) + +-- Checking expected use of %typemap(in) std::string_view {} +test_value("Fee") + +-- Checking expected result of %typemap(out) std::string_view {} +s=test_value("Fi") +assert(type(s)=="string" and s =="Fi") + +-- Checking expected use of %typemap(in) const std::string_view & {} +test_const_reference("Fo") + +-- Checking expected result of %typemap(out) const std::string_view& {} +s=test_const_reference("Fum") +assert(type(s)=="string" and s =="Fum") + +-- Input and output typemaps for pointers and non-const references to +-- std::string_view are *not* supported; the following tests confirm +-- that none of these cases are slipping through. + +stringPtr = test_pointer_out() + +test_pointer(stringPtr) + +stringPtr = test_const_pointer_out() + +test_const_pointer(stringPtr) + +stringPtr = test_reference_out() + +test_reference(stringPtr) + +-- Global variables +assert(cpp17_string_view.ConstGlobalString=="const global string") + +-- Member variables +myStructure = Structure() +assert(myStructure.ConstMemberString=="const member string") + +assert(Structure.ConstStaticMemberString=="const static member string") + +test_const_reference_returning_void("foo") diff --git a/Examples/test-suite/php/cpp17_string_view_runme.php b/Examples/test-suite/php/cpp17_string_view_runme.php new file mode 100644 index 000000000..5f756bb36 --- /dev/null +++ b/Examples/test-suite/php/cpp17_string_view_runme.php @@ -0,0 +1,44 @@ +ConstMemberString, "const member string", "ConstMemberString test"); + +check::equal(Structure::ConstStaticMemberString(), "const static member string", "ConstStaticMemberString test"); + +cpp17_string_view::test_const_reference_returning_void("foo"); + +check::done(); diff --git a/Examples/test-suite/php/director_string_view_runme.php b/Examples/test-suite/php/director_string_view_runme.php new file mode 100644 index 000000000..ae3c10d11 --- /dev/null +++ b/Examples/test-suite/php/director_string_view_runme.php @@ -0,0 +1,34 @@ +smem = "hello"; + } +} + +$b = new B("hello"); + +$b->get(0); +check::equal($b->get_first(),"hello world!", "get_first failed"); + +$b->call_process_func(); + +check::equal($b->smem, "hello", "smem failed"); + +check::done(); -- cgit v1.2.1