blob: cbc8d51d162641a2aea8a08603ad9d76e3908eec [file] [log] [blame]
// 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 "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>
#include <vector>
namespace vk {
namespace dbg {
// Variable is a named value.
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; }
};
// Variables is an interface to a collection of named values.
class Variables
{
public:
using ID = dbg::ID<Variables>;
using ForeachCallback = std::function<bool(const Variable &)>;
using FindCallback = std::function<void(const Variable &)>;
inline Variables();
virtual ~Variables();
// 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);
// 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;
// get() looks up and returns the variable with the given name.
virtual std::shared_ptr<Value> get(const std::string &name);
// 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 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;
size_t count;
};
template<typename F>
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<Variables>> extends GUARDED_BY(mutex);
};
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)
{
marl::lock lock(mutex);
for(size_t i = index.start; i < variables.size() && i < index.count; i++)
{
if(!cb(variables[i]))
{
return;
}
}
index.start -= std::min(index.start, variables.size());
index.count -= std::min(index.count, variables.size());
for(auto &base : extends)
{
base->foreach(index.start, index.count, cb);
}
}
std::shared_ptr<Value> VariableContainer::get(const std::string &name)
{
marl::lock lock(mutex);
for(auto const &var : variables)
{
if(var.name == name)
{
return var.value;
}
}
for(auto &base : extends)
{
if(auto val = base->get(name))
{
return val;
}
}
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())
{
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 });
}
void VariableContainer::extend(const std::shared_ptr<Variables> &base)
{
marl::lock lock(mutex);
extends.emplace_back(base);
}
} // namespace dbg
} // namespace vk
#endif // VK_DEBUG_VARIABLE_HPP_