sclass RealmCopy { O dest = mc(); // destination realm new IdentityHashMap seen; new HashMap classMap; //IF1 classFinder = toIF1(_defaultClassFinder()); bool fullCopy; // descend into objects even when they have the same type O copy(O o) { ret evalInVStack(new CopyObject(o)); } noeq record CopyObject(O o) extends VStackComputableWithStep { void step(VStack stack) { // null and simple types if (o == null || o instanceof String || o instanceof Number) ret with stack.ret(o); // seen object O oo = seen.get(o); if (oo != null) stack.ret(oo); dispatchByType(stack, o); } } void dispatchByType(VStack stack, O o) { if (o cast O[]) ret with stack.replace(new CopyObjectArray(o)); if (o cast Cl) if (!overrideCollectionOrMapCopy(o)) ret with stack.replace(new CopyCollection(o)); if (o cast Map) if (!overrideCollectionOrMapCopy(o)) ret with stack.replace(new CopyMap(o)); ret with stack.replace(new CopyObjectFieldByField(o)); } noeq record CopyObjectArray(O[] o) extends VStackComputableWithStep { O[] out; int i; void step(VStack stack) { if (step == 0) { out = newObjectArrayOfSameType(o); seen.put(o, out); ++step; } if (stack.hasSubResult()) out[i++] = stack.subResult(); if (i >= o.length) ret with stack.ret(out); stack.call(new CopyObject(o[i])); } } noeq record CopyCollection(Cl o) extends VStackComputableWithStep { Cl out; Iterator it; void step(VStack stack) { if (step == 0) { out = similarEmptyCollection(o); seen.put(o, out); ++step; } if (stack.hasSubResult()) out.add(stack.subResult()); if (!it.hasNext()) ret with stack.ret(out); stack.call(new CopyObject(it.next())); } } noeq record CopyMap(Map o) extends VStackComputableWithStep { Map out; Iterator it; Map.Entry entry; O copiedKey; void step(VStack stack) { if (step == 0) { out = similarEmptyMap(o); seen.put(o, out); ++step; } if (stack.hasSubResult()) { if (step == 1) { // got the copied key copiedKey = stack.subResult(); // now copy the value stack.call(new CopyObject(entry.getValue())); ret with ++step; } else { // got the copied value - can put into map out.put(copiedKey, stack.subResult()); step = 1; } } if (!it.hasNext()) ret with stack.ret(out); entry = it.next(); stack.call(new CopyObject(entry.getKey())); } } noeq record CopyObjectFieldByField(O o) extends VStackComputableWithStep { S className; Class destClass; O out; L fields; Iterator itField; Field field; void step(VStack stack) { if (step == 0) { Class c = o.getClass(); className = c.getName(); className = loadableUtilsClassNameToMain(className); if (!className.startsWith("main$")) ret with stack.ret(o); destClass = classMap.get(c); if (destClass == null) { if (!isAnonymousClassName(className)) destClass = getClass_vmName_withLoadableUtils(dest, className); if (destClass == null) destClass = c; classMap.put(c, destClass); } if (destClass == c && !fullCopy) ret with stack.ret(o); // short cut unless deep copying // actually make a new object, copy fields out = nuObjectWithoutArguments(destClass); seen.put(o, out); fields = nonStaticFieldObjects(o); itField = iterator(fields); ++step; } if (stack.hasSubResult()) setOpt(out, field.getName(), stack.subResult()); if (!itField.hasNext()) ret with stack.ret(out); field = itField.next(); stack.push(new CopyObject(fieldGet(field, o)); } } // set to true if you want to copy a map or collection field-by-field bool overrideCollectionOrMapCopy(O o) { false; } }