Skip to content

Commit cb27ba9

Browse files
authored
Merge pull request #64972 from apple/egorzhdan/cxx-string-hashable
[cxx-interop] Conform `std::string` to Hashable
2 parents acc8a7e + 242a432 commit cb27ba9

File tree

5 files changed

+79
-4
lines changed

5 files changed

+79
-4
lines changed

stdlib/public/Cxx/cxxshim/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ foreach(sdk ${SWIFT_SDKS})
1515
endif()
1616

1717
set(outputs)
18-
foreach(source libcxxshim.modulemap libcxxshim.h)
18+
foreach(source libcxxshim.modulemap libcxxshim.h libcxxstdlibshim.h)
1919
add_custom_command(OUTPUT ${module_dir}/${source}
2020
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${source}
2121
COMMAND ${CMAKE_COMMAND} "-E" "copy_if_different" "${CMAKE_CURRENT_SOURCE_DIR}/${source}" "${module_dir}/${source}"
@@ -41,11 +41,11 @@ foreach(sdk ${SWIFT_SDKS})
4141
list(APPEND libcxxshim_modulemap_target_list cxxshim-${sdk}-${arch})
4242

4343

44-
swift_install_in_component(FILES libcxxshim.modulemap libcxxshim.h
44+
swift_install_in_component(FILES libcxxshim.modulemap libcxxshim.h libcxxstdlibshim.h
4545
DESTINATION "lib/swift/${arch_subdir}"
4646
COMPONENT compiler)
4747
if(SWIFT_BUILD_STATIC_STDLIB)
48-
swift_install_in_component(FILES libcxxshim.modulemap libcxxshim.h
48+
swift_install_in_component(FILES libcxxshim.modulemap libcxxshim.h libcxxstdlibshim.h
4949
DESTINATION "lib/swift_static/${arch_subdir}"
5050
COMPONENT compiler)
5151
endif()
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
module CxxShim {
22
header "libcxxshim.h"
33
requires cplusplus
4-
}
4+
}
5+
6+
module CxxStdlibShim {
7+
header "libcxxstdlibshim.h"
8+
requires cplusplus
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <functional>
2+
#include <string>
3+
4+
/// Used for std::string conformance to Swift.Hashable
5+
typedef std::hash<std::string> __swift_interopHashOfString;
6+
7+
/// Used for std::u16string conformance to Swift.Hashable
8+
typedef std::hash<std::u16string> __swift_interopHashOfU16String;

stdlib/public/Cxx/std/String.swift

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

13+
import CxxStdlibShim
14+
1315
// MARK: Initializing C++ string from a Swift String
1416

1517
extension std.string {
@@ -87,6 +89,24 @@ extension std.u16string: Equatable {
8789
}
8890
}
8991

92+
// MARK: Hashing C++ strings
93+
94+
extension std.string: Hashable {
95+
public func hash(into hasher: inout Hasher) {
96+
// Call std::hash<std::string>::operator()
97+
let cxxHash = __swift_interopHashOfString().callAsFunction(self)
98+
hasher.combine(cxxHash)
99+
}
100+
}
101+
102+
extension std.u16string: Hashable {
103+
public func hash(into hasher: inout Hasher) {
104+
// Call std::hash<std::u16string>::operator()
105+
let cxxHash = __swift_interopHashOfU16String().callAsFunction(self)
106+
hasher.combine(cxxHash)
107+
}
108+
}
109+
90110
// MARK: Getting a Swift description of a C++ string
91111

92112
extension std.string: CustomDebugStringConvertible {

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,48 @@ StdStringOverlayTestSuite.test("std::u16string operators") {
8585
expectTrue(s1 == "something123literal")
8686
}
8787

88+
StdStringOverlayTestSuite.test("std::string as Hashable") {
89+
let s0 = std.string()
90+
let h0 = s0.hashValue
91+
92+
let s1 = std.string("something")
93+
let h1 = s1.hashValue
94+
95+
let s2 = std.string("something123")
96+
let h2 = s2.hashValue
97+
98+
let s3 = std.string("something")
99+
let h3 = s3.hashValue
100+
101+
expectEqual(h1, h3)
102+
expectNotEqual(h0, h1)
103+
expectNotEqual(h0, h2)
104+
expectNotEqual(h0, h3)
105+
expectNotEqual(h1, h2)
106+
expectNotEqual(h2, h3)
107+
}
108+
109+
StdStringOverlayTestSuite.test("std::u16string as Hashable") {
110+
let s0 = std.u16string()
111+
let h0 = s0.hashValue
112+
113+
let s1 = std.u16string("something")
114+
let h1 = s1.hashValue
115+
116+
let s2 = std.u16string("something123")
117+
let h2 = s2.hashValue
118+
119+
let s3 = std.u16string("something")
120+
let h3 = s3.hashValue
121+
122+
expectEqual(h1, h3)
123+
expectNotEqual(h0, h1)
124+
expectNotEqual(h0, h2)
125+
expectNotEqual(h0, h3)
126+
expectNotEqual(h1, h2)
127+
expectNotEqual(h2, h3)
128+
}
129+
88130
StdStringOverlayTestSuite.test("std::u16string <=> Swift.String") {
89131
let cxx1 = std.u16string()
90132
let swift1 = String(cxx1)

0 commit comments

Comments
 (0)