tint: Add callback overloads to CloneContext::Insert*
Change-Id: I2fc0b93d3ea3ba0d9d64fe575364f188db564b8a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/104041
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/tint/clone_context.h b/src/tint/clone_context.h
index 8e045f5..029279b 100644
--- a/src/tint/clone_context.h
+++ b/src/tint/clone_context.h
@@ -203,26 +203,26 @@
auto transforms = list_transforms_.Find(&from);
if (transforms) {
- for (auto* o : transforms->insert_front_) {
- to.Push(CheckedCast<T>(o));
+ for (auto& builder : transforms->insert_front_) {
+ to.Push(CheckedCast<T>(builder()));
}
for (auto& el : from) {
if (auto* insert_before = transforms->insert_before_.Find(el)) {
- for (auto insert : *insert_before) {
- to.Push(CheckedCast<T>(insert));
+ for (auto& builder : *insert_before) {
+ to.Push(CheckedCast<T>(builder()));
}
}
if (!transforms->remove_.Contains(el)) {
to.Push(Clone(el));
}
if (auto* insert_after = transforms->insert_after_.Find(el)) {
- for (auto insert : *insert_after) {
- to.Push(CheckedCast<T>(insert));
+ for (auto& builder : *insert_after) {
+ to.Push(CheckedCast<T>(builder()));
}
}
}
- for (auto* o : transforms->insert_back_) {
- to.Push(CheckedCast<T>(o));
+ for (auto& builder : transforms->insert_back_) {
+ to.Push(CheckedCast<T>(builder()));
}
} else {
for (auto& el : from) {
@@ -232,8 +232,8 @@
// transform for `from`.
if (transforms) {
if (auto* insert_after = transforms->insert_after_.Find(el)) {
- for (auto insert : *insert_after) {
- to.Push(CheckedCast<T>(insert));
+ for (auto& builder : *insert_after) {
+ to.Push(CheckedCast<T>(builder()));
}
}
}
@@ -242,8 +242,8 @@
// Clone(el) may have updated the transformation list, adding an `insert_back_`
// transform for `from`.
if (transforms) {
- for (auto* o : transforms->insert_back_) {
- to.Push(CheckedCast<T>(o));
+ for (auto& builder : transforms->insert_back_) {
+ to.Push(CheckedCast<T>(builder()));
}
}
}
@@ -374,7 +374,7 @@
return *this;
}
- /// Removes `object` from the cloned copy of `vector`.
+ /// Removes @p object from the cloned copy of @p vector.
/// @param vector the vector in #src
/// @param object a pointer to the object in #src that will be omitted from
/// the cloned vector.
@@ -392,7 +392,7 @@
return *this;
}
- /// Inserts `object` before any other objects of `vector`, when it is cloned.
+ /// Inserts @p object before any other objects of @p vector, when the vector is cloned.
/// @param vector the vector in #src
/// @param object a pointer to the object in #dst that will be inserted at the
/// front of the vector
@@ -400,11 +400,21 @@
template <typename T, size_t N, typename OBJECT>
CloneContext& InsertFront(const utils::Vector<T, N>& vector, OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
- list_transforms_.Edit(&vector).insert_front_.Push(object);
+ return InsertFront(vector, [object] { return object; });
+ }
+
+ /// Inserts a lazily built object before any other objects of @p vector, when the vector is
+ /// cloned.
+ /// @param vector the vector in #src
+ /// @param builder a builder of the object that will be inserted at the front of the vector.
+ /// @returns this CloneContext so calls can be chained
+ template <typename T, size_t N, typename BUILDER>
+ CloneContext& InsertFront(const utils::Vector<T, N>& vector, BUILDER&& builder) {
+ list_transforms_.Edit(&vector).insert_front_.Push(std::forward<BUILDER>(builder));
return *this;
}
- /// Inserts `object` after any other objects of `vector`, when it is cloned.
+ /// Inserts @p object after any other objects of @p vector, when the vector is cloned.
/// @param vector the vector in #src
/// @param object a pointer to the object in #dst that will be inserted at the
/// end of the vector
@@ -412,15 +422,26 @@
template <typename T, size_t N, typename OBJECT>
CloneContext& InsertBack(const utils::Vector<T, N>& vector, OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
- list_transforms_.Edit(&vector).insert_back_.Push(object);
+ return InsertBack(vector, [object] { return object; });
+ }
+
+ /// Inserts a lazily built object after any other objects of @p vector, when the vector is
+ /// cloned.
+ /// @param vector the vector in #src
+ /// @param builder the builder of the object in #dst that will be inserted at the end of the
+ /// vector.
+ /// @returns this CloneContext so calls can be chained
+ template <typename T, size_t N, typename BUILDER>
+ CloneContext& InsertBack(const utils::Vector<T, N>& vector, BUILDER&& builder) {
+ list_transforms_.Edit(&vector).insert_back_.Push(std::forward<BUILDER>(builder));
return *this;
}
- /// Inserts `object` before `before` whenever `vector` is cloned.
+ /// Inserts @p object before @p before whenever @p vector is cloned.
/// @param vector the vector in #src
/// @param before a pointer to the object in #src
/// @param object a pointer to the object in #dst that will be inserted before
- /// any occurrence of the clone of `before`
+ /// any occurrence of the clone of @p before
/// @returns this CloneContext so calls can be chained
template <typename T, size_t N, typename BEFORE, typename OBJECT>
CloneContext& InsertBefore(const utils::Vector<T, N>& vector,
@@ -434,15 +455,35 @@
return *this;
}
- list_transforms_.Edit(&vector).insert_before_.GetOrZero(before).Push(object);
+ list_transforms_.Edit(&vector).insert_before_.GetOrZero(before).Push(
+ [object] { return object; });
return *this;
}
- /// Inserts `object` after `after` whenever `vector` is cloned.
+ /// Inserts a lazily created object before @p before whenever @p vector is cloned.
+ /// @param vector the vector in #src
+ /// @param before a pointer to the object in #src
+ /// @param builder the builder of the object in #dst that will be inserted before any occurrence
+ /// of the clone of @p before
+ /// @returns this CloneContext so calls can be chained
+ template <typename T,
+ size_t N,
+ typename BEFORE,
+ typename BUILDER,
+ typename _ = std::enable_if_t<!std::is_pointer_v<std::decay_t<BUILDER>>>>
+ CloneContext& InsertBefore(const utils::Vector<T, N>& vector,
+ const BEFORE* before,
+ BUILDER&& builder) {
+ list_transforms_.Edit(&vector).insert_before_.GetOrZero(before).Push(
+ std::forward<BUILDER>(builder));
+ return *this;
+ }
+
+ /// Inserts @p object after @p after whenever @p vector is cloned.
/// @param vector the vector in #src
/// @param after a pointer to the object in #src
/// @param object a pointer to the object in #dst that will be inserted after
- /// any occurrence of the clone of `after`
+ /// any occurrence of the clone of @p after
/// @returns this CloneContext so calls can be chained
template <typename T, size_t N, typename AFTER, typename OBJECT>
CloneContext& InsertAfter(const utils::Vector<T, N>& vector,
@@ -456,7 +497,27 @@
return *this;
}
- list_transforms_.Edit(&vector).insert_after_.GetOrZero(after).Push(object);
+ list_transforms_.Edit(&vector).insert_after_.GetOrZero(after).Push(
+ [object] { return object; });
+ return *this;
+ }
+
+ /// Inserts a lazily created object after @p after whenever @p vector is cloned.
+ /// @param vector the vector in #src
+ /// @param after a pointer to the object in #src
+ /// @param builder the builder of the object in #dst that will be inserted after any occurrence
+ /// of the clone of @p after
+ /// @returns this CloneContext so calls can be chained
+ template <typename T,
+ size_t N,
+ typename AFTER,
+ typename BUILDER,
+ typename _ = std::enable_if_t<!std::is_pointer_v<std::decay_t<BUILDER>>>>
+ CloneContext& InsertAfter(const utils::Vector<T, N>& vector,
+ const AFTER* after,
+ BUILDER&& builder) {
+ list_transforms_.Edit(&vector).insert_after_.GetOrZero(after).Push(
+ std::forward<BUILDER>(builder));
return *this;
}
@@ -487,7 +548,7 @@
};
/// A vector of const Cloneable*
- using CloneableList = utils::Vector<const Cloneable*, 4>;
+ using CloneableBuilderList = utils::Vector<std::function<const Cloneable*()>, 4>;
/// Transformations to be applied to a list (vector)
struct ListTransforms {
@@ -495,20 +556,20 @@
utils::Hashset<const Cloneable*, 4> remove_;
/// A list of objects in #dst to insert before any others when the vector is cloned.
- CloneableList insert_front_;
+ CloneableBuilderList insert_front_;
/// A list of objects in #dst to insert after all others when the vector is cloned.
- CloneableList insert_back_;
+ CloneableBuilderList insert_back_;
/// A map of object in #src to the list of cloned objects in #dst.
/// Clone(const utils::Vector<T*>& v) will use this to insert the map-value
/// list into the target vector before cloning and inserting the map-key.
- utils::Hashmap<const Cloneable*, CloneableList, 4> insert_before_;
+ utils::Hashmap<const Cloneable*, CloneableBuilderList, 4> insert_before_;
/// A map of object in #src to the list of cloned objects in #dst.
/// Clone(const utils::Vector<T*>& v) will use this to insert the map-value
/// list into the target vector after cloning and inserting the map-key.
- utils::Hashmap<const Cloneable*, CloneableList, 4> insert_after_;
+ utils::Hashmap<const Cloneable*, CloneableBuilderList, 4> insert_after_;
};
CloneContext(const CloneContext&) = delete;
diff --git a/src/tint/clone_context_test.cc b/src/tint/clone_context_test.cc
index c895151..f2ed247 100644
--- a/src/tint/clone_context_test.cc
+++ b/src/tint/clone_context_test.cc
@@ -430,6 +430,39 @@
EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
}
+TEST_F(CloneContextNodeTest, CloneWithInsertFrontFunction) {
+ Allocator a;
+
+ ProgramBuilder builder;
+ auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+ original_root->vec = {
+ a.Create<Node>(builder.Symbols().Register("a")),
+ a.Create<Node>(builder.Symbols().Register("b")),
+ a.Create<Node>(builder.Symbols().Register("c")),
+ };
+ Program original(std::move(builder));
+
+ ProgramBuilder cloned;
+
+ auto* cloned_root =
+ CloneContext(&cloned, &original)
+ .InsertFront(original_root->vec,
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion")); })
+ .Clone(original_root);
+
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
+
+ EXPECT_NE(cloned_root->vec[0], cloned_root->a);
+ EXPECT_NE(cloned_root->vec[1], cloned_root->b);
+ EXPECT_NE(cloned_root->vec[2], cloned_root->c);
+
+ EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+ EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
+ EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("a"));
+ EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("b"));
+ EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
+}
+
TEST_F(CloneContextNodeTest, CloneWithInsertFront_Empty) {
Allocator a;
@@ -451,6 +484,28 @@
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
}
+TEST_F(CloneContextNodeTest, CloneWithInsertFront_Empty_Function) {
+ Allocator a;
+
+ ProgramBuilder builder;
+ auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+ original_root->vec.Clear();
+ Program original(std::move(builder));
+
+ ProgramBuilder cloned;
+
+ auto* cloned_root =
+ CloneContext(&cloned, &original)
+ .InsertFront(original_root->vec,
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion")); })
+ .Clone(original_root);
+
+ EXPECT_EQ(cloned_root->vec.Length(), 1u);
+
+ EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+ EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
+}
+
TEST_F(CloneContextNodeTest, CloneWithInsertBack) {
Allocator a;
@@ -479,6 +534,35 @@
EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("insertion"));
}
+TEST_F(CloneContextNodeTest, CloneWithInsertBack_Function) {
+ Allocator a;
+
+ ProgramBuilder builder;
+ auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+ original_root->vec = {
+ a.Create<Node>(builder.Symbols().Register("a")),
+ a.Create<Node>(builder.Symbols().Register("b")),
+ a.Create<Node>(builder.Symbols().Register("c")),
+ };
+ Program original(std::move(builder));
+
+ ProgramBuilder cloned;
+
+ auto* cloned_root =
+ CloneContext(&cloned, &original)
+ .InsertBack(original_root->vec,
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion")); })
+ .Clone(original_root);
+
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
+
+ EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+ EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+ EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
+ EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("c"));
+ EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("insertion"));
+}
+
TEST_F(CloneContextNodeTest, CloneWithInsertBack_Empty) {
Allocator a;
@@ -500,6 +584,28 @@
EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
}
+TEST_F(CloneContextNodeTest, CloneWithInsertBack_Empty_Function) {
+ Allocator a;
+
+ ProgramBuilder builder;
+ auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+ original_root->vec.Clear();
+ Program original(std::move(builder));
+
+ ProgramBuilder cloned;
+
+ auto* cloned_root =
+ CloneContext(&cloned, &original)
+ .InsertBack(original_root->vec,
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion")); })
+ .Clone(original_root);
+
+ EXPECT_EQ(cloned_root->vec.Length(), 1u);
+
+ EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+ EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
+}
+
TEST_F(CloneContextNodeTest, CloneWithInsertFrontAndBack_Empty) {
Allocator a;
@@ -509,8 +615,8 @@
Program original(std::move(builder));
ProgramBuilder cloned;
- auto* insertion_front = a.Create<Node>(cloned.Symbols().New("insertion_front"));
auto* insertion_back = a.Create<Node>(cloned.Symbols().New("insertion_back"));
+ auto* insertion_front = a.Create<Node>(cloned.Symbols().New("insertion_front"));
auto* cloned_root = CloneContext(&cloned, &original)
.InsertBack(original_root->vec, insertion_back)
@@ -524,6 +630,31 @@
EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion_back"));
}
+TEST_F(CloneContextNodeTest, CloneWithInsertFrontAndBack_Empty_Function) {
+ Allocator a;
+
+ ProgramBuilder builder;
+ auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+ original_root->vec.Clear();
+ Program original(std::move(builder));
+
+ ProgramBuilder cloned;
+
+ auto* cloned_root =
+ CloneContext(&cloned, &original)
+ .InsertBack(original_root->vec,
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion_back")); })
+ .InsertFront(original_root->vec,
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion_front")); })
+ .Clone(original_root);
+
+ EXPECT_EQ(cloned_root->vec.Length(), 2u);
+
+ EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+ EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion_front"));
+ EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion_back"));
+}
+
TEST_F(CloneContextNodeTest, CloneWithInsertBefore) {
Allocator a;
@@ -552,6 +683,35 @@
EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
}
+TEST_F(CloneContextNodeTest, CloneWithInsertBefore_Function) {
+ Allocator a;
+
+ ProgramBuilder builder;
+ auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+ original_root->vec = {
+ a.Create<Node>(builder.Symbols().Register("a")),
+ a.Create<Node>(builder.Symbols().Register("b")),
+ a.Create<Node>(builder.Symbols().Register("c")),
+ };
+ Program original(std::move(builder));
+
+ ProgramBuilder cloned;
+
+ auto* cloned_root =
+ CloneContext(&cloned, &original)
+ .InsertBefore(original_root->vec, original_root->vec[1],
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion")); })
+ .Clone(original_root);
+
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
+
+ EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+ EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+ EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion"));
+ EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("b"));
+ EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
+}
+
TEST_F(CloneContextNodeTest, CloneWithInsertAfter) {
Allocator a;
@@ -580,6 +740,35 @@
EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
}
+TEST_F(CloneContextNodeTest, CloneWithInsertAfter_Function) {
+ Allocator a;
+
+ ProgramBuilder builder;
+ auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+ original_root->vec = {
+ a.Create<Node>(builder.Symbols().Register("a")),
+ a.Create<Node>(builder.Symbols().Register("b")),
+ a.Create<Node>(builder.Symbols().Register("c")),
+ };
+ Program original(std::move(builder));
+
+ ProgramBuilder cloned;
+
+ auto* cloned_root =
+ CloneContext(&cloned, &original)
+ .InsertAfter(original_root->vec, original_root->vec[1],
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion")); })
+ .Clone(original_root);
+
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
+
+ EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+ EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+ EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
+ EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion"));
+ EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
+}
+
TEST_F(CloneContextNodeTest, CloneWithInsertAfterInVectorNodeClone) {
Allocator a;
@@ -612,6 +801,38 @@
EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
}
+TEST_F(CloneContextNodeTest, CloneWithInsertAfterInVectorNodeClone_Function) {
+ Allocator a;
+
+ ProgramBuilder builder;
+ auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+ original_root->vec = {
+ a.Create<Node>(builder.Symbols().Register("a")),
+ a.Create<Replaceable>(builder.Symbols().Register("b")),
+ a.Create<Node>(builder.Symbols().Register("c")),
+ };
+
+ Program original(std::move(builder));
+
+ ProgramBuilder cloned;
+ CloneContext ctx(&cloned, &original);
+ ctx.ReplaceAll([&](const Replaceable* r) {
+ ctx.InsertAfter(original_root->vec, r,
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion")); });
+ return nullptr;
+ });
+
+ auto* cloned_root = ctx.Clone(original_root);
+
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
+
+ EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+ EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+ EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
+ EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion"));
+ EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
+}
+
TEST_F(CloneContextNodeTest, CloneWithInsertBackInVectorNodeClone) {
Allocator a;
@@ -644,6 +865,38 @@
EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("insertion"));
}
+TEST_F(CloneContextNodeTest, CloneWithInsertBackInVectorNodeClone_Function) {
+ Allocator a;
+
+ ProgramBuilder builder;
+ auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+ original_root->vec = {
+ a.Create<Node>(builder.Symbols().Register("a")),
+ a.Create<Replaceable>(builder.Symbols().Register("b")),
+ a.Create<Node>(builder.Symbols().Register("c")),
+ };
+
+ Program original(std::move(builder));
+
+ ProgramBuilder cloned;
+ CloneContext ctx(&cloned, &original);
+ ctx.ReplaceAll([&](const Replaceable* /*r*/) {
+ ctx.InsertBack(original_root->vec,
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion")); });
+ return nullptr;
+ });
+
+ auto* cloned_root = ctx.Clone(original_root);
+
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
+
+ EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+ EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+ EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
+ EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("c"));
+ EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("insertion"));
+}
+
TEST_F(CloneContextNodeTest, CloneWithInsertBeforeAndAfterRemoved) {
Allocator a;
@@ -676,6 +929,38 @@
EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
}
+TEST_F(CloneContextNodeTest, CloneWithInsertBeforeAndAfterRemoved_Function) {
+ Allocator a;
+
+ ProgramBuilder builder;
+ auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+ original_root->vec = {
+ a.Create<Node>(builder.Symbols().Register("a")),
+ a.Create<Node>(builder.Symbols().Register("b")),
+ a.Create<Node>(builder.Symbols().Register("c")),
+ };
+ Program original(std::move(builder));
+
+ ProgramBuilder cloned;
+
+ auto* cloned_root =
+ CloneContext(&cloned, &original)
+ .InsertBefore(original_root->vec, original_root->vec[1],
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion_before")); })
+ .InsertAfter(original_root->vec, original_root->vec[1],
+ [&] { return a.Create<Node>(cloned.Symbols().New("insertion_after")); })
+ .Remove(original_root->vec, original_root->vec[1])
+ .Clone(original_root);
+
+ EXPECT_EQ(cloned_root->vec.Length(), 4u);
+
+ EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+ EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+ EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion_before"));
+ EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion_after"));
+ EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
+}
+
TEST_F(CloneContextNodeTest, CloneIntoSameBuilder) {
ProgramBuilder builder;
CloneContext ctx(&builder);