Vulkan/Debug: Add Value and Variable

The Value interface exposes values to the debugger.
Variables are named values.
VariableContainer is a collection of Variables.

Bug: b/145351270
Change-Id: Iae3749447554977f84bfc6e58f37b52aa6ed262f
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38893
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/Value.cpp b/src/Vulkan/Debug/Value.cpp
new file mode 100644
index 0000000..db7f1ca
--- /dev/null
+++ b/src/Vulkan/Debug/Value.cpp
@@ -0,0 +1,80 @@
+// 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 "Type.hpp"
+#include "Value.hpp"
+#include "Variable.hpp"
+
+namespace vk
+{
+namespace dbg
+{
+
+const FormatFlags FormatFlags::Default = {
+	"[",                   // listPrefix
+	"]",                   // listSuffix
+	", ",                  // listDelimiter
+	"",                    // listIndent
+	&FormatFlags::Default, // subListFmt
+};
+
+std::string Value::string(const FormatFlags& fmt /* = FormatFlags::Default */) const
+{
+	switch(type()->kind)
+	{
+	case Kind::Bool:
+		return *reinterpret_cast<const bool*>(get()) ? "true" : "false";
+	case Kind::U8:
+		return std::to_string(*reinterpret_cast<const uint8_t*>(get()));
+	case Kind::S8:
+		return std::to_string(*reinterpret_cast<const int8_t*>(get()));
+	case Kind::U16:
+		return std::to_string(*reinterpret_cast<const uint16_t*>(get()));
+	case Kind::S16:
+		return std::to_string(*reinterpret_cast<const int16_t*>(get()));
+	case Kind::F32:
+		return std::to_string(*reinterpret_cast<const float*>(get()));
+	case Kind::U32:
+		return std::to_string(*reinterpret_cast<const uint32_t*>(get()));
+	case Kind::S32:
+		return std::to_string(*reinterpret_cast<const int32_t*>(get()));
+	case Kind::F64:
+		return std::to_string(*reinterpret_cast<const double*>(get()));
+	case Kind::U64:
+		return std::to_string(*reinterpret_cast<const uint64_t*>(get()));
+	case Kind::S64:
+		return std::to_string(*reinterpret_cast<const int64_t*>(get()));
+	case Kind::Ptr:
+		return std::to_string(reinterpret_cast<uintptr_t>(get()));
+	case Kind::VariableContainer:
+		auto const* vc = static_cast<const VariableContainer*>(this);
+		std::string out = "";
+		auto subfmt = *fmt.subListFmt;
+		subfmt.listIndent = fmt.listIndent + fmt.subListFmt->listIndent;
+		bool first = true;
+		vc->foreach(0, [&](const Variable& var) {
+			if(!first) { out += fmt.listDelimiter; }
+			first = false;
+			out += fmt.listIndent;
+			out += var.name;
+			out += ": ";
+			out += var.value->string(subfmt);
+		});
+		return fmt.listPrefix + out + fmt.listSuffix;
+	}
+	return "";
+}
+
+}  // namespace dbg
+}  // namespace vk
\ No newline at end of file
diff --git a/src/Vulkan/Debug/Value.hpp b/src/Vulkan/Debug/Value.hpp
new file mode 100644
index 0000000..c45b33c
--- /dev/null
+++ b/src/Vulkan/Debug/Value.hpp
@@ -0,0 +1,104 @@
+// 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_VALUE_HPP_
+#define VK_DEBUG_VALUE_HPP_
+
+#include <memory>
+#include <string>
+
+namespace vk
+{
+namespace dbg
+{
+
+class Type;
+
+// FormatFlags holds settings used to serialize a Value to a string.
+struct FormatFlags
+{
+	// The default FormatFlags used to serialize a Value to a string.
+	static const FormatFlags Default;
+
+	std::string listPrefix;         // Prefix to lists.
+	std::string listSuffix;         // Suffix to lists.
+	std::string listDelimiter;      // List item delimiter.
+	std::string listIndent;         // List item indententation prefix.
+	const FormatFlags* subListFmt;  // Format used for list sub items.
+};
+
+// Value holds a value that can be read and possible written to.
+class Value
+{
+public:
+	virtual ~Value() = default;
+
+	// type() returns the value's type.
+	virtual std::shared_ptr<Type> type() const = 0;
+
+	// string() returns a string representation of the value using the specified
+	// FormatFlags.
+	virtual std::string string(const FormatFlags& = FormatFlags::Default) const;
+
+	// get() returns a pointer to the value.
+	virtual const void* get() const = 0;
+
+	// set() changes the value to a copy of the value at ptr.
+	// set() returns true if the value was changed, or false if the value cannot
+	// be set.
+	virtual bool set(void* ptr) { return false; }
+};
+
+// Constant is an immutable value.
+template <typename T>
+class Constant : public Value
+{
+public:
+	inline Constant(const T& value);
+	inline std::shared_ptr<Type> type() const override;
+	inline const void* get() const override;
+
+private:
+	const T value;
+};
+
+template <typename T>
+Constant<T>::Constant(const T& value) :
+    value(value)
+{
+}
+
+template <typename T>
+std::shared_ptr<Type> Constant<T>::type() const
+{
+	return TypeOf<T>::get();
+}
+
+template <typename T>
+const void* Constant<T>::get() const
+{
+	return &value;
+}
+
+// make_constant() returns a shared_ptr to a Constant with the given value.
+template <typename T>
+inline std::shared_ptr<Constant<T>> make_constant(const T& value)
+{
+	return std::shared_ptr<Constant<T>>(new vk::dbg::Constant<T>(value));
+}
+
+}  // namespace dbg
+}  // namespace vk
+
+#endif  // VK_DEBUG_VALUE_HPP_
\ No newline at end of file
diff --git a/src/Vulkan/Debug/Variable.hpp b/src/Vulkan/Debug/Variable.hpp
new file mode 100644
index 0000000..15b50b3
--- /dev/null
+++ b/src/Vulkan/Debug/Variable.hpp
@@ -0,0 +1,139 @@
+// 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_VARIABLE_HPP_
+#define VK_DEBUG_VARIABLE_HPP_
+
+#include "ID.hpp"
+#include "Type.hpp"
+#include "Value.hpp"
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace vk
+{
+namespace dbg
+{
+
+// Variable is a named value.
+struct Variable
+{
+	std::string name;
+	std::shared_ptr<Value> value;
+};
+
+// VariableContainer is a collection of named values.
+class VariableContainer : public Value
+{
+public:
+	using ID = dbg::ID<VariableContainer>;
+
+	inline VariableContainer(ID id);
+
+	// foreach() calls cb with each of the variables in the container.
+	// F must be a function with the signature void(const Variable&).
+	template <typename F>
+	inline void foreach(size_t startIndex, const F& cb) const;
+
+	// find() looks up the variable with the given name.
+	// If the variable with the given name is found, cb is called with the
+	// variable and find() returns true.
+	template <typename F>
+	inline bool find(const std::string& name, const F& cb) const;
+
+	// put() places the variable var into the container.
+	inline void put(const Variable& var);
+
+	// put() places the variable with the given name and value into the container.
+	inline void put(const std::string& name, const std::shared_ptr<Value>& value);
+
+	// The unique identifier of the variable.
+	const ID id;
+
+private:
+	inline std::shared_ptr<Type> type() const override;
+	inline const void* get() const override;
+
+	mutable std::mutex mutex;
+	std::vector<Variable> variables;
+	std::unordered_map<std::string, int> indices;
+};
+
+VariableContainer::VariableContainer(ID id) :
+    id(id) {}
+
+template <typename F>
+void VariableContainer::foreach(size_t startIndex, const F& cb) const
+{
+	std::unique_lock<std::mutex> lock(mutex);
+	for(size_t i = startIndex; i < variables.size(); i++)
+	{
+		cb(variables[i]);
+	}
+}
+
+template <typename F>
+bool VariableContainer::find(const std::string& name, const F& cb) const
+{
+	std::unique_lock<std::mutex> lock(mutex);
+	for(auto const& var : variables)
+	{
+		if(var.name == name)
+		{
+			cb(var);
+			return true;
+		}
+	}
+	return false;
+}
+
+void VariableContainer::put(const Variable& var)
+{
+	std::unique_lock<std::mutex> lock(mutex);
+	auto it = indices.find(var.name);
+	if(it == indices.end())
+	{
+		indices.emplace(var.name, variables.size());
+		variables.push_back(var);
+	}
+	else
+	{
+		variables[it->second].value = var.value;
+	}
+}
+
+void VariableContainer::put(const std::string& name,
+                            const std::shared_ptr<Value>& value)
+{
+	put({ name, value });
+}
+
+std::shared_ptr<Type> VariableContainer::type() const
+{
+	return TypeOf<VariableContainer>::get();
+}
+
+const void* VariableContainer::get() const
+{
+	return nullptr;
+}
+
+}  // namespace dbg
+}  // namespace vk
+
+#endif  // VK_DEBUG_VARIABLE_HPP_
\ No newline at end of file