Add reader::spirv::Namer
A Namer is a place for saving and looking up names
based on SPIR-V IDs.
Bug: tint:3
Change-Id: I6aeb2f5f7ba63c2e0a816dcbac88f964beafabc6
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/17284
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bf0c2e1..2c615df 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -199,6 +199,8 @@
if(${TINT_BUILD_SPV_READER})
list(APPEND TINT_LIB_SRCS
reader/spirv/fail_stream.h
+ reader/spirv/namer.cc
+ reader/spirv/namer.h
reader/spirv/parser.cc
reader/spirv/parser.h
reader/spirv/parser_impl.cc
@@ -313,6 +315,7 @@
if(${TINT_BUILD_SPV_READER})
list(APPEND TINT_TEST_SRCS
reader/spirv/fail_stream_test.cc
+ reader/spirv/namer_test.cc
reader/spirv/parser_impl_import_test.cc
reader/spirv/parser_impl_test.cc
reader/spirv/parser_test.cc
diff --git a/src/reader/spirv/namer.cc b/src/reader/spirv/namer.cc
new file mode 100644
index 0000000..8f316c9
--- /dev/null
+++ b/src/reader/spirv/namer.cc
@@ -0,0 +1,36 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/reader/spirv/namer.h"
+
+namespace tint {
+namespace reader {
+namespace spirv {
+
+Namer::Namer(const FailStream& fail_stream) : fail_stream_(fail_stream) {}
+
+Namer::~Namer() = default;
+
+bool Namer::SaveName(uint32_t id, const std::string& name) {
+ if (HasName(id)) {
+ return Fail() << "internal error: ID " << id
+ << " already has registered name: " << id_to_name_[id];
+ }
+ id_to_name_[id] = name;
+ return true;
+}
+
+} // namespace spirv
+} // namespace reader
+} // namespace tint
diff --git a/src/reader/spirv/namer.h b/src/reader/spirv/namer.h
new file mode 100644
index 0000000..03fc531
--- /dev/null
+++ b/src/reader/spirv/namer.h
@@ -0,0 +1,71 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_READER_SPIRV_NAMER_H_
+#define SRC_READER_SPIRV_NAMER_H_
+
+#include <cstdint>
+#include <string>
+#include <unordered_map>
+
+#include "src/reader/spirv/fail_stream.h"
+
+namespace tint {
+namespace reader {
+namespace spirv {
+
+/// A Namer maps SPIR-V IDs to strings.
+class Namer {
+ public:
+ /// Creates a new namer
+ /// @param fail_stream the error reporting stream
+ explicit Namer(const FailStream& fail_stream);
+ /// Destructor
+ ~Namer();
+
+ /// Registers a failure.
+ /// @returns a fail stream to accumulate diagnostics.
+ FailStream& Fail() { return fail_stream_.Fail(); }
+
+ /// @param id the SPIR-V ID
+ /// @returns true if we the given ID already has a registered name.
+ bool HasName(uint32_t id) {
+ return id_to_name_.find(id) != id_to_name_.end();
+ }
+
+ /// @param id the SPIR-V ID
+ /// @returns the name for the ID. It must have been registered.
+ const std::string& GetName(uint32_t id) {
+ return id_to_name_.find(id)->second;
+ }
+
+ /// Records a mapping from the given ID to a name. Emits a failure
+ /// if the ID already has a registered name.
+ /// @param id the SPIR-V ID
+ /// @param name the name to map to the ID
+ /// @returns true if the ID did not have a previously registered name.
+ bool SaveName(uint32_t id, const std::string& name);
+
+ private:
+ FailStream fail_stream_;
+
+ // Maps an ID to its registered name.
+ std::unordered_map<uint32_t, std::string> id_to_name_;
+};
+
+} // namespace spirv
+} // namespace reader
+} // namespace tint
+
+#endif // SRC_READER_SPIRV_NAMER_H_
diff --git a/src/reader/spirv/namer_test.cc b/src/reader/spirv/namer_test.cc
new file mode 100644
index 0000000..aa6eeee
--- /dev/null
+++ b/src/reader/spirv/namer_test.cc
@@ -0,0 +1,107 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/reader/spirv/namer.h"
+
+#include <cstdint>
+#include <sstream>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "src/reader/spirv/fail_stream.h"
+
+namespace tint {
+namespace reader {
+namespace spirv {
+namespace {
+
+class SpvNamerTest : public testing::Test {
+ public:
+ SpvNamerTest() : fail_stream_(&success_, &errors_) {}
+
+ /// @returns the accumulated diagnostic strings
+ std::string error() { return errors_.str(); }
+
+ protected:
+ std::stringstream errors_;
+ bool success_ = true;
+ FailStream fail_stream_;
+};
+
+TEST_F(SpvNamerTest, NoFailureToStart) {
+ Namer namer(fail_stream_);
+ EXPECT_TRUE(success_);
+ EXPECT_TRUE(error().empty());
+}
+
+TEST_F(SpvNamerTest, FailLogsError) {
+ Namer namer(fail_stream_);
+ const bool converted_result = namer.Fail() << "st. johns wood";
+ EXPECT_FALSE(converted_result);
+ EXPECT_EQ(error(), "st. johns wood");
+ EXPECT_FALSE(success_);
+}
+
+TEST_F(SpvNamerTest, NoNameRecorded) {
+ Namer namer(fail_stream_);
+
+ EXPECT_FALSE(namer.HasName(12));
+ EXPECT_TRUE(success_);
+ EXPECT_TRUE(error().empty());
+}
+
+TEST_F(SpvNamerTest, SaveNameOnce) {
+ Namer namer(fail_stream_);
+
+ const uint32_t id = 9;
+ EXPECT_FALSE(namer.HasName(id));
+ const bool save_result = namer.SaveName(id, "abbey road");
+ EXPECT_TRUE(save_result);
+ EXPECT_TRUE(namer.HasName(id));
+ EXPECT_EQ(namer.GetName(id), "abbey road");
+ EXPECT_TRUE(success_);
+ EXPECT_TRUE(error().empty());
+}
+
+TEST_F(SpvNamerTest, SaveNameTwoIds) {
+ Namer namer(fail_stream_);
+
+ EXPECT_FALSE(namer.HasName(8));
+ EXPECT_FALSE(namer.HasName(9));
+ EXPECT_TRUE(namer.SaveName(8, "abbey road"));
+ EXPECT_TRUE(namer.SaveName(9, "rubber soul"));
+ EXPECT_TRUE(namer.HasName(8));
+ EXPECT_TRUE(namer.HasName(9));
+ EXPECT_EQ(namer.GetName(9), "rubber soul");
+ EXPECT_EQ(namer.GetName(8), "abbey road");
+ EXPECT_TRUE(success_);
+ EXPECT_TRUE(error().empty());
+}
+
+TEST_F(SpvNamerTest, SaveNameFailsDueToIdReuse) {
+ Namer namer(fail_stream_);
+
+ const uint32_t id = 9;
+ EXPECT_TRUE(namer.SaveName(id, "abbey road"));
+ EXPECT_FALSE(namer.SaveName(id, "rubber soul"));
+ EXPECT_TRUE(namer.HasName(id));
+ EXPECT_EQ(namer.GetName(id), "abbey road");
+ EXPECT_FALSE(success_);
+ EXPECT_FALSE(error().empty());
+}
+
+} // namespace
+} // namespace spirv
+} // namespace reader
+} // namespace tint