diff --git a/src/clone_context.h b/src/clone_context.h index c743d3b6aa..0b20d25eeb 100644 --- a/src/clone_context.h +++ b/src/clone_context.h @@ -246,6 +246,9 @@ class CloneContext { } } } + for (auto* o : transforms.insert_back_) { + out.emplace_back(CheckedCast(o)); + } } else { for (auto& el : v) { out.emplace_back(Clone(el)); @@ -391,6 +394,20 @@ class CloneContext { return *this; } + /// Inserts `object` after any other objects of `vector`, when it 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 + /// @returns this CloneContext so calls can be chained + template + CloneContext& InsertBack(const std::vector& vector, OBJECT* object) { + TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(dst, object); + auto& transforms = list_transforms_[&vector]; + auto& list = transforms.insert_back_; + list.emplace_back(object); + return *this; + } + /// Inserts `object` before `before` whenever `vector` is cloned. /// @param vector the vector in #src /// @param before a pointer to the object in #src @@ -502,6 +519,10 @@ class CloneContext { /// cloned. CloneableList insert_front_; + /// A list of objects in #dst to insert befor after any others when the + /// vector is cloned. + CloneableList insert_back_; + /// A map of object in #src to the list of cloned objects in #dst. /// Clone(const std::vector& v) will use this to insert the map-value /// list into the target vector before cloning and inserting the map-key. diff --git a/src/clone_context_test.cc b/src/clone_context_test.cc index ccf18a9638..bd469da9b3 100644 --- a/src/clone_context_test.cc +++ b/src/clone_context_test.cc @@ -401,6 +401,79 @@ TEST_F(CloneContextNodeTest, CloneWithInsertFront_Empty) { EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion")); } +TEST_F(CloneContextNodeTest, CloneWithInsertBack) { + Allocator a; + + ProgramBuilder builder; + auto* original_root = a.Create(builder.Symbols().Register("root")); + original_root->a = a.Create(builder.Symbols().Register("a")); + original_root->b = a.Create(builder.Symbols().Register("b")); + original_root->c = a.Create(builder.Symbols().Register("c")); + original_root->vec = {original_root->a, original_root->b, original_root->c}; + Program original(std::move(builder)); + + ProgramBuilder cloned; + auto* insertion = a.Create(cloned.Symbols().New("insertion")); + + auto* cloned_root = CloneContext(&cloned, &original) + .InsertBack(original_root->vec, insertion) + .Clone(original_root); + + EXPECT_EQ(cloned_root->vec.size(), 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; + + ProgramBuilder builder; + auto* original_root = a.Create(builder.Symbols().Register("root")); + original_root->vec = {}; + Program original(std::move(builder)); + + ProgramBuilder cloned; + auto* insertion = a.Create(cloned.Symbols().New("insertion")); + + auto* cloned_root = CloneContext(&cloned, &original) + .InsertBack(original_root->vec, insertion) + .Clone(original_root); + + EXPECT_EQ(cloned_root->vec.size(), 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; + + ProgramBuilder builder; + auto* original_root = a.Create(builder.Symbols().Register("root")); + original_root->vec = {}; + Program original(std::move(builder)); + + ProgramBuilder cloned; + auto* insertion_front = + a.Create(cloned.Symbols().New("insertion_front")); + auto* insertion_back = a.Create(cloned.Symbols().New("insertion_back")); + + auto* cloned_root = CloneContext(&cloned, &original) + .InsertBack(original_root->vec, insertion_back) + .InsertFront(original_root->vec, insertion_front) + .Clone(original_root); + + EXPECT_EQ(cloned_root->vec.size(), 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;