// 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 #include #include #include #include #include #include namespace vk { namespace dbg { // Variable is a named value. struct Variable { std::string name; std::shared_ptr 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; using ForeachCallback = std::function; using FindCallback = std::function; 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 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 nextID; }; Variables::Variables() : id(nextID++) {} void Variables::foreach(const ForeachCallback &cb) { foreach(0, std::numeric_limits::max(), cb); } // VariableContainer is mutable collection of named values. class VariableContainer : public Variables { public: using ID = dbg::ID; inline void foreach(size_t startIndex, size_t count, const ForeachCallback &cb) override; inline std::shared_ptr 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); // 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 &base); private: struct ForeachIndex { size_t start; size_t count; }; template inline void foreach(ForeachIndex &index, const F &cb); mutable marl::mutex mutex; std::vector variables GUARDED_BY(mutex); std::unordered_map indices GUARDED_BY(mutex); std::vector> 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 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 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) { put({ name, value }); } void VariableContainer::extend(const std::shared_ptr &base) { marl::lock lock(mutex); extends.emplace_back(base); } } // namespace dbg } // namespace vk #endif // VK_DEBUG_VARIABLE_HPP_