diff --git a/stdlib/public/Cxx/CxxDictionary.swift b/stdlib/public/Cxx/CxxDictionary.swift index af164c10fc82d..fa82f13c0464f 100644 --- a/stdlib/public/Cxx/CxxDictionary.swift +++ b/stdlib/public/Cxx/CxxDictionary.swift @@ -144,6 +144,60 @@ extension CxxDictionary { } } + @inlinable + public func mapValues( + _ transform: (Value) throws(E) -> R.Value + ) throws(E) -> R where R: CxxDictionary, R.Key == Key { + var result = R.init() + + var iterator = __beginUnsafe() + let endIterator = __endUnsafe() + + while iterator != endIterator { + let pair = iterator.pointee + try result.__insertUnsafe(R.Element(first: pair.first, second: transform(pair.second))) + iterator = iterator.successor() + } + + return result + } + + @inlinable + @_disfavoredOverload + public func mapValues( + _ transform: (Value) throws(E) -> Value + ) throws(E) -> Self { + return try mapValues(transform) as Self + } + + @inlinable + public func compactMapValues( + _ transform: (Value) throws(E) -> R.Value? + ) throws(E) -> R where R: CxxDictionary, R.Key == Key { + var result = R.init() + + var iterator = __beginUnsafe() + let endIterator = __endUnsafe() + + while iterator != endIterator { + let pair = iterator.pointee + if let value = try transform(pair.second) { + result.__insertUnsafe(R.Element(first: pair.first, second: value)) + } + iterator = iterator.successor() + } + + return result + } + + @inlinable + @_disfavoredOverload + public func compactMapValues( + _ transform: (Value) throws(E) -> Value? + ) throws(E) -> Self { + return try compactMapValues(transform) as Self + } + public func filter(_ isIncluded: (_ key: Key, _ value: Value) throws -> Bool) rethrows -> Self { var filteredDictionary = Self.init() var iterator = __beginUnsafe() diff --git a/test/Interop/Cxx/stdlib/Inputs/std-map.h b/test/Interop/Cxx/stdlib/Inputs/std-map.h index e9275232ef1b5..441fd44ec598d 100644 --- a/test/Interop/Cxx/stdlib/Inputs/std-map.h +++ b/test/Interop/Cxx/stdlib/Inputs/std-map.h @@ -10,8 +10,10 @@ using Map = std::map; using MapStrings = std::map; using NestedMap = std::map; using MapGroup = std::map>; +using MapIntString = std::map; using UnorderedMap = std::unordered_map; using UnorderedMapGroup = std::unordered_map>; +using UnorderedIntString = std::unordered_map; inline Map initMap() { return {{1, 3}, {2, 2}, {3, 3}}; } inline UnorderedMap initUnorderedMap() { return {{1, 3}, {3, 3}, {2, 2}}; } inline Map initEmptyMap() { return {}; } diff --git a/test/Interop/Cxx/stdlib/use-std-map.swift b/test/Interop/Cxx/stdlib/use-std-map.swift index 99320a109f53f..ee20c3d65e820 100644 --- a/test/Interop/Cxx/stdlib/use-std-map.swift +++ b/test/Interop/Cxx/stdlib/use-std-map.swift @@ -267,6 +267,85 @@ StdMapTestSuite.test("UnorderedMap.subscript(:default:)") { expectEqual(m[-5, default: 555], 555) } +StdMapTestSuite.test("Map.mapValues") { + let m = initMap() + let n = m.mapValues { v in v * 2 } + expectEqual(n[1], 6) + expectEqual(n[2], 4) + expectEqual(n[3], 6) + + let n2: MapIntString = m.mapValues { v in std.string("\(v * 3)") } + expectEqual(n2[1], std.string("9")) + expectEqual(n2[2], std.string("6")) + expectEqual(n2[3], std.string("9")) + + let n3: UnorderedMap = m.mapValues { v in v * 4 } + expectEqual(n3[1], 12) + expectEqual(n3[2], 8) + expectEqual(n3[3], 12) +} + +StdMapTestSuite.test("UnorderedMap.mapValues") { + let m = initUnorderedMap() + let n = m.mapValues { v in v * 2 } + expectEqual(n[1], 6) + expectEqual(n[2], 4) + expectEqual(n[3], 6) + + let n2: UnorderedIntString = m.mapValues { v in std.string("\(v * 3)") } + expectEqual(n2[1], std.string("9")) + expectEqual(n2[2], std.string("6")) + expectEqual(n2[3], std.string("9")) + + let n3: Map = m.mapValues { v in v * 4 } + expectEqual(n3[1], 12) + expectEqual(n3[2], 8) + expectEqual(n3[3], 12) +} + +StdMapTestSuite.test("Map.compactMapValues") { + let m = Map([1: 1, 2: 2, 3: 3, 4: 4]) + let n = m.compactMapValues { v in v % 2 == 0 ? nil : v * 2 } + expectEqual(n[1], 2) + expectNil(n[2]) + expectEqual(n[3], 6) + expectNil(n[4]) + + let n2: MapIntString = m.compactMapValues { v in v % 2 == 0 ? nil : std.string("\(v * 3)") } + expectEqual(n2[1], std.string("3")) + expectNil(n2[2]) + expectEqual(n2[3], std.string("9")) + expectNil(n2[4]) + + let n3: UnorderedMap = m.compactMapValues { v in v % 2 == 0 ? nil : v * 4 } + expectEqual(n3[1], 4) + expectNil(n3[2]) + expectEqual(n3[3], 12) + expectNil(n3[4]) +} + +StdMapTestSuite.test("UnorderedMap.compactMapValues") { + let m = UnorderedMap([1: 1, 2: 2, 3: 3, 4: 4]) + + let n = m.compactMapValues { v in v % 2 == 0 ? nil : v * 2 } + expectEqual(n[1], 2) + expectNil(n[2]) + expectEqual(n[3], 6) + expectNil(n[4]) + + let n2: UnorderedIntString = m.compactMapValues { v in v % 2 == 0 ? nil : std.string("\(v * 3)") } + expectEqual(n2[1], std.string("3")) + expectNil(n2[2]) + expectEqual(n2[3], std.string("9")) + expectNil(n2[4]) + + let n3: Map = m.compactMapValues { v in v % 2 == 0 ? nil : v * 4 } + expectEqual(n3[1], 4) + expectNil(n3[2]) + expectEqual(n3[3], 12) + expectNil(n3[4]) +} + StdMapTestSuite.test("Map.filter") { var m = initMap() var n = initEmptyMap()