Vulkan/Debug: Add File

Files represent either physical, filesystem-backed files, or virtual debugger-produced files.

Bug: b/145351270
Change-Id: Ib085a1244cc10dc644546d1d049d1bfa030744ff
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38895
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Vulkan/Debug/File.cpp b/src/Vulkan/Debug/File.cpp
new file mode 100644
index 0000000..2185a0b
--- /dev/null
+++ b/src/Vulkan/Debug/File.cpp
@@ -0,0 +1,131 @@
+// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
+//
+// 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 "File.hpp"
+
+#include <mutex>
+#include <unordered_set>
+
+namespace
+{
+
+////////////////////////////////////////////////////////////////////////////////
+// FileBase
+////////////////////////////////////////////////////////////////////////////////
+class FileBase : public vk::dbg::File
+{
+public:
+	void clearBreakpoints() override;
+	void addBreakpoint(int line) override;
+	bool hasBreakpoint(int line) const override;
+
+protected:
+	FileBase(ID id, std::string dir, std::string name, std::string source);
+
+private:
+	mutable std::mutex breakpointMutex;
+	std::unordered_set<int> breakpoints;  // guarded by breakpointMutex
+};
+
+FileBase::FileBase(ID id, std::string dir, std::string name, std::string source) :
+    File(id, std::move(dir), std::move(name), std::move(source)) {}
+
+void FileBase::clearBreakpoints()
+{
+	std::unique_lock<std::mutex> lock(breakpointMutex);
+	breakpoints.clear();
+}
+
+void FileBase::addBreakpoint(int line)
+{
+	std::unique_lock<std::mutex> lock(breakpointMutex);
+	breakpoints.emplace(line);
+}
+
+bool FileBase::hasBreakpoint(int line) const
+{
+	std::unique_lock<std::mutex> lock(breakpointMutex);
+	return breakpoints.count(line) > 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// VirtualFile
+////////////////////////////////////////////////////////////////////////////////
+class VirtualFile : public FileBase
+{
+public:
+	VirtualFile(ID id, std::string name, std::string source);
+
+	bool isVirtual() const override;
+
+private:
+};
+
+VirtualFile::VirtualFile(ID id, std::string name, std::string source) :
+    FileBase(id, "", std::move(name), std::move(source)) {}
+
+bool VirtualFile::isVirtual() const
+{
+	return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PhysicalFile
+////////////////////////////////////////////////////////////////////////////////
+struct PhysicalFile : public FileBase
+{
+	PhysicalFile(ID id,
+	             std::string dir,
+	             std::string name);
+
+	bool isVirtual() const override;
+};
+
+PhysicalFile::PhysicalFile(ID id,
+                           std::string dir,
+                           std::string name) :
+    FileBase(id, std::move(dir), std::move(name), "") {}
+
+bool PhysicalFile::isVirtual() const
+{
+	return false;
+}
+
+}  // anonymous namespace
+
+namespace vk
+{
+namespace dbg
+{
+
+std::shared_ptr<File> File::createVirtual(ID id, std::string name, std::string source)
+{
+	return std::make_shared<VirtualFile>(id, std::move(name), std::move(source));
+}
+
+std::shared_ptr<File> File::createPhysical(ID id, std::string path)
+{
+	auto pathstr = path;
+	auto pos = pathstr.rfind("/");
+	if(pos != std::string::npos)
+	{
+		auto dir = pathstr.substr(0, pos);
+		auto name = pathstr.substr(pos + 1);
+		return std::make_shared<PhysicalFile>(id, dir.c_str(), name.c_str());
+	}
+	return std::make_shared<PhysicalFile>(id, "", std::move(path));
+}
+
+}  // namespace dbg
+}  // namespace vk
\ No newline at end of file