1 | // optimistic signature that usually holds
|
2 | static <A> A clone(A o) {
|
3 | new ArrayDeque<Runnable> q;
|
4 | Object x = clone_impl(o, new IdentityHashMap, q);
|
5 | while (!q.isEmpty())
|
6 | q.poll().run();
|
7 | return (A) x;
|
8 | }
|
9 |
|
10 | static O clone_impl(O o, final IdentityHashMap seen, final ArrayDeque<Runnable> q) ctex {
|
11 | if (o == null) null;
|
12 |
|
13 | Object y = seen.get(o);
|
14 | if (y != null) return y;
|
15 |
|
16 | if (o instanceof L) {
|
17 | //print("Cloning list: " + o);
|
18 | final new L l;
|
19 | seen.put(o, l);
|
20 | for (final O x : (L) o)
|
21 | q.add(r { l.add(clone_impl(x, seen, q)) });
|
22 | return l;
|
23 | }
|
24 |
|
25 | if (o instanceof Map) {
|
26 | final Map m = similarEmptyMap((Map) o);
|
27 | seen.put(o, m);
|
28 | for (O entry : ((Map) o).entrySet()) {
|
29 | final Map.Entry e = (Map.Entry) entry;
|
30 | q.add(r {
|
31 | m.put(clone_impl(e.getKey(), seen, q), clone_impl(e.getValue(), seen, q))
|
32 | });
|
33 | }
|
34 | ret m;
|
35 | }
|
36 |
|
37 | if (o instanceof S || o instanceof Number || o instanceof Bool) ret o;
|
38 |
|
39 | if (o instanceof O[]) {
|
40 | final O[] l = (O[]) o;
|
41 | final O[] l2 = l.clone();
|
42 | seen.put(o, l2);
|
43 | for (int i = 0; i < l.length; i++) {
|
44 | final int _i = i;
|
45 | q.add(r { l2[_i] = clone_impl(l[_i], seen, q) });
|
46 | }
|
47 | ret l2;
|
48 | }
|
49 |
|
50 | // clone an arbitrary custom object
|
51 |
|
52 | //print("Cloning custom: " + o);
|
53 | final O clone = nuObjectWithoutArguments(o.getClass());
|
54 | seen.put(o, clone);
|
55 | Class c = o.getClass();
|
56 | while (c != O.class) {
|
57 | Field[] fields = c.getDeclaredFields();
|
58 | for (final Field field : fields) {
|
59 | if ((field.getModifiers() & Modifier.STATIC) != 0)
|
60 | continue;
|
61 | field.setAccessible(true);
|
62 | final O value = field.get(o);
|
63 | q.add(r { field.set(clone, clone_impl(value, seen, q)) });
|
64 | }
|
65 | c = c.getSuperclass();
|
66 | }
|
67 | ret clone;
|
68 | }
|