From f77771e21b726245a2e41c50f13e6fadf14b2715 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Tue, 16 Feb 2021 23:09:31 +0000 Subject: [PATCH] CloneContext: Add InsertBefore() Inserts objects before others when cloning Change-Id: Ibf247abae3aeb3d351048f1182db2a2b42b2c677 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/41547 Commit-Queue: Ben Clayton Reviewed-by: David Neto Reviewed-by: dan sinclair --- src/clone_context.h | 48 ++++++++++++++++ src/clone_context_test.cc | 113 ++++++++++++++++++++++++++++---------- 2 files changed, 131 insertions(+), 30 deletions(-) diff --git a/src/clone_context.h b/src/clone_context.h index 8424b73086..0442b3ec9d 100644 --- a/src/clone_context.h +++ b/src/clone_context.h @@ -151,6 +151,30 @@ class CloneContext { return out; } + /// Clones each of the elements of the vector `v` into the ProgramBuilder + /// #dst, inserting any additional elements into the list that were registered + /// with calls to InsertBefore(). + /// + /// All the elements of the vector `v` must be owned by the Program #src. + /// + /// @param v the vector to clone + /// @return the cloned vector + template + std::vector Clone(const std::vector& v) { + std::vector out; + out.reserve(v.size()); + for (auto& el : v) { + auto it = insert_before_.find(el); + if (it != insert_before_.end()) { + for (auto insert : it->second) { + out.emplace_back(CheckedCast(insert)); + } + } + out.emplace_back(Clone(el)); + } + return out; + } + /// Clones each of the elements of the vector `v` into the ProgramBuilder /// #dst. /// @@ -219,6 +243,19 @@ class CloneContext { return *this; } + /// Inserts `object` before `before` whenever a vector containing `object` is + /// cloned. + /// @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` + /// @returns this CloneContext so calls can be chained + template + CloneContext& InsertBefore(BEFORE* before, OBJECT* object) { + auto& list = insert_before_[before]; + list.emplace_back(object); + return *this; + } + /// Clone performs the clone of the entire Program #src to #dst. void Clone(); @@ -266,7 +303,18 @@ class CloneContext { return cast; } + /// A vector of CastableBase* + using CastableList = std::vector; + + /// A map of object in #src to their cloned equivalent in #dst std::unordered_map cloned_; + + /// 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. + std::unordered_map insert_before_; + + /// Transform functions registered with ReplaceAll() std::vector transforms_; }; diff --git a/src/clone_context_test.cc b/src/clone_context_test.cc index 5e47cb2117..edeed3ab35 100644 --- a/src/clone_context_test.cc +++ b/src/clone_context_test.cc @@ -14,7 +14,9 @@ #include "src/clone_context.h" +#include #include +#include #include "gtest/gtest.h" @@ -24,17 +26,21 @@ namespace tint { namespace { struct Cloneable : public Castable { - explicit Cloneable(const Source& source) : Base(source) {} + explicit Cloneable(const Source& source, std::string n) + : Base(source), name(n) {} + std::string name; Cloneable* a = nullptr; Cloneable* b = nullptr; Cloneable* c = nullptr; + std::vector vec; Cloneable* Clone(CloneContext* ctx) const override { - auto* out = ctx->dst->create(); + auto* out = ctx->dst->create(name); out->a = ctx->Clone(a); out->b = ctx->Clone(b); out->c = ctx->Clone(c); + out->vec = ctx->Clone(vec); return out; } @@ -43,10 +49,10 @@ struct Cloneable : public Castable { }; struct Replaceable : public Castable { - explicit Replaceable(const Source& source) : Base(source) {} + explicit Replaceable(const Source& source, std::string n) : Base(source, n) {} }; struct Replacement : public Castable { - explicit Replacement(const Source& source) : Base(source) {} + explicit Replacement(const Source& source, std::string n) : Base(source, n) {} }; struct NotACloneable : public Castable { @@ -62,12 +68,12 @@ struct NotACloneable : public Castable { TEST(CloneContext, Clone) { ProgramBuilder builder; - auto* original_root = builder.create(); - original_root->a = builder.create(); - original_root->a->b = builder.create(); - original_root->b = builder.create(); + auto* original_root = builder.create("root"); + original_root->a = builder.create("a"); + original_root->a->b = builder.create("a->b"); + original_root->b = builder.create("b"); original_root->b->a = original_root->a; // Aliased - original_root->b->b = builder.create(); + original_root->b->b = builder.create("b->b"); original_root->c = original_root->b; // Aliased Program original(std::move(builder)); @@ -101,16 +107,22 @@ TEST(CloneContext, Clone) { EXPECT_NE(cloned_root->b->b, original_root->b->b); EXPECT_NE(cloned_root->c, original_root->c); + EXPECT_EQ(cloned_root->name, "root"); + EXPECT_EQ(cloned_root->a->name, "a"); + EXPECT_EQ(cloned_root->a->b->name, "a->b"); + EXPECT_EQ(cloned_root->b->name, "b"); + EXPECT_EQ(cloned_root->b->b->name, "b->b"); + EXPECT_EQ(cloned_root->b->a, cloned_root->a); // Aliased EXPECT_EQ(cloned_root->c, cloned_root->b); // Aliased } TEST(CloneContext, CloneWithReplacements) { ProgramBuilder builder; - auto* original_root = builder.create(); - original_root->a = builder.create(); - original_root->a->b = builder.create(); - original_root->b = builder.create(); + auto* original_root = builder.create("root"); + original_root->a = builder.create("a"); + original_root->a->b = builder.create("a->b"); + original_root->b = builder.create("b"); original_root->b->a = original_root->a; // Aliased original_root->c = original_root->b; // Aliased Program original(std::move(builder)); @@ -127,14 +139,15 @@ TEST(CloneContext, CloneWithReplacements) { // R: Replaceable ProgramBuilder cloned; - auto* cloned_root = CloneContext(&cloned, &original) - .ReplaceAll([&](CloneContext* ctx, Replaceable* in) { - auto* out = cloned.create(); - out->b = cloned.create(); - out->c = ctx->Clone(in->a); - return out; - }) - .Clone(original_root); + auto* cloned_root = + CloneContext(&cloned, &original) + .ReplaceAll([&](CloneContext* ctx, Replaceable* in) { + auto* out = cloned.create("replacement:" + in->name); + out->b = cloned.create("replacement-child:" + in->name); + out->c = ctx->Clone(in->a); + return out; + }) + .Clone(original_root); // root // ╭─────────────────┼──────────────────╮ @@ -169,6 +182,13 @@ TEST(CloneContext, CloneWithReplacements) { EXPECT_NE(cloned_root->b->a, original_root->b->a); EXPECT_NE(cloned_root->c, original_root->c); + EXPECT_EQ(cloned_root->name, "root"); + EXPECT_EQ(cloned_root->a->name, "a"); + EXPECT_EQ(cloned_root->a->b->name, "replacement:a->b"); + EXPECT_EQ(cloned_root->a->b->b->name, "replacement-child:a->b"); + EXPECT_EQ(cloned_root->b->name, "replacement:b"); + EXPECT_EQ(cloned_root->b->b->name, "replacement-child:b"); + EXPECT_EQ(cloned_root->b->c, cloned_root->a); // Aliased EXPECT_EQ(cloned_root->c, cloned_root->b); // Aliased @@ -181,10 +201,10 @@ TEST(CloneContext, CloneWithReplacements) { TEST(CloneContext, CloneWithReplace) { ProgramBuilder builder; - auto* original_root = builder.create(); - original_root->a = builder.create(); - original_root->b = builder.create(); - original_root->c = builder.create(); + auto* original_root = builder.create("root"); + original_root->a = builder.create("a"); + original_root->b = builder.create("b"); + original_root->c = builder.create("c"); Program original(std::move(builder)); // root @@ -193,7 +213,7 @@ TEST(CloneContext, CloneWithReplace) { // Replaced ProgramBuilder cloned; - auto* replacement = cloned.create(); + auto* replacement = cloned.create("replacement"); auto* cloned_root = CloneContext(&cloned, &original) .Replace(original_root->b, replacement) @@ -202,14 +222,47 @@ TEST(CloneContext, CloneWithReplace) { EXPECT_NE(cloned_root->a, replacement); EXPECT_EQ(cloned_root->b, replacement); EXPECT_NE(cloned_root->c, replacement); + + EXPECT_EQ(cloned_root->name, "root"); + EXPECT_EQ(cloned_root->a->name, "a"); + EXPECT_EQ(cloned_root->b->name, "replacement"); + EXPECT_EQ(cloned_root->c->name, "c"); +} + +TEST(CloneContext, CloneWithInsertBefore) { + ProgramBuilder builder; + auto* original_root = builder.create("root"); + original_root->a = builder.create("a"); + original_root->b = builder.create("b"); + original_root->c = builder.create("c"); + original_root->vec = {original_root->a, original_root->b, original_root->c}; + Program original(std::move(builder)); + + ProgramBuilder cloned; + auto* insertion = cloned.create("insertion"); + + auto* cloned_root = CloneContext(&cloned, &original) + .InsertBefore(original_root->b, insertion) + .Clone(original_root); + + EXPECT_EQ(cloned_root->vec.size(), 4u); + EXPECT_EQ(cloned_root->vec[0], cloned_root->a); + EXPECT_EQ(cloned_root->vec[2], cloned_root->b); + EXPECT_EQ(cloned_root->vec[3], cloned_root->c); + + EXPECT_EQ(cloned_root->name, "root"); + EXPECT_EQ(cloned_root->vec[0]->name, "a"); + EXPECT_EQ(cloned_root->vec[1]->name, "insertion"); + EXPECT_EQ(cloned_root->vec[2]->name, "b"); + EXPECT_EQ(cloned_root->vec[3]->name, "c"); } TEST(CloneContext, CloneWithReplace_WithNotACloneable) { ProgramBuilder builder; - auto* original_root = builder.create(); - original_root->a = builder.create(); - original_root->b = builder.create(); - original_root->c = builder.create(); + auto* original_root = builder.create("root"); + original_root->a = builder.create("a"); + original_root->b = builder.create("b"); + original_root->c = builder.create("c"); Program original(std::move(builder)); // root