summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlly Betts <olly@survex.com>2023-05-08 15:56:37 +1200
committerOlly Betts <olly@survex.com>2023-05-08 15:56:37 +1200
commit6085a9661edd6bbfbe0dbffd187afda8be8aefd0 (patch)
tree747308c4a6a0008fe1ba2b5ab7b74b425b063f73
parent0fa2ab8945ff40e770045dd86ed0380c006643fc (diff)
downloadswig-6085a9661edd6bbfbe0dbffd187afda8be8aefd0.tar.gz
Initial support for std::string_view
So far C#, Java, Lua and PHP are supported. Closes: #2540 See #1567
-rw-r--r--CHANGES.current4
-rw-r--r--Doc/Manual/Contents.html1
-rw-r--r--Doc/Manual/Library.html54
-rw-r--r--Examples/test-suite/common.mk1
-rw-r--r--Examples/test-suite/cpp17_string_view.i112
-rw-r--r--Examples/test-suite/csharp/cpp17_string_view_runme.cs84
-rw-r--r--Examples/test-suite/csharp/director_string_view_runme.cs52
-rw-r--r--Examples/test-suite/director_string_view.i56
-rw-r--r--Examples/test-suite/java/cpp17_string_view_runme.java92
-rw-r--r--Examples/test-suite/java/director_string_view_runme.java55
-rw-r--r--Examples/test-suite/lua/cpp17_string_view_runme.lua50
-rw-r--r--Examples/test-suite/php/cpp17_string_view_runme.php44
-rw-r--r--Examples/test-suite/php/director_string_view_runme.php34
-rw-r--r--Lib/csharp/std_string_view.i113
-rw-r--r--Lib/java/std_string_view.i138
-rw-r--r--Lib/lua/std_string_view.i41
-rw-r--r--Lib/php/std_string_view.i69
-rw-r--r--Lib/swig.swg5
18 files changed, 994 insertions, 11 deletions
diff --git a/CHANGES.current b/CHANGES.current
index 4a4304545..8200b7d7a 100644
--- a/CHANGES.current
+++ b/CHANGES.current
@@ -8,6 +8,10 @@ Version 4.2.0 (in progress)
===========================
2023-05-08: olly
+ #1567 Add support for std::string_view (new in C++17) for C#, Java,
+ Lua and PHP.
+
+2023-05-08: olly
[PHP] #2544 Wrap overloaded method with both static and non-static
forms. We now wrap this as a non-static method in PHP, which means
the static form only callable via an object.
diff --git a/Doc/Manual/Contents.html b/Doc/Manual/Contents.html
index e78410af6..f3517ef9a 100644
--- a/Doc/Manual/Contents.html
+++ b/Doc/Manual/Contents.html
@@ -445,6 +445,7 @@
<li><a href="Library.html#Library_stl_cpp_library">STL/C++ library</a>
<ul>
<li><a href="Library.html#Library_std_string">std::string</a>
+<li><a href="Library.html#Library_std_string_view">std::string_view</a>
<li><a href="Library.html#Library_std_vector">std::vector</a>
<li><a href="Library.html#Library_stl_exceptions">STL exceptions</a>
<li><a href="Library.html#Library_std_shared_ptr">shared_ptr smart pointer</a>
diff --git a/Doc/Manual/Library.html b/Doc/Manual/Library.html
index f308c31f1..be262753a 100644
--- a/Doc/Manual/Library.html
+++ b/Doc/Manual/Library.html
@@ -30,6 +30,7 @@
<li><a href="#Library_stl_cpp_library">STL/C++ library</a>
<ul>
<li><a href="#Library_std_string">std::string</a>
+<li><a href="#Library_std_string_view">std::string_view</a>
<li><a href="#Library_std_vector">std::vector</a>
<li><a href="#Library_stl_exceptions">STL exceptions</a>
<li><a href="#Library_std_shared_ptr">shared_ptr smart pointer</a>
@@ -1450,14 +1451,15 @@ The following table shows which C++ classes are supported and the equivalent SWI
<tr> <td>std::multiset (C++11)</td> <td>multiset</td> <td>std_multiset.i</td> </tr>
<tr> <td>std::pair</td> <td>utility</td> <td>std_pair.i</td> </tr>
<tr> <td>std::set</td> <td>set</td> <td>std_set.i</td> </tr>
+<tr> <td>std::shared_ptr (C++11)</td> <td>shared_ptr</td> <td>std_shared_ptr.i</td> </tr>
<tr> <td>std::string</td> <td>string</td> <td>std_string.i</td> </tr>
+<tr> <td>std::string_view (C++17)</td> <td>string_view</td> <td>std_string_view.i</td> </tr>
<tr> <td>std::unordered_map (C++11)</td> <td>unordered_map</td> <td>std_unordered_map.i</td> </tr>
<tr> <td>std::unordered_multimap (C++11)</td> <td>unordered_multimap</td> <td>std_unordered_multimap.i</td> </tr>
<tr> <td>std::unordered_multiset (C++11)</td> <td>unordered_multiset</td> <td>std_unordered_multiset.i</td> </tr>
<tr> <td>std::unordered_set (C++11)</td> <td>unordered_set</td> <td>std_unordered_set.i</td> </tr>
<tr> <td>std::vector</td> <td>vector</td> <td>std_vector.i</td> </tr>
<tr> <td>std::wstring</td> <td>wstring</td> <td>std_wstring.i</td> </tr>
-<tr> <td>std::shared_ptr (C++11)</td> <td>shared_ptr</td> <td>std_shared_ptr.i</td> </tr>
</table>
@@ -1551,7 +1553,37 @@ void foo(string s, const String &amp;t); // std_string typemaps still applie
</pre>
</div>
-<H3><a name="Library_std_vector">12.4.2 std::vector</a></H3>
+<H3><a name="Library_std_string_view">12.4.2 std::string_view</a></H3>
+
+
+<p>
+The <tt>std_string_view.i</tt> library provides typemaps for converting C++17 <tt>std::string_view</tt>
+objects to and from strings in the target scripting language. For example:
+</p>
+
+<div class="code">
+<pre>
+%module example
+%include "std_string_view.i"
+
+std::string_view foo();
+void bar(std::string_view x);
+</pre>
+</div>
+
+<p>
+In the target language:
+</p>
+
+<div class="targetlang">
+<pre>
+x = foo(); # Returns a string object
+bar("Hello World"); # Pass string as std::string_view
+</pre>
+</div>
+
+
+<H3><a name="Library_std_vector">12.4.3 std::vector</a></H3>
<p>
@@ -1730,7 +1762,7 @@ if you want to make their head explode.
details and the public API exposed to the interpreter vary.
</p>
-<H3><a name="Library_stl_exceptions">12.4.3 STL exceptions</a></H3>
+<H3><a name="Library_stl_exceptions">12.4.4 STL exceptions</a></H3>
<p>
@@ -1780,10 +1812,10 @@ The <tt>%exception</tt> directive can be used by placing the following code befo
Any thrown STL exceptions will then be gracefully handled instead of causing a crash.
</p>
-<H3><a name="Library_std_shared_ptr">12.4.4 shared_ptr smart pointer</a></H3>
+<H3><a name="Library_std_shared_ptr">12.4.5 shared_ptr smart pointer</a></H3>
-<H4><a name="Library_shared_ptr_basics">12.4.4.1 shared_ptr basics</a></H4>
+<H4><a name="Library_shared_ptr_basics">12.4.5.1 shared_ptr basics</a></H4>
<p>
@@ -1879,7 +1911,7 @@ System.out.println(val1 + " " + val2);
</pre>
</div>
-<H4><a name="Library_shared_ptr_inheritance">12.4.4.2 shared_ptr and inheritance</a></H4>
+<H4><a name="Library_shared_ptr_inheritance">12.4.5.2 shared_ptr and inheritance</a></H4>
<p>
@@ -1970,7 +2002,7 @@ Adding the missing <tt>%shared_ptr</tt> macros will fix this:
</pre>
</div>
-<H4><a name="Library_shared_ptr_overloading">12.4.4.3 shared_ptr and method overloading</a></H4>
+<H4><a name="Library_shared_ptr_overloading">12.4.5.3 shared_ptr and method overloading</a></H4>
<p>
@@ -1992,7 +2024,7 @@ SWIG will choose to wrap just the first method by default.
For the interested reader, SWIG detects that they are equivalent types via the <a href=Typemaps.html#Typemaps_typecheck_pointer>typecheck typemaps</a> in the shared_ptr library.
</p>
-<H4><a name="Library_shared_ptr_templates">12.4.4.4 shared_ptr and templates</a></H4>
+<H4><a name="Library_shared_ptr_templates">12.4.5.4 shared_ptr and templates</a></H4>
<p>
@@ -2034,14 +2066,14 @@ The SWIG code below shows the required ordering:
</pre>
</div>
-<H4><a name="Library_shared_ptr_directors">12.4.4.5 shared_ptr and directors</a></H4>
+<H4><a name="Library_shared_ptr_directors">12.4.5.5 shared_ptr and directors</a></H4>
<p>
The languages that support shared_ptr also have support for using shared_ptr with directors.
</p>
-<H3><a name="Library_std_unique_ptr">12.4.5 unique_ptr smart pointer</a></H3>
+<H3><a name="Library_std_unique_ptr">12.4.6 unique_ptr smart pointer</a></H3>
<p>
@@ -2163,7 +2195,7 @@ in a "Cannot release ownership as memory is not owned" exception. For example, i
<b>Compatibility note:</b> Support for <tt>std::unique_ptr</tt> was added in SWIG-4.1.0.
</p>
-<H3><a name="Library_std_auto_ptr">12.4.6 auto_ptr smart pointer</a></H3>
+<H3><a name="Library_std_auto_ptr">12.4.7 auto_ptr smart pointer</a></H3>
<p>
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 <std_string_view.i>
+
+// 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<const std::string_view*>(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 <vector>
+#include <string>
+#include <string_view>
+%}
+
+%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<std::string> 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 @@
+<?php
+
+require "tests.php";
+
+# Checking expected use of %typemap(in) std::string_view {}
+cpp17_string_view::test_value("Fee");
+
+# Checking expected result of %typemap(out) std::string_view {}
+check::equal(cpp17_string_view::test_value("Fi"), "Fi", "Test 1");
+
+# 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& {}
+check::equal(cpp17_string_view::test_const_reference("Fum"), "Fum", "Test 3");
+
+# 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 = 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);
+
+// Global variables
+check::equal(ConstGlobalString_get(), "const global string", "ConstGlobalString test");
+
+// Member variables
+$myStructure = new Structure();
+check::equal($myStructure->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 @@
+<?php
+
+require "tests.php";
+
+// No new functions
+check::functions(array());
+// New classes
+check::classes(array('A'));
+// No new vars
+check::globals(array());
+
+class B extends A {
+ public $smem;
+
+ function get_first() {
+ return parent::get_first() . " world!";
+ }
+
+ function process_text($string) {
+ parent::process_text($string);
+ $this->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();
diff --git a/Lib/csharp/std_string_view.i b/Lib/csharp/std_string_view.i
new file mode 100644
index 000000000..b03c8461a
--- /dev/null
+++ b/Lib/csharp/std_string_view.i
@@ -0,0 +1,113 @@
+/* -----------------------------------------------------------------------------
+ * std_string_view.i
+ *
+ * Typemaps for std::string_view and const std::string_view&
+ * These are mapped to a C# String and are passed around by value.
+ *
+ * To use non-const std::string_view references use the following %apply. Note
+ * that they are passed by value.
+ * %apply const std::string_view & {std::string_view &};
+ * ----------------------------------------------------------------------------- */
+
+%{
+#include <string_view>
+#include <string>
+%}
+
+namespace std {
+
+%naturalvar string_view;
+
+class string_view;
+
+// string_view
+%typemap(ctype) string_view "const char *"
+%typemap(imtype) string_view "string"
+%typemap(cstype) string_view "string"
+
+%typemap(csdirectorin) string_view "$iminput"
+%typemap(csdirectorout) string_view "$cscall"
+
+%typemap(in, canthrow=1) string_view
+%{ if (!$input) {
+ SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "null string", 0);
+ return $null;
+ }
+ $1 = std::string_view($input); %}
+%typemap(out) string_view %{ $result = SWIG_csharp_string_callback(std::string($1).c_str()); %}
+
+%typemap(directorout, canthrow=1) string_view
+%{ if (!$input) {
+ SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "null string", 0);
+ return $null;
+ }
+ $result = std::string_view($input); %}
+
+%typemap(directorin) string_view %{ $input = std::string($1).c_str(); %}
+
+%typemap(csin) string_view "$csinput"
+%typemap(csout, excode=SWIGEXCODE) string_view {
+ string ret = $imcall;$excode
+ return ret;
+ }
+
+%typemap(typecheck) string_view = char *;
+
+%typemap(throws, canthrow=1) string_view
+%{ SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, std::string($1).c_str());
+ return $null; %}
+
+// const string_view &
+%typemap(ctype) const string_view & "const char *"
+%typemap(imtype) const string_view & "string"
+%typemap(cstype) const string_view & "string"
+
+%typemap(csdirectorin) const string_view & "$iminput"
+%typemap(csdirectorout) const string_view & "$cscall"
+
+%typemap(in, canthrow=1) const string_view &
+%{ if (!$input) {
+ SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "null string", 0);
+ return $null;
+ }
+ $*1_ltype $1_str($input);
+ $1 = &$1_str; %}
+%typemap(out) const string_view & %{ $result = SWIG_csharp_string_callback(std::string(*$1).c_str()); %}
+
+%typemap(csin) const string_view & "$csinput"
+%typemap(csout, excode=SWIGEXCODE) const string_view & {
+ string ret = $imcall;$excode
+ return ret;
+ }
+
+%typemap(directorout, canthrow=1, warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const string_view &
+%{ if (!$input) {
+ SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "null string", 0);
+ return $null;
+ }
+ /* possible thread/reentrant code problem */
+ static std::string $1_str;
+ $1_str = $input;
+ static $*1_ltype $1_strview;
+ $1_strview = $1_str;
+ $result = &$1_strview; %}
+
+%typemap(directorin) const string_view & %{ $input = std::string($1).c_str(); %}
+
+%typemap(csvarin, excode=SWIGEXCODE2) const string_view & %{
+ set {
+ $imcall;$excode
+ } %}
+%typemap(csvarout, excode=SWIGEXCODE2) const string_view & %{
+ get {
+ string ret = $imcall;$excode
+ return ret;
+ } %}
+
+%typemap(typecheck) const string_view & = char *;
+
+%typemap(throws, canthrow=1) const string_view &
+%{ SWIG_CSharpSetPendingException(SWIG_CSharpApplicationException, std::string($1).c_str());
+ return $null; %}
+
+}
diff --git a/Lib/java/std_string_view.i b/Lib/java/std_string_view.i
new file mode 100644
index 000000000..005b9c0f8
--- /dev/null
+++ b/Lib/java/std_string_view.i
@@ -0,0 +1,138 @@
+/* -----------------------------------------------------------------------------
+ * std_string_view.i
+ *
+ * Typemaps for std::string_view and const std::string_view&
+ * These are mapped to a Java String and are passed around by value.
+ *
+ * To use non-const std::string_view references use the following %apply. Note
+ * that they are passed by value.
+ * %apply const std::string_view & {std::string_view &};
+ * ----------------------------------------------------------------------------- */
+
+%{
+#include <string_view>
+#include <string>
+%}
+
+namespace std {
+
+%naturalvar string_view;
+
+class string_view;
+
+// string_view
+%typemap(jni) string_view "jstring"
+%typemap(jtype) string_view "String"
+%typemap(jstype) string_view "String"
+%typemap(javadirectorin) string_view "$jniinput"
+%typemap(javadirectorout) string_view "$javacall"
+
+%typemap(in) string_view
+%{ if(!$input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null string");
+ return $null;
+ }
+ const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
+ if (!$1_pstr) return $null;
+ $1 = std::string_view($1_pstr); %}
+
+/* std::string_view requires the string data to remain valid while the
+ * string_view is in use. */
+%typemap(freearg) string_view
+%{ jenv->ReleaseStringUTFChars($input, $1_pstr); %}
+
+%typemap(directorout,warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) string_view
+%{ if(!$input) {
+ if (!jenv->ExceptionCheck()) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null string");
+ }
+ return $null;
+ }
+ const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
+ if (!$1_pstr) return $null;
+ /* possible thread/reentrant code problem */
+ static std::string $1_str;
+ $1_str = $1_pstr;
+ $result = std::string_view($1_str);
+ jenv->ReleaseStringUTFChars($input, $1_pstr); %}
+
+/* std::string_view::data() isn't zero-byte terminated, but NewStringUTF()
+ * requires a zero byte so it seems we have to make a copy (ick). The
+ * cleanest way to do that seems to be via a temporary std::string.
+ */
+%typemap(directorin,descriptor="Ljava/lang/String;") string_view
+%{ $input = jenv->NewStringUTF(std::string($1).c_str());
+ Swig::LocalRefGuard $1_refguard(jenv, $input); %}
+
+%typemap(out) string_view
+%{ $result = jenv->NewStringUTF(std::string($1).c_str()); %}
+
+%typemap(javain) string_view "$javainput"
+
+%typemap(javaout) string_view {
+ return $jnicall;
+ }
+
+%typemap(typecheck) string_view = char *;
+
+%typemap(throws) string_view
+%{ SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, std::string($1).c_str());
+ return $null; %}
+
+// const string_view &
+%typemap(jni) const string_view & "jstring"
+%typemap(jtype) const string_view & "String"
+%typemap(jstype) const string_view & "String"
+%typemap(javadirectorin) const string_view & "$jniinput"
+%typemap(javadirectorout) const string_view & "$javacall"
+
+%typemap(in) const string_view &
+%{ if(!$input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null string");
+ return $null;
+ }
+ const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
+ if (!$1_pstr) return $null;
+ $*1_ltype $1_str($1_pstr);
+ $1 = &$1_str; %}
+
+/* std::string_view requires the string data to remain valid while the
+ * string_view is in use. */
+%typemap(freearg) const string_view &
+%{ jenv->ReleaseStringUTFChars($input, $1_pstr); %}
+
+%typemap(directorout,warning=SWIGWARN_TYPEMAP_THREAD_UNSAFE_MSG) const string_view &
+%{ if(!$input) {
+ SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null string");
+ return $null;
+ }
+ const char *$1_pstr = (const char *)jenv->GetStringUTFChars($input, 0);
+ if (!$1_pstr) return $null;
+ /* possible thread/reentrant code problem */
+ static std::string $1_str;
+ $1_str = $1_pstr;
+ static $*1_ltype $1_strview;
+ $1_strview = $1_str;
+ $result = &$1_str;
+ jenv->ReleaseStringUTFChars($input, $1_pstr); %}
+
+%typemap(directorin,descriptor="Ljava/lang/String;") const string_view &
+%{ $input = jenv->NewStringUTF(std::string($1).c_str());
+ Swig::LocalRefGuard $1_refguard(jenv, $input); %}
+
+%typemap(out) const string_view &
+%{ $result = jenv->NewStringUTF(std::string(*$1).c_str()); %}
+
+%typemap(javain) const string_view & "$javainput"
+
+%typemap(javaout) const string_view & {
+ return $jnicall;
+ }
+
+%typemap(typecheck) const string_view & = char *;
+
+%typemap(throws) const string_view &
+%{ SWIG_JavaThrowException(jenv, SWIG_JavaRuntimeException, std::string($1).c_str());
+ return $null; %}
+
+}
diff --git a/Lib/lua/std_string_view.i b/Lib/lua/std_string_view.i
new file mode 100644
index 000000000..f2a439eaa
--- /dev/null
+++ b/Lib/lua/std_string_view.i
@@ -0,0 +1,41 @@
+/* -----------------------------------------------------------------------------
+ * std_string_view.i
+ *
+ * std::string_view typemaps for LUA
+ * ----------------------------------------------------------------------------- */
+
+%{
+#include <string_view>
+%}
+
+namespace std {
+
+%naturalvar string_view;
+
+%typemap(in,checkfn="lua_isstring") string_view
+%{$1 = std::string_view(lua_tostring(L,$input),lua_rawlen(L,$input));%}
+
+%typemap(out) string_view
+%{ lua_pushlstring(L,$1.data(),$1.size()); SWIG_arg++;%}
+
+%typemap(in,checkfn="lua_isstring") const string_view& ($*1_ltype temp)
+%{temp = std::string_view(lua_tostring(L,$input),lua_rawlen(L,$input)); $1=&temp;%}
+
+%typemap(out) const string_view&
+%{ lua_pushlstring(L,$1->data(),$1->size()); SWIG_arg++;%}
+
+// for throwing of any kind of string_view, string_view ref's and string_view pointers
+// we convert all to lua strings
+%typemap(throws) string_view, string_view&, const string_view&
+%{ lua_pushlstring(L,$1.data(),$1.size()); SWIG_fail;%}
+
+%typemap(throws) string_view*, const string_view*
+%{ lua_pushlstring(L,$1->data(),$1->size()); SWIG_fail;%}
+
+%typecheck(SWIG_TYPECHECK_STRINGVIEW) string_view, const string_view& {
+ $1 = lua_isstring(L,$input);
+}
+
+class string_view;
+
+}
diff --git a/Lib/php/std_string_view.i b/Lib/php/std_string_view.i
new file mode 100644
index 000000000..7f53f9e22
--- /dev/null
+++ b/Lib/php/std_string_view.i
@@ -0,0 +1,69 @@
+/* -----------------------------------------------------------------------------
+ * std_string_view.i
+ *
+ * SWIG typemaps for std::string_view types
+ * ----------------------------------------------------------------------------- */
+
+%include <exception.i>
+
+%{
+#include <string_view>
+%}
+
+namespace std {
+
+ %naturalvar string_view;
+
+ class string_view;
+
+ %typemap(typecheck,precedence=SWIG_TYPECHECK_STRINGVIEW) string_view, const string_view& %{
+ $1 = (Z_TYPE($input) == IS_STRING) ? 1 : 0;
+ %}
+
+ %typemap(in, phptype="string") string_view %{
+ convert_to_string(&$input);
+ $1 = std::string_view(Z_STRVAL($input), Z_STRLEN($input));
+ %}
+
+ %typemap(directorout) string_view %{
+ convert_to_string($input);
+ $result = std::string_view(Z_STRVAL_P($input), Z_STRLEN_P($input));
+ %}
+
+ %typemap(out, phptype="string") string_view %{
+ ZVAL_STRINGL($result, $1.data(), $1.size());
+ %}
+
+ %typemap(directorin) string_view, const string_view& %{
+ ZVAL_STRINGL($input, $1.data(), $1.size());
+ %}
+
+ %typemap(out, phptype="string") const string_view& %{
+ ZVAL_STRINGL($result, $1->data(), $1->size());
+ %}
+
+ %typemap(throws) string_view, const string_view& %{
+ {
+ zval swig_exception;
+ ZVAL_STRINGL(&swig_exception, $1.data(), $1.size());
+ zend_throw_exception_object(&swig_exception);
+ goto fail;
+ }
+ %}
+
+ %typemap(throws) string_view*, const string_view* %{
+ {
+ zval swig_exception;
+ ZVAL_STRINGL(&swig_exception, $1->data(), $1->size());
+ zend_throw_exception_object(&swig_exception);
+ goto fail;
+ }
+ %}
+
+ %typemap(in, phptype="string") const string_view& ($*1_ltype temp) %{
+ convert_to_string(&$input);
+ temp = std::string_view(Z_STRVAL($input), Z_STRLEN($input));
+ $1 = &temp;
+ %}
+
+}
diff --git a/Lib/swig.swg b/Lib/swig.swg
index f904f53c6..696dc8145 100644
--- a/Lib/swig.swg
+++ b/Lib/swig.swg
@@ -361,6 +361,11 @@ static int NAME(TYPE x) {
%define SWIG_TYPECHECK_STDUNISTRING 115 %enddef
%define SWIG_TYPECHECK_UNISTRING 120 %enddef
%define SWIG_TYPECHECK_CHAR 130 %enddef
+/* Give std::string_view a slightly higher precedence because if there are
+ * overloaded forms then it may be more efficient to pass as std::string_view
+ * (e.g. to pass as std::string requires copying the data into a std::string).
+ */
+%define SWIG_TYPECHECK_STRINGVIEW 134 %enddef
%define SWIG_TYPECHECK_STDSTRING 135 %enddef
%define SWIG_TYPECHECK_STRING 140 %enddef
%define SWIG_TYPECHECK_PAIR 150 %enddef