Commit ce1584d1 by Ben Clayton

Vulkan/Debug: Overhaul Values / Variables

`Value` had a number of methods that were never used (like `set()`), so just remove them. Remove `Type`, this was also unused, and was unncessarily complex to maintain. Add `Variables` interface that allows other composite value implementations that are not `VariableContainer`. Break the inheritance of `VariableContainer` from `Value`, as this forces pointer casting and doesn't work with the `Variables` interface. Add `Struct` which is an implementation of `Value` that implements the new `children()` method to return the provided `Variables`. Sets the groundwork for the overhauled debugger implementation. Note: The changes to `SpirvShaderDebugger.cpp` are a least-effort set of changes to make things compile. A significant amount of this file (along with these changes) will be reimplemented in a followup change. Bug: b/145351270 Change-Id: Ic3a641a246737b1f82c786fa8c1ec75700b2a71a Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/48693 Kokoro-Result: kokoro <noreply+kokoro@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com> Reviewed-by: 's avatarAntonio Maiorano <amaiorano@google.com>
parent 1302a4ba
......@@ -453,7 +453,7 @@ struct ArrayType : ObjectImpl<ArrayType, Type, Object::Kind::ArrayType>
vc,
[&](std::shared_ptr<vk::dbg::VariableContainer> &parent, uint32_t idx) {
auto child = std::make_shared<vk::dbg::VariableContainer>();
parent->put(tostring(idx), child);
parent->put(tostring(idx), std::make_shared<vk::dbg::Struct>("array", child));
return child;
},
[&](std::shared_ptr<vk::dbg::VariableContainer> &parent, uint32_t idx, uint32_t offset) {
......@@ -466,7 +466,7 @@ struct ArrayType : ObjectImpl<ArrayType, Type, Object::Kind::ArrayType>
# endif
parent->put(key, child);
});
return vc;
return std::make_shared<vk::dbg::Struct>("array", vc);
}
};
......@@ -502,7 +502,7 @@ struct VectorType : ObjectImpl<VectorType, Type, Object::Kind::VectorType>
# endif
vc->put(elKey, base->value(elPtr, interleaved));
}
return vc;
return std::make_shared<vk::dbg::Struct>("vector", vc);
}
};
......@@ -571,7 +571,7 @@ struct CompositeType : ObjectImpl<CompositeType, Type, Object::Kind::CompositeTy
# endif
vc->put(elKey, member->type->value(elPtr, interleaved));
}
return vc;
return std::make_shared<vk::dbg::Struct>(name, vc);
}
};
......@@ -928,7 +928,7 @@ SpirvShader::Impl::Debugger::State::State(const Debugger *debugger, const char *
for(int i = 0; i < sw::SIMD::Width; i++)
{
auto locals = std::make_shared<vk::dbg::VariableContainer>();
frame.locals->variables->put(laneNames[i], locals);
frame.locals->variables->put(laneNames[i], std::make_shared<vk::dbg::Struct>("", locals));
globals.localsByLane[i] = locals;
}
});
......@@ -979,7 +979,7 @@ template<typename K>
vk::dbg::VariableContainer *SpirvShader::Impl::Debugger::State::group(vk::dbg::VariableContainer *vc, K key)
{
auto out = std::make_shared<vk::dbg::VariableContainer>();
vc->put(tostring(key), out);
vc->put(tostring(key), std::make_shared<vk::dbg::Struct>("", out));
return out.get();
}
......@@ -1018,7 +1018,7 @@ void SpirvShader::Impl::Debugger::State::createScope(const debug::Scope *spirvSc
{
auto locals = std::make_shared<vk::dbg::VariableContainer>();
s.localsByLane[i] = locals;
s.locals->variables->put(laneNames[i], locals);
s.locals->variables->put(laneNames[i], std::make_shared<vk::dbg::Struct>("", locals));
}
if(hasDebuggerScope(spirvScope->parent))
......
......@@ -116,8 +116,8 @@ if(SWIFTSHADER_ENABLE_VULKAN_DEBUGGER)
Debug/Server.hpp
Debug/Thread.cpp
Debug/Thread.hpp
Debug/Type.cpp
Debug/Type.hpp
Debug/TypeOf.cpp
Debug/TypeOf.hpp
Debug/Value.cpp
Debug/Value.hpp
Debug/Variable.cpp
......
......@@ -183,12 +183,11 @@ public:
WeakMap<File::ID, File> files;
WeakMap<Frame::ID, Frame> frames;
WeakMap<Scope::ID, Scope> scopes;
WeakMap<VariableContainer::ID, VariableContainer> variableContainers;
WeakMap<Variables::ID, Variables> variables;
Thread::ID nextThreadID = 1;
File::ID nextFileID = 1;
Frame::ID nextFrameID = 1;
Scope::ID nextScopeID = 1;
VariableContainer::ID nextVariableContainerID = 1;
};
Context::Lock Context::Impl::lock()
......@@ -390,14 +389,14 @@ std::shared_ptr<Scope> Context::Lock::get(Scope::ID id)
return ctx->scopes.get(id);
}
void Context::Lock::track(const std::shared_ptr<VariableContainer> &vc)
void Context::Lock::track(const std::shared_ptr<Variables> &vars)
{
ctx->variableContainers.add(vc->id, vc);
ctx->variables.add(vars->id, vars);
}
std::shared_ptr<VariableContainer> Context::Lock::get(VariableContainer::ID id)
std::shared_ptr<Variables> Context::Lock::get(Variables::ID id)
{
return ctx->variableContainers.get(id);
return ctx->variables.get(id);
}
void Context::Lock::addFunctionBreakpoint(const std::string &name)
......
......@@ -29,7 +29,7 @@ class Thread;
class File;
class Frame;
class Scope;
class VariableContainer;
class Variables;
class ClientEventListener;
class ServerEventListener;
......@@ -107,16 +107,16 @@ public:
// does not exist.
std::shared_ptr<Scope> get(ID<Scope>);
// track() registers the variable container with the context so it can
// be retrieved by get(). Note that the context does not hold a strong
// reference to the variable container, and get() will return nullptr
// if all strong external references are dropped.
void track(const std::shared_ptr<VariableContainer> &);
// track() registers the variables with the context so it can be
// retrieved by get(). Note that the context does not hold a strong
// reference to the variables, and get() will return nullptr if all
// strong external references are dropped.
void track(const std::shared_ptr<Variables> &);
// get() returns the variable container with the given ID, or null if
// the variable container does not exist or no longer has any external
// shared_ptr references.
std::shared_ptr<VariableContainer> get(ID<VariableContainer>);
// get() returns the variables with the given ID, or null if the
// variables does not exist or no longer has any external shared_ptr
// references.
std::shared_ptr<Variables> get(ID<Variables>);
// addFunctionBreakpoint() adds a breakpoint to the start of the
// function with the given name.
......
......@@ -269,7 +269,7 @@ Server::Impl::Impl(const std::shared_ptr<Context> &context, int port)
DAP_LOG("VariablesRequest receieved");
auto lock = ctx->lock();
auto vars = lock.get(VariableContainer::ID(req.variablesReference));
auto vars = lock.get(Variables::ID(req.variablesReference));
if(!vars)
{
return dap::Error("VariablesReference %d not found",
......@@ -281,15 +281,15 @@ Server::Impl::Impl(const std::shared_ptr<Context> &context, int port)
dap::Variable out;
out.evaluateName = v.name;
out.name = v.name;
out.type = v.value->type()->string();
out.value = v.value->string();
if(v.value->type()->kind == Kind::VariableContainer)
out.type = v.value->type();
out.value = v.value->get();
if(auto children = v.value->children())
{
auto const vc = std::dynamic_pointer_cast<VariableContainer>(v.value);
out.variablesReference = vc->id.value();
lock.track(vc);
out.variablesReference = children->id.value();
lock.track(children);
}
response.variables.push_back(out);
return true;
});
return response;
});
......@@ -446,12 +446,8 @@ Server::Impl::Impl(const std::shared_ptr<Context> &context, int port)
}
dap::EvaluateResponse response;
auto findHandler = [&](const Variable &var) {
response.result = var.value->string(fmt);
response.type = var.value->type()->string();
};
std::vector<std::shared_ptr<vk::dbg::VariableContainer>> variables = {
std::vector<std::shared_ptr<vk::dbg::Variables>> variables = {
frame->locals->variables,
frame->arguments->variables,
frame->registers->variables,
......@@ -460,7 +456,12 @@ Server::Impl::Impl(const std::shared_ptr<Context> &context, int port)
for(auto const &vars : variables)
{
if(vars->find(req.expression, findHandler)) { return response; }
if(auto val = vars->get(req.expression))
{
response.result = val->get(fmt);
response.type = val->type();
return response;
}
}
// HACK: VSCode does not appear to include the % in %123 tokens
......@@ -469,7 +470,12 @@ Server::Impl::Impl(const std::shared_ptr<Context> &context, int port)
auto withPercent = "%" + req.expression;
for(auto const &vars : variables)
{
if(vars->find(withPercent, findHandler)) { return response; }
if(auto val = vars->get(withPercent))
{
response.result = val->get(fmt);
response.type = val->type();
return response;
}
}
}
......
// 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"
namespace vk {
namespace dbg {
// clang-format off
std::shared_ptr<Type> TypeOf<bool>::get() { static auto ty = std::make_shared<Type>(Kind::Bool); return ty; }
std::shared_ptr<Type> TypeOf<uint8_t>::get() { static auto ty = std::make_shared<Type>(Kind::U8); return ty; }
std::shared_ptr<Type> TypeOf<int8_t>::get() { static auto ty = std::make_shared<Type>(Kind::S8); return ty; }
std::shared_ptr<Type> TypeOf<uint16_t>::get() { static auto ty = std::make_shared<Type>(Kind::U16); return ty; }
std::shared_ptr<Type> TypeOf<int16_t>::get() { static auto ty = std::make_shared<Type>(Kind::S16); return ty; }
std::shared_ptr<Type> TypeOf<float>::get() { static auto ty = std::make_shared<Type>(Kind::F32); return ty; }
std::shared_ptr<Type> TypeOf<uint32_t>::get() { static auto ty = std::make_shared<Type>(Kind::U32); return ty; }
std::shared_ptr<Type> TypeOf<int32_t>::get() { static auto ty = std::make_shared<Type>(Kind::S32); return ty; }
std::shared_ptr<Type> TypeOf<double>::get() { static auto ty = std::make_shared<Type>(Kind::F64); return ty; }
std::shared_ptr<Type> TypeOf<uint64_t>::get() { static auto ty = std::make_shared<Type>(Kind::U64); return ty; }
std::shared_ptr<Type> TypeOf<int64_t>::get() { static auto ty = std::make_shared<Type>(Kind::S64); return ty; }
std::shared_ptr<Type> TypeOf<VariableContainer>::get() { static auto ty = std::make_shared<Type>(Kind::VariableContainer); return ty; }
// clang-format on
std::string Type::string() const
{
switch(kind)
{
case Kind::Bool:
return "bool";
case Kind::U8:
return "uint8_t";
case Kind::S8:
return "int8_t";
case Kind::U16:
return "uint16_t";
case Kind::S16:
return "int16_t";
case Kind::F32:
return "float";
case Kind::U32:
return "uint32_t";
case Kind::S32:
return "int32_t";
case Kind::F64:
return "double";
case Kind::U64:
return "uint64_t";
case Kind::S64:
return "int64_t";
case Kind::Ptr:
return elem->string() + "*";
case Kind::VariableContainer:
return "struct";
}
return "";
}
} // namespace dbg
} // namespace vk
\ No newline at end of file
// 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_TYPE_HPP_
#define VK_DEBUG_TYPE_HPP_
#include <memory>
#include <cstdint>
#include <string>
namespace vk {
namespace dbg {
class VariableContainer;
class Value;
// Kind is an enumerator of type kinds.
enum class Kind
{
Bool, // Boolean
U8, // 8-bit unsigned integer.
S8, // 8-bit signed integer.
U16, // 16-bit unsigned integer.
S16, // 16-bit signed integer.
F32, // 32-bit unsigned integer.
U32, // 32-bit signed integer.
S32, // 32-bit unsigned integer.
F64, // 64-bit signed integer.
U64, // 64-bit unsigned integer.
S64, // 64-bit signed integer.
Ptr, // A pointer.
VariableContainer, // A VariableContainer.
};
// Type describes the type of a value.
class Type
{
public:
inline Type(Kind kind);
inline Type(Kind kind, const std::shared_ptr<const Type> &elem);
// string() returns a string representation of the type.
std::string string() const;
const Kind kind; // Type kind.
const std::shared_ptr<const Type> elem; // Element type of pointer.
};
Type::Type(Kind kind)
: kind(kind)
{}
Type::Type(Kind kind, const std::shared_ptr<const Type> &elem)
: kind(kind)
, elem(elem)
{}
// clang-format off
template <typename T> struct TypeOf;
template <> struct TypeOf<bool> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<uint8_t> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<int8_t> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<uint16_t> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<int16_t> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<float> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<uint32_t> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<int32_t> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<double> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<uint64_t> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<int64_t> { static std::shared_ptr<Type> get(); };
template <> struct TypeOf<VariableContainer> { static std::shared_ptr<Type> get(); };
// clang-format on
} // namespace dbg
} // namespace vk
#endif // VK_DEBUG_TYPE_HPP_
\ No newline at end of file
// 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 "TypeOf.hpp"
namespace vk {
namespace dbg {
std::string TypeOf<bool>::name = "bool";
std::string TypeOf<uint8_t>::name = "uint8_t";
std::string TypeOf<int8_t>::name = "int8_t";
std::string TypeOf<uint16_t>::name = "uint16_t";
std::string TypeOf<int16_t>::name = "int16_t";
std::string TypeOf<float>::name = "float";
std::string TypeOf<uint32_t>::name = "uint32_t";
std::string TypeOf<int32_t>::name = "int32_t";
std::string TypeOf<double>::name = "double";
std::string TypeOf<uint64_t>::name = "uint64_t";
std::string TypeOf<int64_t>::name = "int64_t";
} // namespace dbg
} // namespace vk
// 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_TYPE_HPP_
#define VK_DEBUG_TYPE_HPP_
#include <memory>
#include <cstdint>
#include <string>
namespace vk {
namespace dbg {
// clang-format off
template <typename T> struct TypeOf;
template <> struct TypeOf<bool> { static std::string name; };
template <> struct TypeOf<uint8_t> { static std::string name; };
template <> struct TypeOf<int8_t> { static std::string name; };
template <> struct TypeOf<uint16_t> { static std::string name; };
template <> struct TypeOf<int16_t> { static std::string name; };
template <> struct TypeOf<float> { static std::string name; };
template <> struct TypeOf<uint32_t> { static std::string name; };
template <> struct TypeOf<int32_t> { static std::string name; };
template <> struct TypeOf<double> { static std::string name; };
template <> struct TypeOf<uint64_t> { static std::string name; };
template <> struct TypeOf<int64_t> { static std::string name; };
// clang-format on
} // namespace dbg
} // namespace vk
#endif // VK_DEBUG_TYPE_HPP_
......@@ -13,7 +13,6 @@
// limitations under the License.
#include "Value.hpp"
#include "Type.hpp"
#include "Variable.hpp"
namespace vk {
......@@ -27,54 +26,10 @@ const FormatFlags FormatFlags::Default = {
&FormatFlags::Default, // subListFmt
};
std::string Value::string(const FormatFlags &fmt /* = FormatFlags::Default */) const
std::string Struct::get(const FormatFlags &fmt /* = FormatFlags::Default */)
{
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, ~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 "";
return members->string(fmt);
}
} // namespace dbg
} // namespace vk
\ No newline at end of file
} // namespace vk
......@@ -15,7 +15,9 @@
#ifndef VK_DEBUG_VALUE_HPP_
#define VK_DEBUG_VALUE_HPP_
#include "Type.hpp"
#include "TypeOf.hpp"
#include "System/Debug.hpp"
#include <memory>
#include <string>
......@@ -23,6 +25,9 @@
namespace vk {
namespace dbg {
class Variables;
class VariableContainer;
// FormatFlags holds settings used to serialize a Value to a string.
struct FormatFlags
{
......@@ -36,97 +41,85 @@ struct FormatFlags
const FormatFlags *subListFmt; // Format used for list sub items.
};
// Value holds a value that can be read and possible written to.
// Value holds a value that can be read.
class Value
{
public:
virtual ~Value() = default;
// type() returns the value's type.
virtual std::shared_ptr<Type> type() const = 0;
// type() returns the typename for the value.
virtual std::string type() = 0;
// string() returns a string representation of the value using the specified
// get() returns a string representation of the value using the specified
// FormatFlags.
virtual std::string string(const FormatFlags & = FormatFlags::Default) const;
virtual std::string get(const FormatFlags & = FormatFlags::Default) = 0;
// 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; }
// children() returns the optional child members of this value.
virtual std::shared_ptr<Variables> children() { return nullptr; }
};
// Constant is an immutable value.
// Constant is constant value of type T.
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;
Constant(const T &val)
: val(val)
{}
std::string type() override { return TypeOf<T>::name; }
std::string get(const FormatFlags &fmt = FormatFlags::Default) override { return std::to_string(val); }
private:
const T value;
T const val;
};
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;
}
// Reference is reference to a value in memory.
template<typename T>
class Reference : public Value
{
public:
inline Reference(T &ptr);
inline std::shared_ptr<Type> type() const override;
inline const void *get() const override;
inline bool set(void *ptr) override;
Reference(const T &ref)
: ref(ref)
{}
std::string type() override { return TypeOf<T>::name; }
std::string get(const FormatFlags &fmt = FormatFlags::Default) override { return std::to_string(ref); }
private:
T &ref;
T const &ref;
};
template<typename T>
Reference<T>::Reference(T &ref)
: ref(ref)
// Struct is an implementation of Value that delegates calls to children() on to
// the constructor provided Variables.
class Struct : public Value
{
}
template<typename T>
std::shared_ptr<Type> Reference<T>::type() const
{
return TypeOf<T>::get();
}
template<typename T>
const void *Reference<T>::get() const
{
return &ref;
}
public:
Struct(const std::string &type, const std::shared_ptr<Variables> &members)
: ty(type)
, members(members)
{
ASSERT(members);
}
std::string type() override { return ty; }
std::string get(const FormatFlags &fmt = FormatFlags::Default) override;
std::shared_ptr<Variables> children() override { return members; }
// create() constructs and returns a new Struct with the given type name and
// calls fields to populate the child members.
// fields must be a function that has the signature:
// void(std::shared_pointer<VariableContainer>&)
template<typename F>
static std::shared_ptr<Struct> create(const std::string &name, F &&fields)
{
auto vc = std::make_shared<VariableContainer>();
fields(vc);
return std::make_shared<Struct>(name, vc);
}
template<typename T>
bool Reference<T>::set(void *ptr)
{
ref = *reinterpret_cast<const T *>(ptr);
return true;
}
private:
std::string const ty;
std::shared_ptr<Variables> const members;
};
// make_constant() returns a shared_ptr to a Constant with the given value.
template<typename T>
......@@ -137,7 +130,7 @@ inline std::shared_ptr<Constant<T>> make_constant(const T &value)
// make_reference() returns a shared_ptr to a Reference with the given value.
template<typename T>
inline std::shared_ptr<Reference<T>> make_reference(T &value)
inline std::shared_ptr<Reference<T>> make_reference(const T &value)
{
return std::make_shared<Reference<T>>(value);
}
......@@ -145,4 +138,4 @@ inline std::shared_ptr<Reference<T>> make_reference(T &value)
} // namespace dbg
} // namespace vk
#endif // VK_DEBUG_VALUE_HPP_
\ No newline at end of file
#endif // VK_DEBUG_VALUE_HPP_
......@@ -17,7 +17,41 @@
namespace vk {
namespace dbg {
std::atomic<int> VariableContainer::nextID{};
std::atomic<int> Variables::nextID{};
Variables::~Variables() = default;
std::shared_ptr<Value> Variables::get(const std::string &name)
{
std::shared_ptr<Value> found;
foreach([&](const Variable &var) {
if(var.name == name)
{
found = var.value;
return false;
}
return true;
});
return found;
}
std::string Variables::string(const FormatFlags &fmt /* = FormatFlags::Default */)
{
std::string out = "";
auto subfmt = *fmt.subListFmt;
subfmt.listIndent = fmt.listIndent + fmt.subListFmt->listIndent;
bool first = true;
foreach([&](const Variable &var) {
if(!first) { out += fmt.listDelimiter; }
first = false;
out += fmt.listIndent;
out += var.name;
out += ": ";
out += var.value->get(subfmt);
return true;
});
return fmt.listPrefix + out + fmt.listSuffix;
}
} // namespace dbg
} // namespace vk
......@@ -16,14 +16,16 @@
#define VK_DEBUG_VARIABLE_HPP_
#include "ID.hpp"
#include "Type.hpp"
#include "Value.hpp"
#include "System/Debug.hpp"
#include "marl/mutex.h"
#include "marl/tsa.h"
#include <algorithm>
#include <atomic>
#include <limits>
#include <memory>
#include <string>
#include <unordered_map>
......@@ -37,43 +39,77 @@ struct Variable
{
std::string name;
std::shared_ptr<Value> value;
// operator bool returns true iff value is not nullptr.
operator bool() const { return value != nullptr; }
};
// VariableContainer is a collection of named values.
class VariableContainer : public Value
// Variables is an interface to a collection of named values.
class Variables
{
public:
using ID = dbg::ID<VariableContainer>;
using ID = dbg::ID<Variables>;
inline VariableContainer();
using ForeachCallback = std::function<bool(const Variable &)>;
using FindCallback = std::function<void(const Variable &)>;
// 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, size_t count, const F &cb) const;
inline Variables();
virtual ~Variables();
// 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;
// foreach() calls cb with each of the variables in the container, while cb
// returns true.
// foreach() will return when cb returns false.
inline void foreach(const ForeachCallback &cb);
// put() places the variable var into the container.
inline void put(const Variable &var);
// foreach() calls cb with each of the variables in the container within the
// indexed range: [startIndex, startIndex+count), while cb returns true.
// foreach() will return when cb returns false.
virtual void foreach(size_t startIndex, size_t count, const ForeachCallback &cb) = 0;
// 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);
// get() looks up and returns the variable with the given name.
virtual std::shared_ptr<Value> get(const std::string &name);
// extend() adds base to the list of VariableContainers that will be
// searched and traversed for variables.
inline void extend(const std::shared_ptr<VariableContainer> &base);
// string() returns the list of variables formatted to a string using the
// given flags.
virtual std::string string(const FormatFlags &fmt /* = FormatFlags::Default */);
// The unique identifier of the variable.
// The unique identifier of the variables.
const ID id;
private:
static std::atomic<int> nextID;
};
Variables::Variables()
: id(nextID++)
{}
void Variables::foreach(const ForeachCallback &cb)
{
foreach(0, std::numeric_limits<size_t>::max(), cb);
}
// VariableContainer is mutable collection of named values.
class VariableContainer : public Variables
{
public:
using ID = dbg::ID<VariableContainer>;
inline void foreach(size_t startIndex, size_t count, const ForeachCallback &cb) override;
inline std::shared_ptr<Value> get(const std::string &name) override;
// 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);
// extend() adds base to the list of Variables that will be searched and
// traversed for variables after those in this VariableContainer are
// searched / traversed.
inline void extend(const std::shared_ptr<Variables> &base);
private:
struct ForeachIndex
{
size_t start;
......@@ -81,35 +117,30 @@ private:
};
template<typename F>
inline void foreach(ForeachIndex &index, const F &cb) const;
inline std::shared_ptr<Type> type() const override;
inline const void *get() const override;
inline void foreach(ForeachIndex &index, const F &cb);
mutable marl::mutex mutex;
std::vector<Variable> variables GUARDED_BY(mutex);
std::unordered_map<std::string, int> indices GUARDED_BY(mutex);
std::vector<std::shared_ptr<VariableContainer>> extends GUARDED_BY(mutex);
std::vector<std::shared_ptr<Variables>> extends GUARDED_BY(mutex);
};
VariableContainer::VariableContainer()
: id(nextID++)
{}
template<typename F>
void VariableContainer::foreach(size_t startIndex, size_t count, const F &cb) const
void VariableContainer::foreach(size_t startIndex, size_t count, const ForeachCallback &cb)
{
auto index = ForeachIndex{ startIndex, count };
foreach(index, cb);
}
template<typename F>
void VariableContainer::foreach(ForeachIndex &index, const F &cb) const
void VariableContainer::foreach(ForeachIndex &index, const F &cb)
{
marl::lock lock(mutex);
for(size_t i = index.start; i < variables.size() && i < index.count; i++)
{
cb(variables[i]);
if(!cb(variables[i]))
{
return;
}
}
index.start -= std::min(index.start, variables.size());
......@@ -117,34 +148,34 @@ void VariableContainer::foreach(ForeachIndex &index, const F &cb) const
for(auto &base : extends)
{
base->foreach(index, cb);
base->foreach(index.start, index.count, cb);
}
}
template<typename F>
bool VariableContainer::find(const std::string &name, const F &cb) const
std::shared_ptr<Value> VariableContainer::get(const std::string &name)
{
marl::lock lock(mutex);
for(auto const &var : variables)
{
if(var.name == name)
{
cb(var);
return true;
return var.value;
}
}
for(auto &base : extends)
{
if(base->find(name, cb))
if(auto val = base->get(name))
{
return true;
return val;
}
}
return false;
return nullptr;
}
void VariableContainer::put(const Variable &var)
{
ASSERT(var.value);
marl::lock lock(mutex);
auto it = indices.find(var.name);
if(it == indices.end())
......@@ -164,22 +195,12 @@ void VariableContainer::put(const std::string &name,
put({ name, value });
}
void VariableContainer::extend(const std::shared_ptr<VariableContainer> &base)
void VariableContainer::extend(const std::shared_ptr<Variables> &base)
{
marl::lock lock(mutex);
extends.emplace_back(base);
}
std::shared_ptr<Type> VariableContainer::type() const
{
return TypeOf<VariableContainer>::get();
}
const void *VariableContainer::get() const
{
return nullptr;
}
} // namespace dbg
} // namespace vk
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment