Skip to content

Commit c6b10df

Browse files
committed
"Enhance CxxDictionary with removeValue(forKey:), subscript(key:default:), mergemerging and init(grouping:by:)"
1 parent 6221b29 commit c6b10df

File tree

3 files changed

+348
-2
lines changed

3 files changed

+348
-2
lines changed

stdlib/public/Cxx/CxxDictionary.swift

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public protocol CxxDictionary<Key, Value>: ExpressibleByDictionaryLiteral {
4040
@discardableResult
4141
mutating func erase(_ key: Key) -> Size
4242

43+
/// Do not implement this function manually in Swift.
44+
@discardableResult
45+
mutating func __eraseUnsafe(_ iter: RawMutableIterator) -> RawMutableIterator
46+
4347
/// Do not implement this function manually in Swift.
4448
func __beginUnsafe() -> RawIterator
4549

@@ -73,6 +77,25 @@ extension CxxDictionary {
7377
}
7478
}
7579

80+
@inlinable
81+
public init<S: Sequence>(
82+
grouping values: __owned S,
83+
by keyForValue: (S.Element) throws -> Key
84+
) rethrows where Value: CxxVector<S.Element> {
85+
self.init()
86+
for value in values {
87+
let key = try keyForValue(value)
88+
var iter = __findMutatingUnsafe(key)
89+
if iter != __endMutatingUnsafe() {
90+
iter.pointee.second.push_back(value)
91+
} else {
92+
var vector = Value()
93+
vector.push_back(value)
94+
self[key] = vector
95+
}
96+
}
97+
}
98+
7699
@inlinable
77100
public subscript(key: Key) -> Value? {
78101
get {
@@ -98,7 +121,29 @@ extension CxxDictionary {
98121
}
99122
}
100123
}
101-
124+
125+
@inlinable
126+
public subscript(
127+
key: Key, default defaultValue: @autoclosure () -> Value
128+
) -> Value {
129+
get {
130+
let iter = __findUnsafe(key)
131+
guard iter != __endUnsafe() else {
132+
return defaultValue()
133+
}
134+
return iter.pointee.second
135+
}
136+
set(newValue) {
137+
var iter = self.__findMutatingUnsafe(key)
138+
if iter != self.__endMutatingUnsafe() {
139+
iter.pointee.second = newValue
140+
} else {
141+
let keyValuePair = Element(first: key, second: newValue)
142+
self.__insertUnsafe(keyValuePair)
143+
}
144+
}
145+
}
146+
102147
public func filter(_ isIncluded: (_ key: Key, _ value: Value) throws -> Bool) rethrows -> Self {
103148
var filteredDictionary = Self.init()
104149
var iterator = __beginUnsafe()
@@ -116,4 +161,95 @@ extension CxxDictionary {
116161

117162
return filteredDictionary
118163
}
164+
165+
@inlinable
166+
@discardableResult
167+
public mutating func removeValue(forKey key: Key) -> Value? {
168+
var iter = self.__findMutatingUnsafe(key)
169+
guard iter != self.__endMutatingUnsafe() else { return nil }
170+
171+
let value = iter.pointee.second
172+
self.__eraseUnsafe(iter)
173+
return value
174+
}
175+
176+
@inlinable
177+
public mutating func merge<S: Sequence>(
178+
_ other: __owned S,
179+
uniquingKeysWith combine: (Value, Value) throws -> Value
180+
) rethrows where S.Element == (Key, Value) {
181+
for (key, value) in other {
182+
var iter = self.__findMutatingUnsafe(key)
183+
if iter != self.__endMutatingUnsafe() {
184+
iter.pointee.second = try combine(iter.pointee.second, value)
185+
} else {
186+
let keyValuePair = Element(first: key, second: value)
187+
self.__insertUnsafe(keyValuePair)
188+
}
189+
}
190+
}
191+
192+
@inlinable
193+
public mutating func merge(
194+
_ other: __owned Dictionary<Key, Value>,
195+
uniquingKeysWith combine: (Value, Value) throws -> Value
196+
) rethrows where Key: Hashable {
197+
for (key, value) in other {
198+
var iter = self.__findMutatingUnsafe(key)
199+
if iter != self.__endMutatingUnsafe() {
200+
iter.pointee.second = try combine(iter.pointee.second, value)
201+
} else {
202+
let keyValuePair = Element(first: key, second: value)
203+
self.__insertUnsafe(keyValuePair)
204+
}
205+
}
206+
}
207+
208+
@inlinable
209+
public mutating func merge(
210+
_ other: __owned Self,
211+
uniquingKeysWith combine: (Value, Value) throws -> Value
212+
) rethrows {
213+
var iterator = other.__beginUnsafe()
214+
while iterator != other.__endUnsafe() {
215+
var iter = self.__findMutatingUnsafe(iterator.pointee.first)
216+
if iter != self.__endMutatingUnsafe() {
217+
iter.pointee.second = try combine(iter.pointee.second, iterator.pointee.second)
218+
} else {
219+
let keyValuePair = Element(first: iterator.pointee.first, second: iterator.pointee.second)
220+
self.__insertUnsafe(keyValuePair)
221+
}
222+
iterator = iterator.successor()
223+
}
224+
}
225+
226+
@inlinable
227+
public __consuming func merging<S: Sequence>(
228+
_ other: __owned S,
229+
uniquingKeysWith combine: (Value, Value) throws -> Value
230+
) rethrows -> Self where S.Element == (Key, Value) {
231+
var result = self
232+
try result.merge(other, uniquingKeysWith: combine)
233+
return result
234+
}
235+
236+
@inlinable
237+
public __consuming func merging(
238+
_ other: __owned Dictionary<Key, Value>,
239+
uniquingKeysWith combine: (Value, Value) throws -> Value
240+
) rethrows -> Self where Key: Hashable {
241+
var result = self
242+
try result.merge(other, uniquingKeysWith: combine)
243+
return result
244+
}
245+
246+
@inlinable
247+
public __consuming func merging(
248+
_ other: __owned Self,
249+
uniquingKeysWith combine: (Value, Value) throws -> Value
250+
) rethrows -> Self {
251+
var result = self
252+
try result.merge(other, uniquingKeysWith: combine)
253+
return result
254+
}
119255
}

test/Interop/Cxx/stdlib/Inputs/std-map.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
#include <map>
55
#include <string>
66
#include <unordered_map>
7+
#include <vector>
78

89
using Map = std::map<int, int>;
910
using MapStrings = std::map<std::string, std::string>;
1011
using NestedMap = std::map<int, Map>;
12+
using MapGroup = std::map<int, std::vector<int>>;
1113
using UnorderedMap = std::unordered_map<int, int>;
12-
14+
using UnorderedMapGroup = std::unordered_map<int, std::vector<int>>;
1315
inline Map initMap() { return {{1, 3}, {2, 2}, {3, 3}}; }
1416
inline UnorderedMap initUnorderedMap() { return {{1, 3}, {3, 3}, {2, 2}}; }
1517
inline Map initEmptyMap() { return {}; }

0 commit comments

Comments
 (0)