Skip to content

Commit 306dcdf

Browse files
committed
[cxx-interop] Add conversions between std::u16string and Swift.String
This change adds a few extensions to the C++ stdlib overlay to allow convenient conversions between C++ UTF-16 strings and Swift strings.
1 parent 77b702d commit 306dcdf

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

stdlib/public/Cxx/std/String.swift

Lines changed: 29 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
public init(_ string: String) {
1517
self.init()
@@ -19,12 +21,31 @@ extension std.string {
1921
}
2022
}
2123

24+
extension std.u16string {
25+
public init(_ string: String) {
26+
self.init()
27+
for char in string.utf16 {
28+
self.push_back(char)
29+
}
30+
}
31+
}
32+
33+
// MARK: Initializing C++ string from a Swift String literal
34+
2235
extension std.string: ExpressibleByStringLiteral {
2336
public init(stringLiteral value: String) {
2437
self.init(value)
2538
}
2639
}
2740

41+
extension std.u16string: ExpressibleByStringLiteral {
42+
public init(stringLiteral value: String) {
43+
self.init(value)
44+
}
45+
}
46+
47+
// MARK: Initializing Swift String from a C++ string
48+
2849
extension String {
2950
public init(cxxString: std.string) {
3051
let buffer = UnsafeBufferPointer<CChar>(
@@ -35,4 +56,12 @@ extension String {
3556
}
3657
withExtendedLifetime(cxxString) {}
3758
}
59+
60+
public init(cxxU16String: std.u16string) {
61+
let buffer = UnsafeBufferPointer<UInt16>(
62+
start: cxxU16String.__dataUnsafe(),
63+
count: cxxU16String.size())
64+
self = String(decoding: buffer, as: UTF16.self)
65+
withExtendedLifetime(cxxU16String) {}
66+
}
3867
}

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,36 @@ StdStringOverlayTestSuite.test("std::string <=> Swift.String") {
3737
expectEqual(swift6, "xyz\0abc")
3838
}
3939

40+
StdStringOverlayTestSuite.test("std::u16string <=> Swift.String") {
41+
let cxx1 = std.u16string()
42+
let swift1 = String(cxxU16String: cxx1)
43+
expectEqual(swift1, "")
44+
45+
let cxx2 = std.u16string("something123")
46+
expectEqual(cxx2.size(), 12)
47+
let swift2 = String(cxxU16String: cxx2)
48+
expectEqual(swift2, "something123")
49+
50+
let cxx3: std.u16string = "literal"
51+
expectEqual(cxx3.size(), 7)
52+
53+
let cxx4: std.u16string = "тест"
54+
expectEqual(cxx4.size(), 4)
55+
let swift4 = String(cxxU16String: cxx4)
56+
expectEqual(swift4, "тест")
57+
58+
// Emojis are represented by more than one CWideChar.
59+
let cxx5: std.u16string = "emoji_🤖"
60+
expectEqual(cxx5.size(), 8)
61+
let swift5 = String(cxxU16String: cxx5)
62+
expectEqual(swift5, "emoji_🤖")
63+
64+
let cxx6 = std.u16string("xyz\0abc")
65+
expectEqual(cxx6.size(), 7)
66+
let swift6 = String(cxxU16String: cxx6)
67+
expectEqual(swift6, "xyz\0abc")
68+
}
69+
4070
extension std.string.const_iterator: UnsafeCxxInputIterator {
4171
// This func should not be required.
4272
public static func ==(lhs: std.string.const_iterator,

0 commit comments

Comments
 (0)