about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--073deep_copy.cc52
1 files changed, 44 insertions, 8 deletions
diff --git a/073deep_copy.cc b/073deep_copy.cc
index bf5675db..7c67425b 100644
--- a/073deep_copy.cc
+++ b/073deep_copy.cc
@@ -213,31 +213,38 @@ case DEEP_COPY: {
 }
 
 :(code)
-vector<double> deep_copy(reagent/*copy*/ in, const reagent& tmp) {
+vector<double> deep_copy(const reagent& in, const reagent& tmp) {
+  map<int, int> addresses_copied;
+  return deep_copy(in, addresses_copied, tmp);
+}
+
+vector<double> deep_copy(reagent/*copy*/ in, map<int, int>& addresses_copied, const reagent& tmp) {
   canonize(in);
   vector<double> result;
-  map<int, int> addresses_copied;
   if (is_mu_address(in))
     result.push_back(deep_copy_address(in, addresses_copied, tmp));
   else
     deep_copy(in, addresses_copied, tmp, result);
-  trace(9991, "run") << "deep-copy: done" << end();
   return result;
 }
 
 // deep-copy an address and return a new address
 int deep_copy_address(const reagent& canonized_in, map<int, int>& addresses_copied, const reagent& tmp) {
-  int in_address = canonized_in.value;
-  if (in_address == 0) return 0;
+  if (canonized_in.value == 0) return 0;
+  int in_address = payload_address(canonized_in);
   trace(9991, "run") << "deep-copy: copying address " << in_address << end();
-  if (contains_key(addresses_copied, in_address))
-    return get(addresses_copied, in_address);
+  if (contains_key(addresses_copied, in_address)) {
+    int out = get(addresses_copied, in_address);
+    trace(9991, "run") << "deep-copy: copy already exists: " << out << end();
+    return out;
+  }
   int out = allocate(payload_size(canonized_in));
+  trace(9991, "run") << "deep-copy: new address is " << out << end();
   put(addresses_copied, in_address, out);
   reagent/*copy*/ payload = canonized_in;
   payload.properties.push_back(pair<string, string_tree*>("lookup", NULL));
   trace(9991, "run") << "recursing on payload " << payload.value << ' ' << to_string(payload) << end();
-  vector<double> data = deep_copy(payload, tmp);
+  vector<double> data = deep_copy(payload, addresses_copied, tmp);
   trace(9991, "run") << "deep-copy: writing result " << out << ": " << to_string(data) << end();
   // HACK: write_memory interface isn't ideal for this situation; we need
   // a temporary location to help copy the payload.
@@ -274,6 +281,12 @@ void deep_copy(const reagent& canonized_in, map<int, int>& addresses_copied, con
   }
 }
 
+int payload_address(reagent/*copy*/ x) {
+  x.properties.push_back(pair<string, string_tree*>("lookup", NULL));
+  canonize(x);
+  return x.value;
+}
+
 //: moar tests, just because I can't believe it all works
 
 :(scenario deep_copy_stress_test_1)
@@ -338,3 +351,26 @@ def main [
   1:number/raw <- copy *y
 ]
 +mem: storing 34 in location 1
+
+:(scenario deep_copy_cycles)
+container foo [
+  p:number
+  q:address:foo
+]
+def main [
+  local-scope
+  x:address:foo <- new foo:type
+  *x <- put *x, p:offset, 34
+  *x <- put *x, q:offset, x  # create a cycle
+  y:address:foo <- deep-copy x
+  1:number/raw <- get *y, p:offset
+  y2:address:foo <- get *y, q:offset
+  stash y [vs] y2
+  2:boolean/raw <- equal y, y2  # is it still a cycle?
+  3:boolean/raw <- equal x, y  # is it the same cycle?
+]
++mem: storing 34 in location 1
+# deep copy also contains a cycle
++mem: storing 1 in location 2
+# but it's a completely different (disjoint) cycle
++mem: storing 0 in location 3