Skip to content

Commit c854fa2

Browse files
authored
Merge pull request #77190 from swiftlang/egorzhdan/std-string-view
[cxx-interop] Allow creating a String from `std::string_view`
2 parents 7dfdfe0 + cb486c6 commit c854fa2

File tree

4 files changed

+111
-0
lines changed

4 files changed

+111
-0
lines changed

stdlib/public/Cxx/std/String.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,3 +291,61 @@ extension String {
291291
withExtendedLifetime(cxxU32String) {}
292292
}
293293
}
294+
295+
// MARK: Initializing Swift String from a C++ string_view
296+
297+
extension String {
298+
/// Creates a String having the same content as the given C++ string view.
299+
///
300+
/// If `cxxStringView` contains ill-formed UTF-8 code unit sequences, this
301+
/// initializer replaces them with the Unicode replacement character
302+
/// (`"\u{FFFD}"`).
303+
///
304+
/// - Complexity: O(*n*), where *n* is the number of bytes in the C++ string
305+
/// view.
306+
public init(_ cxxStringView: std.string_view) {
307+
let buffer = UnsafeBufferPointer<CChar>(
308+
start: cxxStringView.__dataUnsafe(),
309+
count: cxxStringView.size())
310+
self = buffer.withMemoryRebound(to: UInt8.self) {
311+
String(decoding: $0, as: UTF8.self)
312+
}
313+
withExtendedLifetime(cxxStringView) {}
314+
}
315+
316+
/// Creates a String having the same content as the given C++ UTF-16 string
317+
/// view.
318+
///
319+
/// If `cxxU16StringView` contains ill-formed UTF-16 code unit sequences, this
320+
/// initializer replaces them with the Unicode replacement character
321+
/// (`"\u{FFFD}"`).
322+
///
323+
/// - Complexity: O(*n*), where *n* is the number of bytes in the C++ UTF-16
324+
/// string view.
325+
public init(_ cxxU16StringView: std.u16string_view) {
326+
let buffer = UnsafeBufferPointer<UInt16>(
327+
start: cxxU16StringView.__dataUnsafe(),
328+
count: cxxU16StringView.size())
329+
self = String(decoding: buffer, as: UTF16.self)
330+
withExtendedLifetime(cxxU16StringView) {}
331+
}
332+
333+
/// Creates a String having the same content as the given C++ UTF-32 string
334+
/// view.
335+
///
336+
/// If `cxxU32StringView` contains ill-formed UTF-32 code unit sequences, this
337+
/// initializer replaces them with the Unicode replacement character
338+
/// (`"\u{FFFD}"`).
339+
///
340+
/// - Complexity: O(*n*), where *n* is the number of bytes in the C++ UTF-32
341+
/// string view.
342+
public init(_ cxxU32StringView: std.u32string_view) {
343+
let buffer = UnsafeBufferPointer<Unicode.Scalar>(
344+
start: cxxU32StringView.__dataUnsafe(),
345+
count: cxxU32StringView.size())
346+
self = buffer.withMemoryRebound(to: UInt32.self) {
347+
String(decoding: $0, as: UTF32.self)
348+
}
349+
withExtendedLifetime(cxxU32StringView) {}
350+
}
351+
}

test/Interop/Cxx/stdlib/Inputs/module.modulemap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ module StdString {
4040
export *
4141
}
4242

43+
module StdStringView {
44+
header "std-string-view.h"
45+
requires cplusplus
46+
export *
47+
}
48+
4349
module StdPair {
4450
header "std-pair.h"
4551
requires cplusplus
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <string_view>
2+
3+
static std::string_view staticStringView{"abc210"};
4+
static std::string_view staticEmptyStringView{""};
5+
static std::string_view staticNonASCIIStringView{"тест"};
6+
7+
// UTF-16
8+
static std::u16string_view staticU16StringView{u"abc210"};
9+
static std::u16string_view staticU16EmptyStringView{u""};
10+
static std::u16string_view staticU16NonASCIIStringView{u"тест"};
11+
12+
// UTF-32
13+
static std::u32string_view staticU32StringView{U"abc210"};
14+
static std::u32string_view staticU32EmptyStringView{U""};
15+
static std::u32string_view staticU32NonASCIIStringView{U"тест"};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=swift-6)
2+
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=upcoming-swift)
3+
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=upcoming-swift -Xcc -std=c++17)
4+
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=upcoming-swift -Xcc -std=c++20)
5+
6+
// REQUIRES: executable_test
7+
8+
import StdlibUnittest
9+
import CxxStdlib
10+
import StdStringView
11+
12+
var StdStringTestSuite = TestSuite("StdStringView")
13+
14+
StdStringTestSuite.test("String.init(_: std.string_view)") {
15+
expectEqual("abc210", String(staticStringView))
16+
expectEqual("", String(staticEmptyStringView))
17+
expectEqual("тест", String(staticNonASCIIStringView))
18+
}
19+
20+
StdStringTestSuite.test("String.init(_: std.u16string_view)") {
21+
expectEqual("abc210", String(staticU16StringView))
22+
expectEqual("", String(staticU16EmptyStringView))
23+
expectEqual("тест", String(staticU16NonASCIIStringView))
24+
}
25+
26+
StdStringTestSuite.test("String.init(_: std.u32string_view)") {
27+
expectEqual("abc210", String(staticU32StringView))
28+
expectEqual("", String(staticU32EmptyStringView))
29+
expectEqual("тест", String(staticU32NonASCIIStringView))
30+
}
31+
32+
runAllTests()

0 commit comments

Comments
 (0)