@@ -1251,40 +1251,42 @@ def zip(*others)
1251
1251
end
1252
1252
end
1253
1253
1254
- # Helper to recurse through flattening since the method
1255
- # is not allowed to recurse itself. Detects recursive structures .
1254
+ # Helper to " recurse" through flattening. Detects recursive structures.
1255
+ # Does not actually recurse, but uses a worklist instead .
1256
1256
def recursively_flatten ( array , out , max_levels = -1 )
1257
1257
modified = false
1258
+ visited = { } . compare_by_identity
1259
+ worklist = [ [ array , 0 ] ]
1258
1260
1259
- # Strict equality since < 0 means 'infinite'
1260
- if max_levels == 0
1261
- out . concat ( array )
1262
- return false
1263
- end
1261
+ until worklist . empty?
1262
+ array , i = worklist . pop
1264
1263
1265
- max_levels -= 1
1266
- recursion = Truffle ::ThreadOperations . detect_recursion ( array ) do
1267
- array = Truffle ::Type . coerce_to ( array , Array , :to_ary )
1264
+ if i == 0
1265
+ raise ArgumentError , 'tried to flatten recursive array' if visited . key? ( array )
1266
+ if max_levels == worklist . size
1267
+ out . concat ( array )
1268
+ next
1269
+ end
1270
+ visited [ array ] = true
1271
+ end
1268
1272
1269
- i = 0
1270
1273
size = array . size
1271
-
1272
1274
while i < size
1273
1275
o = array . at i
1274
-
1275
1276
tmp = Truffle ::Type . rb_check_convert_type ( o , Array , :to_ary )
1276
1277
if Primitive . nil? tmp
1277
1278
out << o
1278
1279
else
1279
1280
modified = true
1280
- recursively_flatten tmp , out , max_levels
1281
+ worklist . push ( [ array , i + 1 ] , [ tmp , 0 ] )
1282
+ break
1281
1283
end
1282
-
1283
1284
i += 1
1284
1285
end
1286
+
1287
+ visited . delete array if i == size
1285
1288
end
1286
1289
1287
- raise ArgumentError , 'tried to flatten recursive array' if recursion
1288
1290
modified
1289
1291
end
1290
1292
private :recursively_flatten
0 commit comments