Skip to content

Commit 86b7b28

Browse files
committed
♻️ refactor bridgeInputForEncode and bridgeUndefinedPreservingOrder to use Set<ObjectIdentifier> for cycle detection instead of NSHashTable
1 parent abecdda commit 86b7b28

File tree

1 file changed

+32
-29
lines changed

1 file changed

+32
-29
lines changed

Sources/QsObjC/QsBridge.swift

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,13 @@
139139
/// throw `EncodeError.cyclicObject`, which we relay as `NSError`.
140140
@inline(__always)
141141
internal static func bridgeInputForEncode(_ input: Any) -> Any {
142-
let seen = NSHashTable<AnyObject>.weakObjects()
143-
return _bridgeInputForEncode(input, seen: seen)
142+
var seen = Set<ObjectIdentifier>()
143+
return _bridgeInputForEncode(input, seen: &seen)
144144
}
145145

146146
@inline(__always)
147-
private static func _bridgeInputForEncode(_ input: Any, seen: NSHashTable<AnyObject>) -> Any
147+
private static func _bridgeInputForEncode(_ input: Any, seen: inout Set<ObjectIdentifier>)
148+
-> Any
148149
{
149150
switch input {
150151
// Strings
@@ -155,49 +156,51 @@
155156
case let od as OrderedDictionary<String, Any>:
156157
var out = OrderedDictionary<String, Any>()
157158
out.reserveCapacity(od.count)
158-
for (k, v) in od { out[k] = _bridgeInputForEncode(v, seen: seen) }
159+
for (k, v) in od { out[k] = _bridgeInputForEncode(v, seen: &seen) }
159160
return out
160161

161162
// Already ordered Swift dict (NSString keys)
162163
case let od as OrderedDictionary<NSString, Any>:
163164
var out = OrderedDictionary<String, Any>()
164165
out.reserveCapacity(od.count)
165-
for (k, v) in od { out[k as String] = _bridgeInputForEncode(v, seen: seen) }
166+
for (k, v) in od { out[k as String] = _bridgeInputForEncode(v, seen: &seen) }
166167
return out
167168

168169
// NSDictionary → OrderedDictionary<String, Any> (stringify keys)
169170
case let d as NSDictionary:
170171
let obj = d as AnyObject
171-
if seen.contains(obj) {
172+
let id = ObjectIdentifier(obj)
173+
if seen.contains(id) {
172174
// Cycle detected: keep the original reference so the core can report cyclicObject.
173175
return d
174176
}
175-
seen.add(obj)
177+
seen.insert(id)
176178

177179
var out = OrderedDictionary<String, Any>()
178180
out.reserveCapacity(d.count)
179181
d.forEach { (k, v) in
180-
out[stringifyKey(k)] = _bridgeInputForEncode(v, seen: seen)
182+
out[stringifyKey(k)] = _bridgeInputForEncode(v, seen: &seen)
181183
}
182184
return out
183185

184186
// NSArray → [Any]
185187
case let a as NSArray:
186188
let obj = a as AnyObject
187-
if seen.contains(obj) { return a }
188-
seen.add(obj)
189-
return a.map { _bridgeInputForEncode($0, seen: seen) }
189+
let id = ObjectIdentifier(obj)
190+
if seen.contains(id) { return a }
191+
seen.insert(id)
192+
return a.map { _bridgeInputForEncode($0, seen: &seen) }
190193

191194
// Plain Swift dict → OrderedDictionary<String, Any>
192195
case let d as [String: Any]:
193196
var out = OrderedDictionary<String, Any>()
194197
out.reserveCapacity(d.count)
195-
for (k, v) in d { out[k] = _bridgeInputForEncode(v, seen: seen) }
198+
for (k, v) in d { out[k] = _bridgeInputForEncode(v, seen: &seen) }
196199
return out
197200

198201
// Plain Swift array
199202
case let a as [Any]:
200-
return a.map { _bridgeInputForEncode($0, seen: seen) }
203+
return a.map { _bridgeInputForEncode($0, seen: &seen) }
201204

202205
// Scalars / everything else
203206
default:
@@ -214,16 +217,14 @@
214217
/// - **Identity cycles** (returns the original Foundation object when revisiting it)
215218
@inline(__always)
216219
internal static func bridgeUndefinedPreservingOrder(_ v: Any?) -> Any? {
217-
let seen = NSHashTable<AnyObject>.weakObjects()
218-
return _bridgeUndefinedPreservingOrder(v, seen: seen)
220+
var seen = Set<ObjectIdentifier>()
221+
return _bridgeUndefinedPreservingOrder(v, seen: &seen)
219222
}
220223

221224
@inline(__always)
222225
internal static func _bridgeUndefinedPreservingOrder(
223-
_ v: Any?, seen: NSHashTable<AnyObject>
224-
)
225-
-> Any?
226-
{
226+
_ v: Any?, seen: inout Set<ObjectIdentifier>
227+
) -> Any? {
227228
switch v {
228229
// ObjC sentinel → Swift sentinel
229230
case is UndefinedObjC:
@@ -234,7 +235,7 @@
234235
var out = OrderedDictionary<String, Any>()
235236
out.reserveCapacity(od.count)
236237
for (k, val) in od {
237-
out[k] = _bridgeUndefinedPreservingOrder(val, seen: seen) ?? val
238+
out[k] = _bridgeUndefinedPreservingOrder(val, seen: &seen) ?? val
238239
}
239240
return out
240241

@@ -243,41 +244,43 @@
243244
var out = OrderedDictionary<String, Any>()
244245
out.reserveCapacity(od.count)
245246
for (k, val) in od {
246-
out[k as String] = _bridgeUndefinedPreservingOrder(val, seen: seen) ?? val
247+
out[k as String] = _bridgeUndefinedPreservingOrder(val, seen: &seen) ?? val
247248
}
248249
return out
249250

250251
// NSDictionary → OrderedDictionary<String, Any>
251252
case let d as NSDictionary:
252253
let obj = d as AnyObject
253-
if seen.contains(obj) { return d } // keep cycles
254-
seen.add(obj)
254+
let id = ObjectIdentifier(obj)
255+
if seen.contains(id) { return d } // keep cycles
256+
seen.insert(id)
255257
var out = OrderedDictionary<String, Any>()
256258
out.reserveCapacity(d.count)
257259
d.forEach { (k, val) in
258-
out[stringifyKey(k)] = _bridgeUndefinedPreservingOrder(val, seen: seen) ?? val
260+
out[stringifyKey(k)] = _bridgeUndefinedPreservingOrder(val, seen: &seen) ?? val
259261
}
260262
return out
261263

262264
// NSArray → [Any]
263265
case let a as NSArray:
264266
let obj = a as AnyObject
265-
if seen.contains(obj) { return a }
266-
seen.add(obj)
267-
return a.map { _bridgeUndefinedPreservingOrder($0, seen: seen) ?? $0 }
267+
let id = ObjectIdentifier(obj)
268+
if seen.contains(id) { return a }
269+
seen.insert(id)
270+
return a.map { _bridgeUndefinedPreservingOrder($0, seen: &seen) ?? $0 }
268271

269272
// Plain Swift dict → OrderedDictionary<String, Any>
270273
case let d as [String: Any]:
271274
var out = OrderedDictionary<String, Any>()
272275
out.reserveCapacity(d.count)
273276
for (k, val) in d {
274-
out[k] = _bridgeUndefinedPreservingOrder(val, seen: seen) ?? val
277+
out[k] = _bridgeUndefinedPreservingOrder(val, seen: &seen) ?? val
275278
}
276279
return out
277280

278281
// Plain Swift array
279282
case let a as [Any]:
280-
return a.map { _bridgeUndefinedPreservingOrder($0, seen: seen) ?? $0 }
283+
return a.map { _bridgeUndefinedPreservingOrder($0, seen: &seen) ?? $0 }
281284

282285
// Scalars / everything else
283286
default:

0 commit comments

Comments
 (0)