Skip to content

Commit 9d9e015

Browse files
authored
Merge pull request swiftlang#63833 from apple/egorzhdan/cxx-u16string-reland
Revert "Revert "[cxx-interop] Add conversions between `std::u16string` and `Swift.String`""
2 parents dd353b9 + 9818312 commit 9d9e015

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

stdlib/public/Cxx/std/String.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
// MARK: Initializing C++ string from a Swift String
14+
1315
extension std.string {
1416
/// Creates a C++ string having the same content as the given Swift string.
1517
///
@@ -23,12 +25,34 @@ extension std.string {
2325
}
2426
}
2527

28+
extension std.u16string {
29+
/// Creates a C++ UTF-16 string having the same content as the given Swift
30+
/// string.
31+
///
32+
/// - Complexity: O(*n*), where *n* is the number of UTF-16 code units in the
33+
/// Swift string.
34+
public init(_ string: String) {
35+
self.init()
36+
for char in string.utf16 {
37+
self.push_back(char)
38+
}
39+
}
40+
}
41+
42+
// MARK: Initializing C++ string from a Swift String literal
43+
2644
extension std.string: ExpressibleByStringLiteral {
2745
public init(stringLiteral value: String) {
2846
self.init(value)
2947
}
3048
}
3149

50+
extension std.u16string: ExpressibleByStringLiteral {
51+
public init(stringLiteral value: String) {
52+
self.init(value)
53+
}
54+
}
55+
3256
extension std.string: CustomDebugStringConvertible {
3357
public var debugDescription: String {
3458
return "std.string(\(String(self)))"
@@ -41,6 +65,8 @@ extension std.string: CustomStringConvertible {
4165
}
4266
}
4367

68+
// MARK: Initializing Swift String from a C++ string
69+
4470
extension String {
4571
/// Creates a String having the same content as the given C++ string.
4672
///
@@ -58,4 +84,20 @@ extension String {
5884
}
5985
withExtendedLifetime(cxxString) {}
6086
}
87+
88+
/// Creates a String having the same content as the given C++ UTF-16 string.
89+
///
90+
/// If `cxxString` contains ill-formed UTF-16 code unit sequences, this
91+
/// initializer replaces them with the Unicode replacement character
92+
/// (`"\u{FFFD}"`).
93+
///
94+
/// - Complexity: O(*n*), where *n* is the number of bytes in the C++ UTF-16
95+
/// string.
96+
public init(_ cxxU16String: std.u16string) {
97+
let buffer = UnsafeBufferPointer<UInt16>(
98+
start: cxxU16String.__dataUnsafe(),
99+
count: cxxU16String.size())
100+
self = String(decoding: buffer, as: UTF16.self)
101+
withExtendedLifetime(cxxU16String) {}
102+
}
61103
}

test/Interop/Cxx/stdlib/overlay/std-string-overlay.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,36 @@ StdStringOverlayTestSuite.test("std::string <=> Swift.String") {
4545
expectEqual(swift7, "���")
4646
}
4747

48+
StdStringOverlayTestSuite.test("std::u16string <=> Swift.String") {
49+
let cxx1 = std.u16string()
50+
let swift1 = String(cxx1)
51+
expectEqual(swift1, "")
52+
53+
let cxx2 = std.u16string("something123")
54+
expectEqual(cxx2.size(), 12)
55+
let swift2 = String(cxx2)
56+
expectEqual(swift2, "something123")
57+
58+
let cxx3: std.u16string = "literal"
59+
expectEqual(cxx3.size(), 7)
60+
61+
let cxx4: std.u16string = "тест"
62+
expectEqual(cxx4.size(), 4)
63+
let swift4 = String(cxx4)
64+
expectEqual(swift4, "тест")
65+
66+
// Emojis are represented by more than one CWideChar.
67+
let cxx5: std.u16string = "emoji_🤖"
68+
expectEqual(cxx5.size(), 8)
69+
let swift5 = String(cxx5)
70+
expectEqual(swift5, "emoji_🤖")
71+
72+
let cxx6 = std.u16string("xyz\0abc")
73+
expectEqual(cxx6.size(), 7)
74+
let swift6 = String(cxx6)
75+
expectEqual(swift6, "xyz\0abc")
76+
}
77+
4878
StdStringOverlayTestSuite.test("std::string as Swift.CustomDebugStringConvertible") {
4979
let cxx1 = std.string()
5080
expectEqual(cxx1.debugDescription, "std.string()")

0 commit comments

Comments
 (0)