// optimistic signature that usually holds static A clone(A o) { new ArrayDeque q; Object x = clone_impl(o, new IdentityHashMap, q); while (!q.isEmpty()) q.poll().run(); return (A) x; } static O clone_impl(O o, final IdentityHashMap seen, final ArrayDeque q) ctex { if (o == null) null; Object y = seen.get(o); if (y != null) return y; if (o instanceof L) { //print("Cloning list: " + o); final new L l; seen.put(o, l); for (final O x : (L) o) q.add(r { l.add(clone_impl(x, seen, q)) }); return l; } if (o instanceof Map) { final Map m = similarEmptyMap((Map) o); seen.put(o, m); for (O entry : ((Map) o).entrySet()) { final Map.Entry e = (Map.Entry) entry; q.add(r { m.put(clone_impl(e.getKey(), seen, q), clone_impl(e.getValue(), seen, q)) }); } ret m; } if (o instanceof S || o instanceof Number || o instanceof Bool) ret o; if (o instanceof O[]) { final O[] l = (O[]) o; final O[] l2 = l.clone(); seen.put(o, l2); for (int i = 0; i < l.length; i++) { final int _i = i; q.add(r { l2[_i] = clone_impl(l[_i], seen, q) }); } ret l2; } // clone an arbitrary custom object //print("Cloning custom: " + o); final O clone = nuObjectWithoutArguments(o.getClass()); seen.put(o, clone); Class c = o.getClass(); while (c != O.class) { Field[] fields = c.getDeclaredFields(); for (final Field field : fields) { if ((field.getModifiers() & Modifier.STATIC) != 0) continue; field.setAccessible(true); final O value = field.get(o); q.add(r { field.set(clone, clone_impl(value, seen, q)) }); } c = c.getSuperclass(); } ret clone; }