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
diff --git a/src/Vulkan/Debug/File.hpp b/src/Vulkan/Debug/File.hpp
new file mode 100644
index 0000000..d67316d
--- /dev/null
+++ b/src/Vulkan/Debug/File.hpp
@@ -0,0 +1,95 @@
+// 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.
+
+#ifndef VK_DEBUG_FILE_HPP_
+#define VK_DEBUG_FILE_HPP_
+
+#include "ID.hpp"
+
+#include <memory>
+#include <string>
+
+namespace vk
+{
+namespace dbg
+{
+
+class File
+{
+public:
+	using ID = dbg::ID<File>;
+
+	// createVirtual() returns a new file that is not backed by the filesystem.
+	// name is the name of the file.
+	// source is the content of the file.
+	static std::shared_ptr<File> createVirtual(ID id, std::string name, std::string source);
+
+	// createPhysical() returns a new file that is backed by the file at path.
+	static std::shared_ptr<File> createPhysical(ID id, std::string path);
+
+	// clearBreakpoints() removes all the breakpoints set on the file.
+	// This function and addBreakpoint() is safe to call concurrently on
+	// multiple threads.
+	virtual void clearBreakpoints() = 0;
+
+	// addBreakpoint() adds a new line breakpoint at the line with the given
+	// index.
+	// This function and clearBreakpoints() is safe to call concurrently on
+	// multiple threads.
+	virtual void addBreakpoint(int line) = 0;
+
+	// hasBreakpoint() returns true iff the file has a breakpoint set at the
+	// line with the given index.
+	virtual bool hasBreakpoint(int line) const = 0;
+
+	// isVirtual() returns true iff the file is not backed by the filesystem.
+	virtual bool isVirtual() const = 0;
+
+	// path() returns the path to the file, if backed by the filesystem,
+	// otherwise and empty string.
+	inline std::string path() const;
+
+	// The unique identifier of the file.
+	const ID id;
+
+	// The directory of file if backed by the filesystem, otherwise an empty string.
+	const std::string dir;
+
+	// The name of the file.
+	const std::string name;
+
+	// The source of the file if not backed by the filesystem, otherwise an empty string.
+	const std::string source;
+
+	virtual ~File() = default;
+
+protected:
+	inline File(ID id, std::string dir, std::string name, std::string source);
+};
+
+File::File(ID id, std::string dir, std::string name, std::string source) :
+    id(std::move(id)),
+    dir(std::move(dir)),
+    name(std::move(name)),
+    source(source) {}
+
+std::string File::path() const
+{
+	return (dir.size() > 0) ? (dir + "/" + name) : name;
+}
+
+}  // namespace dbg
+}  // namespace vk
+
+#endif  // VK_DEBUG_FILE_HPP_